--- /dev/null
+From 9d87e1aadc0dbf4645c36d0ae3d795e176411384 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 23:01:46 +0200
+Subject: openvswitch: fix GSO userspace truncation underflow
+
+From: Kyle Zeng <kylebot@openai.com>
+
+[ Upstream commit 4032f8ed10fcb84d41c508dfb04be96589f78dfe ]
+
+OVS_ACTION_ATTR_TRUNC currently stores a delta from the original skb
+length in OVS_CB(skb)->cutlen. When a later userspace action segments a
+GSO skb, queue_gso_packets() reuses that delta for each smaller segment.
+A segment can then reach queue_userspace_packet() with cutlen greater
+than skb->len, underflowing the length passed to skb_zerocopy().
+
+Store the maximum preserved length instead and bound each consumer
+against the current skb length. Use U32_MAX as the no-truncation
+sentinel so the value remains valid if skb geometry changes before a
+consumer handles it.
+
+Fixes: f2a4d086ed4c ("openvswitch: Add packet truncation support.")
+Cc: stable@vger.kernel.org
+Assisted-by: Codex:gpt-5.5
+Signed-off-by: Kyle Zeng <kylebot@openai.com>
+Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
+Reviewed-by: Aaron Conole <aconole@redhat.com>
+Link: https://patch.msgid.link/20260707221635.27489-1-kylebot@openai.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[5.10.y supports neither OVS_ACTION_ATTR_PSAMPLE nor OVS drop reasons]
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/actions.c | 15 +++++----------
+ net/openvswitch/datapath.c | 25 ++++++++++++++-----------
+ net/openvswitch/datapath.h | 2 +-
+ net/openvswitch/vport.c | 2 +-
+ 4 files changed, 21 insertions(+), 23 deletions(-)
+
+diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
+index 3b3cc6ea274f8c..4995e617ca032f 100644
+--- a/net/openvswitch/actions.c
++++ b/net/openvswitch/actions.c
+@@ -855,12 +855,8 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
+ u16 mru = OVS_CB(skb)->mru;
+ u32 cutlen = OVS_CB(skb)->cutlen;
+
+- if (unlikely(cutlen > 0)) {
+- if (skb->len - cutlen > ovs_mac_header_len(key))
+- pskb_trim(skb, skb->len - cutlen);
+- else
+- pskb_trim(skb, ovs_mac_header_len(key));
+- }
++ if (unlikely(cutlen < skb->len))
++ pskb_trim(skb, max(cutlen, ovs_mac_header_len(key)));
+
+ if (likely(!mru ||
+ (skb->len <= mru + vport->dev->hard_header_len))) {
+@@ -1232,22 +1228,21 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
+ clone = skb_clone(skb, GFP_ATOMIC);
+ if (clone)
+ do_output(dp, clone, port, key);
+- OVS_CB(skb)->cutlen = 0;
++ OVS_CB(skb)->cutlen = U32_MAX;
+ break;
+ }
+
+ case OVS_ACTION_ATTR_TRUNC: {
+ struct ovs_action_trunc *trunc = nla_data(a);
+
+- if (skb->len > trunc->max_len)
+- OVS_CB(skb)->cutlen = skb->len - trunc->max_len;
++ OVS_CB(skb)->cutlen = trunc->max_len;
+ break;
+ }
+
+ case OVS_ACTION_ATTR_USERSPACE:
+ output_userspace(dp, skb, key, a, attr,
+ len, OVS_CB(skb)->cutlen);
+- OVS_CB(skb)->cutlen = 0;
++ OVS_CB(skb)->cutlen = U32_MAX;
+ break;
+
+ case OVS_ACTION_ATTR_HASH:
+diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
+index 5fb74fbcb2f382..b985e6696b4251 100644
+--- a/net/openvswitch/datapath.c
++++ b/net/openvswitch/datapath.c
+@@ -240,7 +240,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
+ upcall.cmd = OVS_PACKET_CMD_MISS;
+ upcall.portid = ovs_vport_find_upcall_portid(p, skb);
+ upcall.mru = OVS_CB(skb)->mru;
+- error = ovs_dp_upcall(dp, skb, key, &upcall, 0);
++ error = ovs_dp_upcall(dp, skb, key, &upcall, U32_MAX);
+ switch (error) {
+ case 0:
+ case -EAGAIN:
+@@ -400,7 +400,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ struct sk_buff *nskb = NULL;
+ struct sk_buff *user_skb = NULL; /* to be queued to userspace */
+ struct nlattr *nla;
+- size_t len;
++ size_t msg_size;
++ size_t skb_len;
+ unsigned int hlen;
+ int err, dp_ifindex;
+ u64 hash;
+@@ -421,7 +422,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ skb = nskb;
+ }
+
+- if (nla_attr_size(skb->len) > USHRT_MAX) {
++ skb_len = min(skb->len, cutlen);
++ if (nla_attr_size(skb_len) > USHRT_MAX) {
+ err = -EFBIG;
+ goto out;
+ }
+@@ -436,13 +438,13 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ * padding logic. Only perform zerocopy if padding is not required.
+ */
+ if (dp->user_features & OVS_DP_F_UNALIGNED)
+- hlen = skb_zerocopy_headlen(skb);
++ hlen = min(skb_zerocopy_headlen(skb), cutlen);
+ else
+- hlen = skb->len;
++ hlen = skb_len;
+
+- len = upcall_msg_size(upcall_info, hlen - cutlen,
+- OVS_CB(skb)->acts_origlen);
+- user_skb = genlmsg_new(len, GFP_ATOMIC);
++ msg_size = upcall_msg_size(upcall_info, hlen,
++ OVS_CB(skb)->acts_origlen);
++ user_skb = genlmsg_new(msg_size, GFP_ATOMIC);
+ if (!user_skb) {
+ err = -ENOMEM;
+ goto out;
+@@ -503,7 +505,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ }
+
+ /* Add OVS_PACKET_ATTR_LEN when packet is truncated */
+- if (cutlen > 0 &&
++ if (skb_len < skb->len &&
+ nla_put_u32(user_skb, OVS_PACKET_ATTR_LEN, skb->len)) {
+ err = -ENOBUFS;
+ goto out;
+@@ -528,9 +530,9 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ err = -ENOBUFS;
+ goto out;
+ }
+- nla->nla_len = nla_attr_size(skb->len - cutlen);
++ nla->nla_len = nla_attr_size(skb_len);
+
+- err = skb_zerocopy(user_skb, skb, skb->len - cutlen, hlen);
++ err = skb_zerocopy(user_skb, skb, skb_len, hlen);
+ if (err)
+ goto out;
+
+@@ -587,6 +589,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
+ packet->ignore_df = 1;
+ }
+ OVS_CB(packet)->mru = mru;
++ OVS_CB(packet)->cutlen = U32_MAX;
+
+ if (a[OVS_PACKET_ATTR_HASH]) {
+ hash = nla_get_u64(a[OVS_PACKET_ATTR_HASH]);
+diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
+index 38f7d3e66ca613..62e7ad32f83764 100644
+--- a/net/openvswitch/datapath.h
++++ b/net/openvswitch/datapath.h
+@@ -96,7 +96,7 @@ struct datapath {
+ * @mru: The maximum received fragement size; 0 if the packet is not
+ * fragmented.
+ * @acts_origlen: The netlink size of the flow actions applied to this skb.
+- * @cutlen: The number of bytes from the packet end to be removed.
++ * @cutlen: The number of bytes in the packet to preserve on output.
+ */
+ struct ovs_skb_cb {
+ struct vport *input_vport;
+diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
+index da733b92ae8a76..ced707ff6dd971 100644
+--- a/net/openvswitch/vport.c
++++ b/net/openvswitch/vport.c
+@@ -436,7 +436,7 @@ int ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
+
+ OVS_CB(skb)->input_vport = vport;
+ OVS_CB(skb)->mru = 0;
+- OVS_CB(skb)->cutlen = 0;
++ OVS_CB(skb)->cutlen = U32_MAX;
+ if (unlikely(dev_net(skb->dev) != ovs_dp_get_net(vport->dp))) {
+ u32 mark;
+
+--
+2.53.0
+
drm-amdgpu-gfx9-replace-bug_on-with-warn_on.patch
drm-amdgpu-fix-division-by-zero-with-invalid-uvd-dimensions.patch
drm-amdgpu-invoke-pm_genpd_remove-before-freeing-genpd.patch
+tipc-fix-use-after-free-of-the-discoverer-in-tipc_di.patch
+wifi-mt76-mt7615-drop-txrx_notify-on-non-mmio-buses.patch
+openvswitch-fix-gso-userspace-truncation-underflow.patch
--- /dev/null
+From 6c98e5c4b49db2cd1f1b3c8c572c719f7a661d1d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:16:02 +0300
+Subject: tipc: fix use-after-free of the discoverer in tipc_disc_rcv()
+
+From: Weiming Shi <bestswngs@gmail.com>
+
+commit 1579342d71133da7f00daa02c75cebec7372097b upstream.
+
+bearer_disable() frees b->disc with tipc_disc_delete()'s plain kfree(),
+but tipc_disc_rcv() still dereferences b->disc in RX softirq under
+rcu_read_lock() (tipc_udp_recv -> tipc_rcv -> tipc_disc_rcv).
+
+L2 bearers are safe thanks to the synchronize_net() in
+tipc_disable_l2_media(), but the UDP bearer defers that call to the
+cleanup_bearer() workqueue, so the discoverer is freed with no grace
+period:
+
+ BUG: KASAN: slab-use-after-free in tipc_disc_rcv (net/tipc/discover.c:149)
+ Read of size 8 at addr ffff88802348b728 by task poc_tipc/184
+ <IRQ>
+ tipc_disc_rcv (net/tipc/discover.c:149)
+ tipc_rcv (net/tipc/node.c:2126)
+ tipc_udp_recv (net/tipc/udp_media.c:391)
+ udp_rcv (net/ipv4/udp.c:2643)
+ ip_local_deliver_finish (net/ipv4/ip_input.c:241)
+ </IRQ>
+ Freed by task 181:
+ kfree (mm/slub.c:6565)
+ bearer_disable (net/tipc/bearer.c:418)
+ tipc_nl_bearer_disable (net/tipc/bearer.c:1001)
+
+The bearer is freed with kfree_rcu(); free the discoverer the same way.
+Add an rcu_head to struct tipc_discoverer and free it and its skb from an
+RCU callback.
+
+Because the RCU callback (tipc_disc_free_rcu) lives in module text, a
+call_rcu() that is still pending when the tipc module is unloaded would
+invoke a freed function. Add an rcu_barrier() to tipc_exit() after the
+bearer subsystem has been torn down, so all pending discoverer callbacks
+have run before the module text goes away.
+
+Reachable from an unprivileged user namespace: the TIPCv2 genl family is
+netnsok and its bearer commands have no GENL_ADMIN_PERM. Needs CONFIG_TIPC
+and CONFIG_TIPC_MEDIA_UDP.
+
+Fixes: 25b0b9c4e835 ("tipc: handle collisions of 32-bit node address hash values")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Weiming Shi <bestswngs@gmail.com>
+Reviewed-by: Tung Nguyen <tung.quang.nguyen@est.tech>
+Link: https://patch.msgid.link/20260617135744.3383175-3-bestswngs@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Alexander Martyniuk <alexevgmart@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tipc/core.c | 5 +++++
+ net/tipc/discover.c | 14 ++++++++++++--
+ 2 files changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/net/tipc/core.c b/net/tipc/core.c
+index 7724499f516e9e..4f01691aea3a40 100644
+--- a/net/tipc/core.c
++++ b/net/tipc/core.c
+@@ -220,6 +220,11 @@ static void __exit tipc_exit(void)
+ unregister_pernet_device(&tipc_net_ops);
+ tipc_unregister_sysctl();
+
++ /* TODO: Wait for all timers that called call_rcu() to finish before
++ * calling rcu_barrier().
++ */
++ rcu_barrier();
++
+ pr_info("Deactivated\n");
+ }
+
+diff --git a/net/tipc/discover.c b/net/tipc/discover.c
+index 2730310249e3ca..28665de32245a5 100644
+--- a/net/tipc/discover.c
++++ b/net/tipc/discover.c
+@@ -58,6 +58,7 @@
+ * @skb: request message to be (repeatedly) sent
+ * @timer: timer governing period between requests
+ * @timer_intv: current interval between requests (in ms)
++ * @rcu: RCU head for deferred freeing
+ */
+ struct tipc_discoverer {
+ u32 bearer_id;
+@@ -69,6 +70,7 @@ struct tipc_discoverer {
+ struct sk_buff *skb;
+ struct timer_list timer;
+ unsigned long timer_intv;
++ struct rcu_head rcu;
+ };
+
+ /**
+@@ -381,6 +383,15 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,
+ return 0;
+ }
+
++static void tipc_disc_free_rcu(struct rcu_head *rp)
++{
++ struct tipc_discoverer *d = container_of(rp, struct tipc_discoverer,
++ rcu);
++
++ kfree_skb(d->skb);
++ kfree(d);
++}
++
+ /**
+ * tipc_disc_delete - destroy object sending periodic link setup requests
+ * @d: ptr to link duest structure
+@@ -388,8 +399,7 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,
+ void tipc_disc_delete(struct tipc_discoverer *d)
+ {
+ del_timer_sync(&d->timer);
+- kfree_skb(d->skb);
+- kfree(d);
++ call_rcu(&d->rcu, tipc_disc_free_rcu);
+ }
+
+ /**
+--
+2.53.0
+
--- /dev/null
+From 67b6439e6dcbe407b489c24d78362f8c7ad8c12a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 08:00:42 -0700
+Subject: wifi: mt76: mt7615: drop TXRX_NOTIFY on non-mmio buses
+
+From: Devin Wittmayer <lucid_duck@justthetip.ca>
+
+commit 39afc46c0243d10b7795e6e6cf4ae91f41732120 upstream.
+
+PKT_TYPE_TXRX_NOTIFY is an mmio-only event, but mt7615_rx_check() and
+mt7615_queue_rx_skb() dispatch it to mt7615_mac_tx_free() on every bus.
+mt7615_mac_tx_free() cleans the DMA tx queues with
+mt76_queue_tx_cleanup(), which calls queue_ops->tx_cleanup(). Only the
+mmio queue ops implement that callback; on the mt7663 USB and SDIO
+buses it is NULL, so a TXRX_NOTIFY there calls a NULL pointer in the RX
+worker. Same defect as the mt7921 and mt7925 patches in this series.
+
+Drop the event on non-mmio buses via mt76_is_mmio(), as in
+commit 5683e1488aa9 ("wifi: mt76: connac: do not check WED status for
+non-mmio devices").
+
+Fixes: eb99cc95c3b6 ("mt76: mt7615: introduce mt7663u support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>
+Link: https://patch.msgid.link/20260627191336.20223-4-lucid_duck@justthetip.ca
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+[ No mt7615_rx_check() on this tree, so only the mt7615_queue_rx_skb()
+ hunk applies, and mt7615_mac_tx_free() takes the skb rather than
+ (data, len), so the guard frees it here. ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+index 4364f73b501da8..0c9201e073b271 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+@@ -1492,6 +1492,10 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+ dev_kfree_skb(skb);
+ break;
+ case PKT_TYPE_TXRX_NOTIFY:
++ if (!mt76_is_mmio(mdev)) {
++ dev_kfree_skb(skb);
++ break;
++ }
+ mt7615_mac_tx_free(dev, skb);
+ break;
+ case PKT_TYPE_RX_EVENT:
+--
+2.53.0
+
--- /dev/null
+From b0db12307f8fc57d1cc5d61de932d4b9a723da43 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 23:00:20 +0200
+Subject: openvswitch: fix GSO userspace truncation underflow
+
+From: Kyle Zeng <kylebot@openai.com>
+
+[ Upstream commit 4032f8ed10fcb84d41c508dfb04be96589f78dfe ]
+
+OVS_ACTION_ATTR_TRUNC currently stores a delta from the original skb
+length in OVS_CB(skb)->cutlen. When a later userspace action segments a
+GSO skb, queue_gso_packets() reuses that delta for each smaller segment.
+A segment can then reach queue_userspace_packet() with cutlen greater
+than skb->len, underflowing the length passed to skb_zerocopy().
+
+Store the maximum preserved length instead and bound each consumer
+against the current skb length. Use U32_MAX as the no-truncation
+sentinel so the value remains valid if skb geometry changes before a
+consumer handles it.
+
+Fixes: f2a4d086ed4c ("openvswitch: Add packet truncation support.")
+Cc: stable@vger.kernel.org
+Assisted-by: Codex:gpt-5.5
+Signed-off-by: Kyle Zeng <kylebot@openai.com>
+Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
+Reviewed-by: Aaron Conole <aconole@redhat.com>
+Link: https://patch.msgid.link/20260707221635.27489-1-kylebot@openai.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[5.15.y supports neither OVS_ACTION_ATTR_PSAMPLE nor OVS drop reasons]
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/actions.c | 15 +++++----------
+ net/openvswitch/datapath.c | 25 ++++++++++++++-----------
+ net/openvswitch/datapath.h | 2 +-
+ net/openvswitch/vport.c | 2 +-
+ 4 files changed, 21 insertions(+), 23 deletions(-)
+
+diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
+index aa240953d7669f..6d6d82ed5bd172 100644
+--- a/net/openvswitch/actions.c
++++ b/net/openvswitch/actions.c
+@@ -856,12 +856,8 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
+ u16 mru = OVS_CB(skb)->mru;
+ u32 cutlen = OVS_CB(skb)->cutlen;
+
+- if (unlikely(cutlen > 0)) {
+- if (skb->len - cutlen > ovs_mac_header_len(key))
+- pskb_trim(skb, skb->len - cutlen);
+- else
+- pskb_trim(skb, ovs_mac_header_len(key));
+- }
++ if (unlikely(cutlen < skb->len))
++ pskb_trim(skb, max(cutlen, ovs_mac_header_len(key)));
+
+ if (likely(!mru ||
+ (skb->len <= mru + vport->dev->hard_header_len))) {
+@@ -1242,22 +1238,21 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
+ clone = skb_clone(skb, GFP_ATOMIC);
+ if (clone)
+ do_output(dp, clone, port, key);
+- OVS_CB(skb)->cutlen = 0;
++ OVS_CB(skb)->cutlen = U32_MAX;
+ break;
+ }
+
+ case OVS_ACTION_ATTR_TRUNC: {
+ struct ovs_action_trunc *trunc = nla_data(a);
+
+- if (skb->len > trunc->max_len)
+- OVS_CB(skb)->cutlen = skb->len - trunc->max_len;
++ OVS_CB(skb)->cutlen = trunc->max_len;
+ break;
+ }
+
+ case OVS_ACTION_ATTR_USERSPACE:
+ output_userspace(dp, skb, key, a, attr,
+ len, OVS_CB(skb)->cutlen);
+- OVS_CB(skb)->cutlen = 0;
++ OVS_CB(skb)->cutlen = U32_MAX;
+ break;
+
+ case OVS_ACTION_ATTR_HASH:
+diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
+index 0202111cda3531..e9ff6b87af7010 100644
+--- a/net/openvswitch/datapath.c
++++ b/net/openvswitch/datapath.c
+@@ -250,7 +250,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
+ upcall.portid = ovs_vport_find_upcall_portid(p, skb);
+
+ upcall.mru = OVS_CB(skb)->mru;
+- error = ovs_dp_upcall(dp, skb, key, &upcall, 0);
++ error = ovs_dp_upcall(dp, skb, key, &upcall, U32_MAX);
+ switch (error) {
+ case 0:
+ case -EAGAIN:
+@@ -413,7 +413,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ struct sk_buff *nskb = NULL;
+ struct sk_buff *user_skb = NULL; /* to be queued to userspace */
+ struct nlattr *nla;
+- size_t len;
++ size_t msg_size;
++ size_t skb_len;
+ unsigned int hlen;
+ int err, dp_ifindex;
+ u64 hash;
+@@ -434,7 +435,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ skb = nskb;
+ }
+
+- if (nla_attr_size(skb->len) > USHRT_MAX) {
++ skb_len = min(skb->len, cutlen);
++ if (nla_attr_size(skb_len) > USHRT_MAX) {
+ err = -EFBIG;
+ goto out;
+ }
+@@ -449,13 +451,13 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ * padding logic. Only perform zerocopy if padding is not required.
+ */
+ if (dp->user_features & OVS_DP_F_UNALIGNED)
+- hlen = skb_zerocopy_headlen(skb);
++ hlen = min(skb_zerocopy_headlen(skb), cutlen);
+ else
+- hlen = skb->len;
++ hlen = skb_len;
+
+- len = upcall_msg_size(upcall_info, hlen - cutlen,
+- OVS_CB(skb)->acts_origlen);
+- user_skb = genlmsg_new(len, GFP_ATOMIC);
++ msg_size = upcall_msg_size(upcall_info, hlen,
++ OVS_CB(skb)->acts_origlen);
++ user_skb = genlmsg_new(msg_size, GFP_ATOMIC);
+ if (!user_skb) {
+ err = -ENOMEM;
+ goto out;
+@@ -516,7 +518,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ }
+
+ /* Add OVS_PACKET_ATTR_LEN when packet is truncated */
+- if (cutlen > 0 &&
++ if (skb_len < skb->len &&
+ nla_put_u32(user_skb, OVS_PACKET_ATTR_LEN, skb->len)) {
+ err = -ENOBUFS;
+ goto out;
+@@ -541,9 +543,9 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ err = -ENOBUFS;
+ goto out;
+ }
+- nla->nla_len = nla_attr_size(skb->len - cutlen);
++ nla->nla_len = nla_attr_size(skb_len);
+
+- err = skb_zerocopy(user_skb, skb, skb->len - cutlen, hlen);
++ err = skb_zerocopy(user_skb, skb, skb_len, hlen);
+ if (err)
+ goto out;
+
+@@ -600,6 +602,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
+ packet->ignore_df = 1;
+ }
+ OVS_CB(packet)->mru = mru;
++ OVS_CB(packet)->cutlen = U32_MAX;
+
+ if (a[OVS_PACKET_ATTR_HASH]) {
+ hash = nla_get_u64(a[OVS_PACKET_ATTR_HASH]);
+diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
+index fcfe6cb464417e..86a47998a359a6 100644
+--- a/net/openvswitch/datapath.h
++++ b/net/openvswitch/datapath.h
+@@ -114,7 +114,7 @@ struct datapath {
+ * @mru: The maximum received fragement size; 0 if the packet is not
+ * fragmented.
+ * @acts_origlen: The netlink size of the flow actions applied to this skb.
+- * @cutlen: The number of bytes from the packet end to be removed.
++ * @cutlen: The number of bytes in the packet to preserve on output.
+ */
+ struct ovs_skb_cb {
+ struct vport *input_vport;
+diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
+index 25197e14c123bd..a2a9a602dd254d 100644
+--- a/net/openvswitch/vport.c
++++ b/net/openvswitch/vport.c
+@@ -438,7 +438,7 @@ int ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
+
+ OVS_CB(skb)->input_vport = vport;
+ OVS_CB(skb)->mru = 0;
+- OVS_CB(skb)->cutlen = 0;
++ OVS_CB(skb)->cutlen = U32_MAX;
+ if (unlikely(dev_net(skb->dev) != ovs_dp_get_net(vport->dp))) {
+ u32 mark;
+
+--
+2.53.0
+
drm-amdgpu-gfx9-replace-bug_on-with-warn_on.patch
drm-amdgpu-fix-division-by-zero-with-invalid-uvd-dimensions.patch
drm-amdgpu-invoke-pm_genpd_remove-before-freeing-genpd.patch
+tipc-fix-use-after-free-of-the-discoverer-in-tipc_di.patch
+wifi-mt76-mt7615-drop-txrx_notify-on-non-mmio-buses.patch
+openvswitch-fix-gso-userspace-truncation-underflow.patch
--- /dev/null
+From b82dbf5b0a5f904d428e938b5580869b98ad80d7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:16:03 +0300
+Subject: tipc: fix use-after-free of the discoverer in tipc_disc_rcv()
+
+From: Weiming Shi <bestswngs@gmail.com>
+
+commit 1579342d71133da7f00daa02c75cebec7372097b upstream.
+
+bearer_disable() frees b->disc with tipc_disc_delete()'s plain kfree(),
+but tipc_disc_rcv() still dereferences b->disc in RX softirq under
+rcu_read_lock() (tipc_udp_recv -> tipc_rcv -> tipc_disc_rcv).
+
+L2 bearers are safe thanks to the synchronize_net() in
+tipc_disable_l2_media(), but the UDP bearer defers that call to the
+cleanup_bearer() workqueue, so the discoverer is freed with no grace
+period:
+
+ BUG: KASAN: slab-use-after-free in tipc_disc_rcv (net/tipc/discover.c:149)
+ Read of size 8 at addr ffff88802348b728 by task poc_tipc/184
+ <IRQ>
+ tipc_disc_rcv (net/tipc/discover.c:149)
+ tipc_rcv (net/tipc/node.c:2126)
+ tipc_udp_recv (net/tipc/udp_media.c:391)
+ udp_rcv (net/ipv4/udp.c:2643)
+ ip_local_deliver_finish (net/ipv4/ip_input.c:241)
+ </IRQ>
+ Freed by task 181:
+ kfree (mm/slub.c:6565)
+ bearer_disable (net/tipc/bearer.c:418)
+ tipc_nl_bearer_disable (net/tipc/bearer.c:1001)
+
+The bearer is freed with kfree_rcu(); free the discoverer the same way.
+Add an rcu_head to struct tipc_discoverer and free it and its skb from an
+RCU callback.
+
+Because the RCU callback (tipc_disc_free_rcu) lives in module text, a
+call_rcu() that is still pending when the tipc module is unloaded would
+invoke a freed function. Add an rcu_barrier() to tipc_exit() after the
+bearer subsystem has been torn down, so all pending discoverer callbacks
+have run before the module text goes away.
+
+Reachable from an unprivileged user namespace: the TIPCv2 genl family is
+netnsok and its bearer commands have no GENL_ADMIN_PERM. Needs CONFIG_TIPC
+and CONFIG_TIPC_MEDIA_UDP.
+
+Fixes: 25b0b9c4e835 ("tipc: handle collisions of 32-bit node address hash values")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Weiming Shi <bestswngs@gmail.com>
+Reviewed-by: Tung Nguyen <tung.quang.nguyen@est.tech>
+Link: https://patch.msgid.link/20260617135744.3383175-3-bestswngs@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Alexander Martyniuk <alexevgmart@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tipc/core.c | 5 +++++
+ net/tipc/discover.c | 14 ++++++++++++--
+ 2 files changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/net/tipc/core.c b/net/tipc/core.c
+index 434e70eabe0812..1ddecea1df6e91 100644
+--- a/net/tipc/core.c
++++ b/net/tipc/core.c
+@@ -218,6 +218,11 @@ static void __exit tipc_exit(void)
+ unregister_pernet_device(&tipc_net_ops);
+ tipc_unregister_sysctl();
+
++ /* TODO: Wait for all timers that called call_rcu() to finish before
++ * calling rcu_barrier().
++ */
++ rcu_barrier();
++
+ pr_info("Deactivated\n");
+ }
+
+diff --git a/net/tipc/discover.c b/net/tipc/discover.c
+index e8dcdf267c0c3f..835ff27f8ea88c 100644
+--- a/net/tipc/discover.c
++++ b/net/tipc/discover.c
+@@ -58,6 +58,7 @@
+ * @skb: request message to be (repeatedly) sent
+ * @timer: timer governing period between requests
+ * @timer_intv: current interval between requests (in ms)
++ * @rcu: RCU head for deferred freeing
+ */
+ struct tipc_discoverer {
+ u32 bearer_id;
+@@ -69,6 +70,7 @@ struct tipc_discoverer {
+ struct sk_buff *skb;
+ struct timer_list timer;
+ unsigned long timer_intv;
++ struct rcu_head rcu;
+ };
+
+ /**
+@@ -382,6 +384,15 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,
+ return 0;
+ }
+
++static void tipc_disc_free_rcu(struct rcu_head *rp)
++{
++ struct tipc_discoverer *d = container_of(rp, struct tipc_discoverer,
++ rcu);
++
++ kfree_skb(d->skb);
++ kfree(d);
++}
++
+ /**
+ * tipc_disc_delete - destroy object sending periodic link setup requests
+ * @d: ptr to link dest structure
+@@ -389,8 +400,7 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,
+ void tipc_disc_delete(struct tipc_discoverer *d)
+ {
+ del_timer_sync(&d->timer);
+- kfree_skb(d->skb);
+- kfree(d);
++ call_rcu(&d->rcu, tipc_disc_free_rcu);
+ }
+
+ /**
+--
+2.53.0
+
--- /dev/null
+From 7676b51964a6e4efee9154f091be9a3bc32ce328 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 08:00:56 -0700
+Subject: wifi: mt76: mt7615: drop TXRX_NOTIFY on non-mmio buses
+
+From: Devin Wittmayer <lucid_duck@justthetip.ca>
+
+commit 39afc46c0243d10b7795e6e6cf4ae91f41732120 upstream.
+
+PKT_TYPE_TXRX_NOTIFY is an mmio-only event, but mt7615_rx_check() and
+mt7615_queue_rx_skb() dispatch it to mt7615_mac_tx_free() on every bus.
+mt7615_mac_tx_free() cleans the DMA tx queues with
+mt76_queue_tx_cleanup(), which calls queue_ops->tx_cleanup(). Only the
+mmio queue ops implement that callback; on the mt7663 USB and SDIO
+buses it is NULL, so a TXRX_NOTIFY there calls a NULL pointer in the RX
+worker. Same defect as the mt7921 and mt7925 patches in this series.
+
+Drop the event on non-mmio buses via mt76_is_mmio(), as in
+commit 5683e1488aa9 ("wifi: mt76: connac: do not check WED status for
+non-mmio devices").
+
+Fixes: eb99cc95c3b6 ("mt76: mt7615: introduce mt7663u support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>
+Link: https://patch.msgid.link/20260627191336.20223-4-lucid_duck@justthetip.ca
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+[ No mt7615_rx_check() on this tree, so only the mt7615_queue_rx_skb()
+ hunk applies, and mt7615_mac_tx_free() takes the skb rather than
+ (data, len), so the guard frees it here. ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+index 2f0ba8a75d71bc..ee90ec27f09faa 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+@@ -1601,6 +1601,10 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+ dev_kfree_skb(skb);
+ break;
+ case PKT_TYPE_TXRX_NOTIFY:
++ if (!mt76_is_mmio(mdev)) {
++ dev_kfree_skb(skb);
++ break;
++ }
+ mt7615_mac_tx_free(dev, skb);
+ break;
+ case PKT_TYPE_RX_EVENT:
+--
+2.53.0
+
--- /dev/null
+From df55355b80d46547f9ff07aeacfcd505dffa9763 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 23:11:51 +0800
+Subject: bpf: drop bpf_lsm_getselfattr from hook list
+
+From: Wentao Guan <guanwentao@uniontech.com>
+
+Backport ("bpf, lsm: Add disabled BPF LSM hook list") for v6.1.y bring the
+warning "WARN: resolve_btfids: unresolved symbol bpf_lsm_getselfattr".
+
+The lsm_getselfattr from commit a04a1198088a
+("LSM: syscalls for current process attributes"), no need to backport
+the huge patch, simply drop the entry to fix the noise.
+
+This is a fix for stable v6.1.178 backport commit, so no upstream commit.
+
+Fixes: 0562ae02a6c4 ("bpf, lsm: Add disabled BPF LSM hook list")
+Link: https://lore.kernel.org/stable/20260728225520.stable-0003@kernel.org/
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/bpf_lsm.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
+index 4bb8c363c0bfde..61e93253b6b5e7 100644
+--- a/kernel/bpf/bpf_lsm.c
++++ b/kernel/bpf/bpf_lsm.c
+@@ -42,7 +42,6 @@ BTF_ID(func, bpf_lsm_inode_need_killpriv)
+ BTF_ID(func, bpf_lsm_inode_getsecurity)
+ BTF_ID(func, bpf_lsm_inode_listsecurity)
+ BTF_ID(func, bpf_lsm_inode_copy_up_xattr)
+-BTF_ID(func, bpf_lsm_getselfattr)
+ BTF_ID(func, bpf_lsm_getprocattr)
+ BTF_ID(func, bpf_lsm_setprocattr)
+ #ifdef CONFIG_KEYS
+--
+2.53.0
+
--- /dev/null
+From 976527ea433873bda8166a340ddf53c55edb5e57 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 20:53:13 +0000
+Subject: exfat: validate cluster allocation bits of the allocation bitmap
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 79c1587b6cda74deb0c86fc7ba194b92958c793c ]
+
+syzbot created an exfat image with cluster bits not set for the allocation
+bitmap. exfat-fs reads and uses the allocation bitmap without checking
+this. The problem is that if the start cluster of the allocation bitmap
+is 6, cluster 6 can be allocated when creating a directory with mkdir.
+exfat zeros out this cluster in exfat_mkdir, which can delete existing
+entries. This can reallocate the allocated entries. In addition,
+the allocation bitmap is also zeroed out, so cluster 6 can be reallocated.
+This patch adds exfat_test_bitmap_range to validate that clusters used for
+the allocation bitmap are correctly marked as in-use.
+
+Reported-by: syzbot+a725ab460fc1def9896f@syzkaller.appspotmail.com
+Tested-by: syzbot+a725ab460fc1def9896f@syzkaller.appspotmail.com
+Reviewed-by: Yuezhang Mo <Yuezhang.Mo@sony.com>
+Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+[Adapted to 6.1: replaced __le_long/lel_to_cpu word-level bitmap access
+ with per-bit test_bit_le() calls, as __le_long and lel_to_cpu do not
+ exist in 6.1. Uses same test_bit_le API as rest of exfat bitmap code.]
+Signed-off-by: Jay Wang <wanjay@amazon.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/exfat/balloc.c | 54 ++++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 42 insertions(+), 12 deletions(-)
+
+diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c
+index 32209acd51be4f..2d4fe3d754bbc5 100644
+--- a/fs/exfat/balloc.c
++++ b/fs/exfat/balloc.c
+@@ -45,12 +45,37 @@ static const unsigned char used_bit[] = {
+ /*
+ * Allocation Bitmap Management Functions
+ */
++static bool exfat_test_bitmap_range(struct super_block *sb, unsigned int clu,
++ unsigned int count)
++{
++ struct exfat_sb_info *sbi = EXFAT_SB(sb);
++ unsigned int start = clu;
++ unsigned int end = clu + count;
++ unsigned int ent_idx, i, b;
++
++ if (!is_valid_cluster(sbi, start) || !is_valid_cluster(sbi, end - 1))
++ return false;
++
++ while (start < end) {
++ ent_idx = CLUSTER_TO_BITMAP_ENT(start);
++ i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
++ b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
++
++ if (!test_bit_le(b, sbi->vol_amap[i]->b_data))
++ return false;
++
++ start++;
++ }
++
++ return true;
++}
++
+ static int exfat_allocate_bitmap(struct super_block *sb,
+ struct exfat_dentry *ep)
+ {
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ long long map_size;
+- unsigned int i, need_map_size;
++ unsigned int i, j, need_map_size;
+ sector_t sector;
+
+ sbi->map_clu = le32_to_cpu(ep->dentry.bitmap.start_clu);
+@@ -77,20 +102,25 @@ static int exfat_allocate_bitmap(struct super_block *sb,
+ sector = exfat_cluster_to_sector(sbi, sbi->map_clu);
+ for (i = 0; i < sbi->map_sectors; i++) {
+ sbi->vol_amap[i] = sb_bread(sb, sector + i);
+- if (!sbi->vol_amap[i]) {
+- /* release all buffers and free vol_amap */
+- int j = 0;
+-
+- while (j < i)
+- brelse(sbi->vol_amap[j++]);
+-
+- kvfree(sbi->vol_amap);
+- sbi->vol_amap = NULL;
+- return -EIO;
+- }
++ if (!sbi->vol_amap[i])
++ goto err_out;
+ }
+
++ if (exfat_test_bitmap_range(sb, sbi->map_clu,
++ EXFAT_B_TO_CLU_ROUND_UP(map_size, sbi)) == false)
++ goto err_out;
++
+ return 0;
++
++err_out:
++ j = 0;
++ /* release all buffers and free vol_amap */
++ while (j < i)
++ brelse(sbi->vol_amap[j++]);
++
++ kvfree(sbi->vol_amap);
++ sbi->vol_amap = NULL;
++ return -EIO;
+ }
+
+ int exfat_load_bitmap(struct super_block *sb)
+--
+2.53.0
+
--- /dev/null
+From 5c2d836210e8692514117e112d8e66ca5c39d4e2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 08:26:55 -0700
+Subject: fscrypt: Avoid dynamic allocation in fscrypt_get_devices()
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 6fe4e4b8259e1330945b5f3c9476e08473b8e0e8 upstream.
+
+When a blk_crypto_key starts being used or is evicted, fs/crypto/ calls
+fscrypt_get_devices() to get the filesystem's list of block devices,
+then iterates over them and calls blk_crypto_config_supported(),
+blk_crypto_start_using_key(), or blk_crypto_evict_key() on each one.
+
+Currently, the block device pointers are placed in a dynamically
+allocated array. This dynamic allocation is problematic because:
+
+- It can fail, especially at the fscrypt_destroy_inline_crypt_key() call
+ site when it's invoked for inode eviction under direct reclaim.
+
+- fscrypt_destroy_inline_crypt_key() doesn't handle the failure. It
+ just zeroizes and frees the blk_crypto_key without calling
+ blk_crypto_evict_key(). That causes a use-after-free.
+
+For now, let's fix this in the straightforward and easily-backportable
+way by switching to an on-stack array. Currently the fscrypt
+multi-device functionality is used only by f2fs, which has a hardcoded
+limit of 8 block devices. An on-stack array works fine for that.
+
+(Of course, this solution won't scale up to large number of block
+devices. For that we'd need a different solution, like moving the block
+device iteration into the filesystem. Or in the case of btrfs, which
+will only support blk-crypto-fallback, we should make it just call
+blk-crypto-fallback directly, so the block devices won't be needed.)
+
+Fixes: 22e9947a4b2b ("fscrypt: stop holding extra request_queue references")
+Cc: stable@vger.kernel.org
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Closes: https://sashiko.dev/#/patchset/20260713023708.9245-1-ebiggers%40kernel.org
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Link: https://patch.msgid.link/20260719055602.78828-1-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/crypto/inline_crypt.c | 57 ++++++++++++++--------------------------
+ fs/f2fs/super.c | 25 ++++++++++--------
+ include/linux/fscrypt.h | 18 +++++++------
+ 3 files changed, 44 insertions(+), 56 deletions(-)
+
+diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
+index 8bfb3ce864766e..47645c5539bc84 100644
+--- a/fs/crypto/inline_crypt.c
++++ b/fs/crypto/inline_crypt.c
+@@ -21,22 +21,14 @@
+
+ #include "fscrypt_private.h"
+
+-static struct block_device **fscrypt_get_devices(struct super_block *sb,
+- unsigned int *num_devs)
++static unsigned int
++fscrypt_get_devices(struct super_block *sb,
++ struct block_device *devs[FSCRYPT_MAX_DEVICES])
+ {
+- struct block_device **devs;
+-
+- if (sb->s_cop->get_devices) {
+- devs = sb->s_cop->get_devices(sb, num_devs);
+- if (devs)
+- return devs;
+- }
+- devs = kmalloc(sizeof(*devs), GFP_KERNEL);
+- if (!devs)
+- return ERR_PTR(-ENOMEM);
++ if (sb->s_cop->get_devices)
++ return sb->s_cop->get_devices(sb, devs);
+ devs[0] = sb->s_bdev;
+- *num_devs = 1;
+- return devs;
++ return 1;
+ }
+
+ static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_info *ci)
+@@ -95,7 +87,7 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci)
+ const struct inode *inode = ci->ci_inode;
+ struct super_block *sb = inode->i_sb;
+ struct blk_crypto_config crypto_cfg;
+- struct block_device **devs;
++ struct block_device *devs[FSCRYPT_MAX_DEVICES];
+ unsigned int num_devs;
+ unsigned int i;
+
+@@ -132,20 +124,15 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci)
+ crypto_cfg.data_unit_size = sb->s_blocksize;
+ crypto_cfg.dun_bytes = fscrypt_get_dun_bytes(ci);
+
+- devs = fscrypt_get_devices(sb, &num_devs);
+- if (IS_ERR(devs))
+- return PTR_ERR(devs);
+-
++ num_devs = fscrypt_get_devices(sb, devs);
+ for (i = 0; i < num_devs; i++) {
+ if (!blk_crypto_config_supported(devs[i], &crypto_cfg))
+- goto out_free_devs;
++ return 0;
+ }
+
+ fscrypt_log_blk_crypto_impl(ci->ci_mode, devs, num_devs, &crypto_cfg);
+
+ ci->ci_inlinecrypt = true;
+-out_free_devs:
+- kfree(devs);
+
+ return 0;
+ }
+@@ -158,7 +145,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
+ struct super_block *sb = inode->i_sb;
+ enum blk_crypto_mode_num crypto_mode = ci->ci_mode->blk_crypto_mode;
+ struct blk_crypto_key *blk_key;
+- struct block_device **devs;
++ struct block_device *devs[FSCRYPT_MAX_DEVICES];
+ unsigned int num_devs;
+ unsigned int i;
+ int err;
+@@ -175,17 +162,12 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
+ }
+
+ /* Start using blk-crypto on all the filesystem's block devices. */
+- devs = fscrypt_get_devices(sb, &num_devs);
+- if (IS_ERR(devs)) {
+- err = PTR_ERR(devs);
+- goto fail;
+- }
++ num_devs = fscrypt_get_devices(sb, devs);
+ for (i = 0; i < num_devs; i++) {
+ err = blk_crypto_start_using_key(devs[i], blk_key);
+ if (err)
+ break;
+ }
+- kfree(devs);
+ if (err) {
+ fscrypt_err(inode, "error %d starting to use blk-crypto", err);
+ goto fail;
+@@ -209,20 +191,21 @@ void fscrypt_destroy_inline_crypt_key(struct super_block *sb,
+ struct fscrypt_prepared_key *prep_key)
+ {
+ struct blk_crypto_key *blk_key = prep_key->blk_key;
+- struct block_device **devs;
++ struct block_device *devs[FSCRYPT_MAX_DEVICES];
+ unsigned int num_devs;
+ unsigned int i;
+
+ if (!blk_key)
+ return;
+
+- /* Evict the key from all the filesystem's block devices. */
+- devs = fscrypt_get_devices(sb, &num_devs);
+- if (!IS_ERR(devs)) {
+- for (i = 0; i < num_devs; i++)
+- blk_crypto_evict_key(devs[i], blk_key);
+- kfree(devs);
+- }
++ /*
++ * Evict the key from all the filesystem's block devices.
++ * This *must* be done before the key is freed.
++ */
++ num_devs = fscrypt_get_devices(sb, devs);
++ for (i = 0; i < num_devs; i++)
++ blk_crypto_evict_key(devs[i], blk_key);
++
+ kfree_sensitive(blk_key);
+ }
+
+diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
+index 7c8e05a81a0c63..9d1b5699f5bf1a 100644
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -3126,24 +3126,27 @@ static void f2fs_get_ino_and_lblk_bits(struct super_block *sb,
+ *lblk_bits_ret = 8 * sizeof(block_t);
+ }
+
+-static struct block_device **f2fs_get_devices(struct super_block *sb,
+- unsigned int *num_devs)
++static unsigned int
++f2fs_get_devices(struct super_block *sb,
++ struct block_device *devs[FSCRYPT_MAX_DEVICES])
+ {
+ struct f2fs_sb_info *sbi = F2FS_SB(sb);
+- struct block_device **devs;
++ int ndevs;
+ int i;
+
+- if (!f2fs_is_multi_device(sbi))
+- return NULL;
++ static_assert(MAX_DEVICES <= FSCRYPT_MAX_DEVICES);
+
+- devs = kmalloc_array(sbi->s_ndevs, sizeof(*devs), GFP_KERNEL);
+- if (!devs)
+- return ERR_PTR(-ENOMEM);
++ if (!f2fs_is_multi_device(sbi)) {
++ devs[0] = sb->s_bdev;
++ return 1;
++ }
++ ndevs = sbi->s_ndevs;
++ if (WARN_ON_ONCE(ndevs > FSCRYPT_MAX_DEVICES))
++ ndevs = FSCRYPT_MAX_DEVICES;
+
+- for (i = 0; i < sbi->s_ndevs; i++)
++ for (i = 0; i < ndevs; i++)
+ devs[i] = FDEV(i).bdev;
+- *num_devs = sbi->s_ndevs;
+- return devs;
++ return ndevs;
+ }
+
+ static const struct fscrypt_operations f2fs_cryptops = {
+diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
+index 4f5f8a65121328..fe842c9af9dcb8 100644
+--- a/include/linux/fscrypt.h
++++ b/include/linux/fscrypt.h
+@@ -57,6 +57,9 @@ struct fscrypt_name {
+ /* Maximum value for the third parameter of fscrypt_operations.set_context(). */
+ #define FSCRYPT_SET_CONTEXT_MAX_SIZE 40
+
++/* Maximum supported number of block devices per filesystem */
++#define FSCRYPT_MAX_DEVICES 8
++
+ #ifdef CONFIG_FS_ENCRYPTION
+
+ /*
+@@ -161,21 +164,20 @@ struct fscrypt_operations {
+ int *ino_bits_ret, int *lblk_bits_ret);
+
+ /*
+- * Return an array of pointers to the block devices to which the
+- * filesystem may write encrypted file contents, NULL if the filesystem
+- * only has a single such block device, or an ERR_PTR() on error.
++ * Retrieve the list of block devices to which the filesystem may write
++ * encrypted file contents.
+ *
+- * On successful non-NULL return, *num_devs is set to the number of
+- * devices in the returned array. The caller must free the returned
+- * array using kfree().
++ * This writes the block_device pointers to @devs and returns the count
++ * (between 1 and FSCRYPT_MAX_DEVICES inclusively).
+ *
+ * If the filesystem can use multiple block devices (other than block
+ * devices that aren't used for encrypted file contents, such as
+ * external journal devices), and wants to support inline encryption,
+ * then it must implement this function. Otherwise it's not needed.
+ */
+- struct block_device **(*get_devices)(struct super_block *sb,
+- unsigned int *num_devs);
++ unsigned int (*get_devices)(
++ struct super_block *sb,
++ struct block_device *devs[FSCRYPT_MAX_DEVICES]);
+ };
+
+ static inline struct fscrypt_info *fscrypt_get_info(const struct inode *inode)
+--
+2.53.0
+
--- /dev/null
+From 11a4c956410a51d8317bdb2c6d10c7ff735103f0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 21:21:11 +0000
+Subject: i40e: remove read access to debugfs files
+
+From: Jacob Keller <jacob.e.keller@intel.com>
+
+[ Upstream commit 9fcdb1c3c4ba134434694c001dbff343f1ffa319 ]
+
+The 'command' and 'netdev_ops' debugfs files are a legacy debugging
+interface supported by the i40e driver since its early days by commit
+02e9c290814c ("i40e: debugfs interface").
+
+Both of these debugfs files provide a read handler which is mostly useless,
+and which is implemented with questionable logic. They both use a static
+256 byte buffer which is initialized to the empty string. In the case of
+the 'command' file this buffer is literally never used and simply wastes
+space. In the case of the 'netdev_ops' file, the last command written is
+saved here.
+
+On read, the files contents are presented as the name of the device
+followed by a colon and then the contents of their respective static
+buffer. For 'command' this will always be "<device>: ". For 'netdev_ops',
+this will be "<device>: <last command written>". But note the buffer is
+shared between all devices operated by this module. At best, it is mostly
+meaningless information, and at worse it could be accessed simultaneously
+as there doesn't appear to be any locking mechanism.
+
+We have also recently received multiple reports for both read functions
+about their use of snprintf and potential overflow that could result in
+reading arbitrary kernel memory. For the 'command' file, this is
+definitely impossible, since the static buffer is always zero and never
+written to. For the 'netdev_ops' file, it does appear to be possible, if
+the user carefully crafts the command input, it will be copied into the
+buffer, which could be large enough to cause snprintf to truncate, which
+then causes the copy_to_user to read beyond the length of the buffer
+allocated by kzalloc.
+
+A minimal fix would be to replace snprintf() with scnprintf() which would
+cap the return to the number of bytes written, preventing an overflow. A
+more involved fix would be to drop the mostly useless static buffers,
+saving 512 bytes and modifying the read functions to stop needing those as
+input.
+
+Instead, lets just completely drop the read access to these files. These
+are debug interfaces exposed as part of debugfs, and I don't believe that
+dropping read access will break any script, as the provided output is
+pretty useless. You can find the netdev name through other more standard
+interfaces, and the 'netdev_ops' interface can easily result in garbage if
+you issue simultaneous writes to multiple devices at once.
+
+In order to properly remove the i40e_dbg_netdev_ops_buf, we need to
+refactor its write function to avoid using the static buffer. Instead, use
+the same logic as the i40e_dbg_command_write, with an allocated buffer.
+Update the code to use this instead of the static buffer, and ensure we
+free the buffer on exit. This fixes simultaneous writes to 'netdev_ops' on
+multiple devices, and allows us to remove the now unused static buffer
+along with removing the read access.
+
+Fixes: 02e9c290814c ("i40e: debugfs interface")
+Reported-by: Kunwu Chan <chentao@kylinos.cn>
+Closes: https://lore.kernel.org/intel-wired-lan/20231208031950.47410-1-chentao@kylinos.cn/
+Reported-by: Wang Haoran <haoranwangsec@gmail.com>
+Closes: https://lore.kernel.org/all/CANZ3JQRRiOdtfQJoP9QM=6LS1Jto8PGBGw6y7-TL=BcnzHQn1Q@mail.gmail.com/
+Reported-by: Amir Mohammad Jahangirzad <a.jahangirzad@gmail.com>
+Closes: https://lore.kernel.org/all/20250722115017.206969-1-a.jahangirzad@gmail.com/
+Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
+Reviewed-by: Dawid Osuchowski <dawid.osuchowski@linux.intel.com>
+Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Reviewed-by: Kunwu Chan <kunwu.chan@linux.dev>
+Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+[Adapted to 6.1: context conflict due to 6.1 using pf->vsi[pf->lan_vsi]
+ vs i40e_pf_get_main_vsi(pf) in the removed read functions; resolution
+ is simply to delete the 6.1 version of those functions.]
+Signed-off-by: Jay Wang <wanjay@amazon.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/intel/i40e/i40e_debugfs.c | 121 +++---------------
+ 1 file changed, 19 insertions(+), 102 deletions(-)
+
+diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+index b438cf846c41b2..5b59db6a5439cd 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
++++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+@@ -57,47 +57,6 @@ static struct i40e_veb *i40e_dbg_find_veb(struct i40e_pf *pf, int seid)
+ * setup, adding or removing filters, or other things. Many of
+ * these will be useful for some forms of unit testing.
+ **************************************************************/
+-static char i40e_dbg_command_buf[256] = "";
+-
+-/**
+- * i40e_dbg_command_read - read for command datum
+- * @filp: the opened file
+- * @buffer: where to write the data for the user to read
+- * @count: the size of the user's buffer
+- * @ppos: file position offset
+- **/
+-static ssize_t i40e_dbg_command_read(struct file *filp, char __user *buffer,
+- size_t count, loff_t *ppos)
+-{
+- struct i40e_pf *pf = filp->private_data;
+- int bytes_not_copied;
+- int buf_size = 256;
+- char *buf;
+- int len;
+-
+- /* don't allow partial reads */
+- if (*ppos != 0)
+- return 0;
+- if (count < buf_size)
+- return -ENOSPC;
+-
+- buf = kzalloc(buf_size, GFP_KERNEL);
+- if (!buf)
+- return -ENOSPC;
+-
+- len = snprintf(buf, buf_size, "%s: %s\n",
+- pf->vsi[pf->lan_vsi]->netdev->name,
+- i40e_dbg_command_buf);
+-
+- bytes_not_copied = copy_to_user(buffer, buf, len);
+- kfree(buf);
+-
+- if (bytes_not_copied)
+- return -EFAULT;
+-
+- *ppos = len;
+- return len;
+-}
+
+ static char *i40e_filter_state_string[] = {
+ "INVALID",
+@@ -1636,7 +1595,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
+ static const struct file_operations i40e_dbg_command_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+- .read = i40e_dbg_command_read,
+ .write = i40e_dbg_command_write,
+ };
+
+@@ -1645,47 +1603,6 @@ static const struct file_operations i40e_dbg_command_fops = {
+ * The netdev_ops entry in debugfs is for giving the driver commands
+ * to be executed from the netdev operations.
+ **************************************************************/
+-static char i40e_dbg_netdev_ops_buf[256] = "";
+-
+-/**
+- * i40e_dbg_netdev_ops_read - read for netdev_ops datum
+- * @filp: the opened file
+- * @buffer: where to write the data for the user to read
+- * @count: the size of the user's buffer
+- * @ppos: file position offset
+- **/
+-static ssize_t i40e_dbg_netdev_ops_read(struct file *filp, char __user *buffer,
+- size_t count, loff_t *ppos)
+-{
+- struct i40e_pf *pf = filp->private_data;
+- int bytes_not_copied;
+- int buf_size = 256;
+- char *buf;
+- int len;
+-
+- /* don't allow partal reads */
+- if (*ppos != 0)
+- return 0;
+- if (count < buf_size)
+- return -ENOSPC;
+-
+- buf = kzalloc(buf_size, GFP_KERNEL);
+- if (!buf)
+- return -ENOSPC;
+-
+- len = snprintf(buf, buf_size, "%s: %s\n",
+- pf->vsi[pf->lan_vsi]->netdev->name,
+- i40e_dbg_netdev_ops_buf);
+-
+- bytes_not_copied = copy_to_user(buffer, buf, len);
+- kfree(buf);
+-
+- if (bytes_not_copied)
+- return -EFAULT;
+-
+- *ppos = len;
+- return len;
+-}
+
+ /**
+ * i40e_dbg_netdev_ops_write - write into netdev_ops datum
+@@ -1699,35 +1616,36 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
+ size_t count, loff_t *ppos)
+ {
+ struct i40e_pf *pf = filp->private_data;
++ char *cmd_buf, *buf_tmp;
+ int bytes_not_copied;
+ struct i40e_vsi *vsi;
+- char *buf_tmp;
+ int vsi_seid;
+ int i, cnt;
+
+ /* don't allow partial writes */
+ if (*ppos != 0)
+ return 0;
+- if (count >= sizeof(i40e_dbg_netdev_ops_buf))
+- return -ENOSPC;
+
+- memset(i40e_dbg_netdev_ops_buf, 0, sizeof(i40e_dbg_netdev_ops_buf));
+- bytes_not_copied = copy_from_user(i40e_dbg_netdev_ops_buf,
+- buffer, count);
+- if (bytes_not_copied)
++ cmd_buf = kzalloc(count + 1, GFP_KERNEL);
++ if (!cmd_buf)
++ return count;
++ bytes_not_copied = copy_from_user(cmd_buf, buffer, count);
++ if (bytes_not_copied) {
++ kfree(cmd_buf);
+ return -EFAULT;
+- i40e_dbg_netdev_ops_buf[count] = '\0';
++ }
++ cmd_buf[count] = '\0';
+
+- buf_tmp = strchr(i40e_dbg_netdev_ops_buf, '\n');
++ buf_tmp = strchr(cmd_buf, '\n');
+ if (buf_tmp) {
+ *buf_tmp = '\0';
+- count = buf_tmp - i40e_dbg_netdev_ops_buf + 1;
++ count = buf_tmp - cmd_buf + 1;
+ }
+
+- if (strncmp(i40e_dbg_netdev_ops_buf, "change_mtu", 10) == 0) {
++ if (strncmp(cmd_buf, "change_mtu", 10) == 0) {
+ int mtu;
+
+- cnt = sscanf(&i40e_dbg_netdev_ops_buf[11], "%i %i",
++ cnt = sscanf(&cmd_buf[11], "%i %i",
+ &vsi_seid, &mtu);
+ if (cnt != 2) {
+ dev_info(&pf->pdev->dev, "change_mtu <vsi_seid> <mtu>\n");
+@@ -1749,8 +1667,8 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
+ dev_info(&pf->pdev->dev, "Could not acquire RTNL - please try again\n");
+ }
+
+- } else if (strncmp(i40e_dbg_netdev_ops_buf, "set_rx_mode", 11) == 0) {
+- cnt = sscanf(&i40e_dbg_netdev_ops_buf[11], "%i", &vsi_seid);
++ } else if (strncmp(cmd_buf, "set_rx_mode", 11) == 0) {
++ cnt = sscanf(&cmd_buf[11], "%i", &vsi_seid);
+ if (cnt != 1) {
+ dev_info(&pf->pdev->dev, "set_rx_mode <vsi_seid>\n");
+ goto netdev_ops_write_done;
+@@ -1770,8 +1688,8 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
+ dev_info(&pf->pdev->dev, "Could not acquire RTNL - please try again\n");
+ }
+
+- } else if (strncmp(i40e_dbg_netdev_ops_buf, "napi", 4) == 0) {
+- cnt = sscanf(&i40e_dbg_netdev_ops_buf[4], "%i", &vsi_seid);
++ } else if (strncmp(cmd_buf, "napi", 4) == 0) {
++ cnt = sscanf(&cmd_buf[4], "%i", &vsi_seid);
+ if (cnt != 1) {
+ dev_info(&pf->pdev->dev, "napi <vsi_seid>\n");
+ goto netdev_ops_write_done;
+@@ -1789,21 +1707,20 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
+ dev_info(&pf->pdev->dev, "napi called\n");
+ }
+ } else {
+- dev_info(&pf->pdev->dev, "unknown command '%s'\n",
+- i40e_dbg_netdev_ops_buf);
++ dev_info(&pf->pdev->dev, "unknown command '%s'\n", cmd_buf);
+ dev_info(&pf->pdev->dev, "available commands\n");
+ dev_info(&pf->pdev->dev, " change_mtu <vsi_seid> <mtu>\n");
+ dev_info(&pf->pdev->dev, " set_rx_mode <vsi_seid>\n");
+ dev_info(&pf->pdev->dev, " napi <vsi_seid>\n");
+ }
+ netdev_ops_write_done:
++ kfree(cmd_buf);
+ return count;
+ }
+
+ static const struct file_operations i40e_dbg_netdev_ops_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+- .read = i40e_dbg_netdev_ops_read,
+ .write = i40e_dbg_netdev_ops_write,
+ };
+
+--
+2.53.0
+
--- /dev/null
+From 6b56124b745d9b091b88ee8d29fa815be08bacca Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 12:08:08 +0300
+Subject: ipv6: ndisc: fix NULL deref in accept_untracked_na()
+
+From: Weiming Shi <bestswngs@gmail.com>
+
+commit d186e942365acece7c56d39da05dd63bf95b280a upstream.
+
+accept_untracked_na() re-fetches the inet6_dev with __in6_dev_get(dev)
+and dereferences idev->cnf.accept_untracked_na without a NULL check,
+even though its only caller ndisc_recv_na() already fetched and
+NULL-checked idev for the same device.
+
+Both reads of dev->ip6_ptr run in the same RCU read-side critical
+section, but a concurrent addrconf_ifdown() can clear dev->ip6_ptr
+between them: lowering the MTU below IPV6_MIN_MTU calls addrconf_ifdown()
+without the synchronize_net() that orders the unregister path, so the
+re-fetch returns NULL and oopses:
+
+ BUG: KASAN: null-ptr-deref in ndisc_recv_na (net/ipv6/ndisc.c:974)
+ Read of size 4 at addr 0000000000000364
+ Call Trace:
+ <IRQ>
+ ndisc_recv_na (net/ipv6/ndisc.c:974)
+ icmpv6_rcv (net/ipv6/icmp.c:1193)
+ ip6_protocol_deliver_rcu (net/ipv6/ip6_input.c:479)
+ ip6_input_finish (net/ipv6/ip6_input.c:534)
+ ip6_input (net/ipv6/ip6_input.c:545)
+ ip6_mc_input (net/ipv6/ip6_input.c:635)
+ ipv6_rcv (net/ipv6/ip6_input.c:351)
+ </IRQ>
+
+It is reachable by an unprivileged user via a network namespace.
+
+Pass the caller's already validated idev instead of re-fetching it; the
+idev stays alive for the whole RCU critical section, so it is safe even
+after dev->ip6_ptr has been cleared.
+
+Fixes: aaa5f515b16b ("net: ipv6: new accept_untracked_na option to accept na only if in-network")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Weiming Shi <bestswngs@gmail.com>
+Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Link: https://patch.msgid.link/20260617065512.2529757-2-bestswngs@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Alexander Martyniuk <alexevgmart@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ndisc.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
+index f1c4c4dbefb0c9..85f7798d3e55c4 100644
+--- a/net/ipv6/ndisc.c
++++ b/net/ipv6/ndisc.c
+@@ -972,10 +972,8 @@ static void ndisc_recv_ns(struct sk_buff *skb)
+ in6_dev_put(idev);
+ }
+
+-static int accept_untracked_na(struct net_device *dev, struct in6_addr *saddr)
++static int accept_untracked_na(struct inet6_dev *idev, struct in6_addr *saddr)
+ {
+- struct inet6_dev *idev = __in6_dev_get(dev);
+-
+ switch (idev->cnf.accept_untracked_na) {
+ case 0: /* Don't accept untracked na (absent in neighbor cache) */
+ return 0;
+@@ -985,7 +983,7 @@ static int accept_untracked_na(struct net_device *dev, struct in6_addr *saddr)
+ * same subnet as an address configured on the interface that
+ * received the na
+ */
+- return !!ipv6_chk_prefix(saddr, dev);
++ return !!ipv6_chk_prefix(saddr, idev->dev);
+ default:
+ return 0;
+ }
+@@ -1086,7 +1084,7 @@ static void ndisc_recv_na(struct sk_buff *skb)
+ */
+ new_state = msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE;
+ if (!neigh && lladdr && idev && idev->cnf.forwarding) {
+- if (accept_untracked_na(dev, saddr)) {
++ if (accept_untracked_na(idev, saddr)) {
+ neigh = neigh_create(&nd_tbl, &msg->target, dev);
+ new_state = NUD_STALE;
+ }
+--
+2.53.0
+
--- /dev/null
+From 6284f2aba2f71a8e190a32193f09eee6d5550590 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 22:58:53 +0200
+Subject: openvswitch: fix GSO userspace truncation underflow
+
+From: Kyle Zeng <kylebot@openai.com>
+
+[ Upstream commit 4032f8ed10fcb84d41c508dfb04be96589f78dfe ]
+
+OVS_ACTION_ATTR_TRUNC currently stores a delta from the original skb
+length in OVS_CB(skb)->cutlen. When a later userspace action segments a
+GSO skb, queue_gso_packets() reuses that delta for each smaller segment.
+A segment can then reach queue_userspace_packet() with cutlen greater
+than skb->len, underflowing the length passed to skb_zerocopy().
+
+Store the maximum preserved length instead and bound each consumer
+against the current skb length. Use U32_MAX as the no-truncation
+sentinel so the value remains valid if skb geometry changes before a
+consumer handles it.
+
+Fixes: f2a4d086ed4c ("openvswitch: Add packet truncation support.")
+Cc: stable@vger.kernel.org
+Assisted-by: Codex:gpt-5.5
+Signed-off-by: Kyle Zeng <kylebot@openai.com>
+Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
+Reviewed-by: Aaron Conole <aconole@redhat.com>
+Link: https://patch.msgid.link/20260707221635.27489-1-kylebot@openai.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[6.1.y supports neither OVS_ACTION_ATTR_PSAMPLE nor OVS drop reasons]
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/actions.c | 15 +++++----------
+ net/openvswitch/datapath.c | 25 ++++++++++++++-----------
+ net/openvswitch/datapath.h | 2 +-
+ net/openvswitch/vport.c | 2 +-
+ 4 files changed, 21 insertions(+), 23 deletions(-)
+
+diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
+index f7cc87e67d3c8c..18e419affb5727 100644
+--- a/net/openvswitch/actions.c
++++ b/net/openvswitch/actions.c
+@@ -856,12 +856,8 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
+ u16 mru = OVS_CB(skb)->mru;
+ u32 cutlen = OVS_CB(skb)->cutlen;
+
+- if (unlikely(cutlen > 0)) {
+- if (skb->len - cutlen > ovs_mac_header_len(key))
+- pskb_trim(skb, skb->len - cutlen);
+- else
+- pskb_trim(skb, ovs_mac_header_len(key));
+- }
++ if (unlikely(cutlen < skb->len))
++ pskb_trim(skb, max(cutlen, ovs_mac_header_len(key)));
+
+ if (likely(!mru ||
+ (skb->len <= mru + vport->dev->hard_header_len))) {
+@@ -1242,22 +1238,21 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
+ clone = skb_clone(skb, GFP_ATOMIC);
+ if (clone)
+ do_output(dp, clone, port, key);
+- OVS_CB(skb)->cutlen = 0;
++ OVS_CB(skb)->cutlen = U32_MAX;
+ break;
+ }
+
+ case OVS_ACTION_ATTR_TRUNC: {
+ struct ovs_action_trunc *trunc = nla_data(a);
+
+- if (skb->len > trunc->max_len)
+- OVS_CB(skb)->cutlen = skb->len - trunc->max_len;
++ OVS_CB(skb)->cutlen = trunc->max_len;
+ break;
+ }
+
+ case OVS_ACTION_ATTR_USERSPACE:
+ output_userspace(dp, skb, key, a, attr,
+ len, OVS_CB(skb)->cutlen);
+- OVS_CB(skb)->cutlen = 0;
++ OVS_CB(skb)->cutlen = U32_MAX;
+ break;
+
+ case OVS_ACTION_ATTR_HASH:
+diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
+index 0c0d89470145a1..1181807f2b5020 100644
+--- a/net/openvswitch/datapath.c
++++ b/net/openvswitch/datapath.c
+@@ -251,7 +251,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
+ upcall.portid = ovs_vport_find_upcall_portid(p, skb);
+
+ upcall.mru = OVS_CB(skb)->mru;
+- error = ovs_dp_upcall(dp, skb, key, &upcall, 0);
++ error = ovs_dp_upcall(dp, skb, key, &upcall, U32_MAX);
+ switch (error) {
+ case 0:
+ case -EAGAIN:
+@@ -414,7 +414,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ struct sk_buff *nskb = NULL;
+ struct sk_buff *user_skb = NULL; /* to be queued to userspace */
+ struct nlattr *nla;
+- size_t len;
++ size_t msg_size;
++ size_t skb_len;
+ unsigned int hlen;
+ int err, dp_ifindex;
+ u64 hash;
+@@ -435,7 +436,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ skb = nskb;
+ }
+
+- if (nla_attr_size(skb->len) > USHRT_MAX) {
++ skb_len = min(skb->len, cutlen);
++ if (nla_attr_size(skb_len) > USHRT_MAX) {
+ err = -EFBIG;
+ goto out;
+ }
+@@ -450,13 +452,13 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ * padding logic. Only perform zerocopy if padding is not required.
+ */
+ if (dp->user_features & OVS_DP_F_UNALIGNED)
+- hlen = skb_zerocopy_headlen(skb);
++ hlen = min(skb_zerocopy_headlen(skb), cutlen);
+ else
+- hlen = skb->len;
++ hlen = skb_len;
+
+- len = upcall_msg_size(upcall_info, hlen - cutlen,
+- OVS_CB(skb)->acts_origlen);
+- user_skb = genlmsg_new(len, GFP_ATOMIC);
++ msg_size = upcall_msg_size(upcall_info, hlen,
++ OVS_CB(skb)->acts_origlen);
++ user_skb = genlmsg_new(msg_size, GFP_ATOMIC);
+ if (!user_skb) {
+ err = -ENOMEM;
+ goto out;
+@@ -517,7 +519,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ }
+
+ /* Add OVS_PACKET_ATTR_LEN when packet is truncated */
+- if (cutlen > 0 &&
++ if (skb_len < skb->len &&
+ nla_put_u32(user_skb, OVS_PACKET_ATTR_LEN, skb->len)) {
+ err = -ENOBUFS;
+ goto out;
+@@ -542,9 +544,9 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ err = -ENOBUFS;
+ goto out;
+ }
+- nla->nla_len = nla_attr_size(skb->len - cutlen);
++ nla->nla_len = nla_attr_size(skb_len);
+
+- err = skb_zerocopy(user_skb, skb, skb->len - cutlen, hlen);
++ err = skb_zerocopy(user_skb, skb, skb_len, hlen);
+ if (err)
+ goto out;
+
+@@ -601,6 +603,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
+ packet->ignore_df = 1;
+ }
+ OVS_CB(packet)->mru = mru;
++ OVS_CB(packet)->cutlen = U32_MAX;
+
+ if (a[OVS_PACKET_ATTR_HASH]) {
+ hash = nla_get_u64(a[OVS_PACKET_ATTR_HASH]);
+diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
+index 0cd29971a907ca..88156a677f22c5 100644
+--- a/net/openvswitch/datapath.h
++++ b/net/openvswitch/datapath.h
+@@ -114,7 +114,7 @@ struct datapath {
+ * @mru: The maximum received fragement size; 0 if the packet is not
+ * fragmented.
+ * @acts_origlen: The netlink size of the flow actions applied to this skb.
+- * @cutlen: The number of bytes from the packet end to be removed.
++ * @cutlen: The number of bytes in the packet to preserve on output.
+ */
+ struct ovs_skb_cb {
+ struct vport *input_vport;
+diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
+index 5d7af559a20bed..e83aa6417ffde0 100644
+--- a/net/openvswitch/vport.c
++++ b/net/openvswitch/vport.c
+@@ -438,7 +438,7 @@ int ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
+
+ OVS_CB(skb)->input_vport = vport;
+ OVS_CB(skb)->mru = 0;
+- OVS_CB(skb)->cutlen = 0;
++ OVS_CB(skb)->cutlen = U32_MAX;
+ if (unlikely(dev_net(skb->dev) != ovs_dp_get_net(vport->dp))) {
+ u32 mark;
+
+--
+2.53.0
+
--- /dev/null
+From f4f4500df13d067b00911d2a51da6096ce02f97e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 09:38:09 +0800
+Subject: RISC-V: KVM: Serialize virtual interrupt pending state updates
+
+From: Xie Bo <xb@ultrarisc.com>
+
+commit d024a0a7879e6f37c0152aacf6d8e37b214a1738 upstream.
+
+KVM RISC-V tracks guest local interrupt state with two bitmaps:
+
+ - irqs_pending: interrupts that should be visible to the guest
+ - irqs_pending_mask: interrupts whose pending state changed
+
+The current code updates those bitmaps with independent atomic bitops
+and assumes a multiple-producer, single-consumer protocol. That model
+does not actually hold.
+
+kvm_riscv_vcpu_sync_interrupts() is not a pure consumer. When the guest
+changes guest-visible HVIP state, sync_interrupts() writes both
+irqs_pending and irqs_pending_mask to reflect the new guest state back
+into KVM state. As a result, irqs_pending and irqs_pending_mask form a
+single logical state transition, but they are not updated atomically as
+a pair.
+
+This allows a race where a newly injected interrupt is lost. For
+example:
+
+ CPU0 CPU1
+ ---- ----
+ kvm_riscv_vcpu_set_interrupt(VS_SOFT)
+ set_bit(VS_SOFT, irqs_pending)
+ kvm_riscv_vcpu_sync_interrupts()
+ sees guest-cleared HVIP.VSSIP
+ sets irqs_pending_mask
+ clear_bit(IRQ_VS_SOFT, irqs_pending)
+ set_bit(VS_SOFT, irqs_pending_mask)
+ kvm_vcpu_kick()
+
+After that interleaving, a later flush can update HVIP without VSSIP
+even though a new virtual interrupt was injected. In practice, the
+guest can remain blocked in WFI with work pending.
+
+The same pending/mask protocol is shared by VS soft interrupts, PMU
+overflow delivery, and AIA high interrupt synchronization, so the race
+is not limited to one interrupt source.
+
+Fix this by serializing all updates to irqs_pending and irqs_pending_mask
+with a per-vCPU raw spinlock. This keeps the pending bit and the dirty
+mask as one state transition across:
+
+ - set/unset interrupt
+ - guest HVIP sync
+ - interrupt flush to guest CSR state
+ - vCPU reset
+ - AIA CSR writes that clear dirty state
+
+Use non-atomic bitmap operations while holding the lock. Hold the lock
+across the AIA sync, flush, and pending checks as well, so both bitmap
+words share the same serialization domain.
+
+This intentionally replaces the existing lockless protocol instead of
+trying to repair it with additional barriers. The problem is not memory
+ordering on a single field; it is that two separate bitmaps encode one
+shared state machine while both producers and sync paths can modify
+them. A per-vCPU raw spinlock keeps the fix small, local, and suitable
+for backporting.
+
+Fixes: cce69aff689e ("RISC-V: KVM: Implement VCPU interrupts and requests handling")
+Cc: stable@vger.kernel.org
+Signed-off-by: Xie Bo <xb@ultrarisc.com>
+Reviewed-by: Anup Patel <anup@brainfault.org>
+Link: https://lore.kernel.org/r/20260715020359.1521354-2-xb@ultrarisc.com
+Signed-off-by: Anup Patel <anup@brainfault.org>
+
+[ bo: Adapt to the scalar interrupt state in 6.1.y and its CSR one-reg
+ helpers in vcpu.c. Drop AIA and PMU overflow handling, which are not
+ present in this tree. ]
+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/riscv/include/asm/kvm_host.h | 10 ++--
+ arch/riscv/kvm/vcpu.c | 78 ++++++++++++++++++++++---------
+ 2 files changed, 60 insertions(+), 28 deletions(-)
+
+diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
+index dbbf43d5262348..dc5e553e136992 100644
+--- a/arch/riscv/include/asm/kvm_host.h
++++ b/arch/riscv/include/asm/kvm_host.h
+@@ -192,12 +192,12 @@ struct kvm_vcpu_arch {
+ /*
+ * VCPU interrupts
+ *
+- * We have a lockless approach for tracking pending VCPU interrupts
+- * implemented using atomic bitops. The irqs_pending bitmap represent
+- * pending interrupts whereas irqs_pending_mask represent bits changed
+- * in irqs_pending. Our approach is modeled around multiple producer
+- * and single consumer problem where the consumer is the VCPU itself.
++ * The irqs_pending field represents pending interrupts whereas
++ * irqs_pending_mask represents bits changed in irqs_pending. Updates
++ * to these fields are serialized so vcpu interrupt sync/flush cannot
++ * drop a newly injected interrupt while syncing guest-visible HVIP.
+ */
++ raw_spinlock_t irqs_pending_lock;
+ unsigned long irqs_pending;
+ unsigned long irqs_pending_mask;
+
+diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
+index 5174ef54ad1d9e..c6afbf0a9916fb 100644
+--- a/arch/riscv/kvm/vcpu.c
++++ b/arch/riscv/kvm/vcpu.c
+@@ -112,6 +112,7 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu)
+ struct kvm_vcpu_csr *reset_csr = &vcpu->arch.guest_reset_csr;
+ struct kvm_cpu_context *cntx = &vcpu->arch.guest_context;
+ struct kvm_cpu_context *reset_cntx = &vcpu->arch.guest_reset_context;
++ unsigned long flags;
+ bool loaded;
+
+ /**
+@@ -134,8 +135,10 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu)
+
+ kvm_riscv_vcpu_timer_reset(vcpu);
+
+- WRITE_ONCE(vcpu->arch.irqs_pending, 0);
+- WRITE_ONCE(vcpu->arch.irqs_pending_mask, 0);
++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++ vcpu->arch.irqs_pending = 0;
++ vcpu->arch.irqs_pending_mask = 0;
++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+
+ vcpu->arch.hfence_head = 0;
+ vcpu->arch.hfence_tail = 0;
+@@ -173,6 +176,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
+
+ /* Setup VCPU hfence queue */
+ spin_lock_init(&vcpu->arch.hfence_lock);
++ raw_spin_lock_init(&vcpu->arch.irqs_pending_lock);
+
+ /* Setup reset state of shadow SSTATUS and HSTATUS CSRs */
+ cntx = &vcpu->arch.guest_reset_context;
+@@ -444,7 +448,7 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,
+ unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK |
+ KVM_REG_SIZE_MASK |
+ KVM_REG_RISCV_CSR);
+- unsigned long reg_val;
++ unsigned long flags, reg_val;
+
+ if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long))
+ return -EINVAL;
+@@ -461,8 +465,11 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,
+
+ ((unsigned long *)csr)[reg_num] = reg_val;
+
+- if (reg_num == KVM_REG_RISCV_CSR_REG(sip))
+- WRITE_ONCE(vcpu->arch.irqs_pending_mask, 0);
++ if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++ vcpu->arch.irqs_pending_mask = 0;
++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
++ }
+
+ return 0;
+ }
+@@ -679,19 +686,26 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)
+ {
+ struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
+ unsigned long mask, val;
++ unsigned long flags;
+
+- if (READ_ONCE(vcpu->arch.irqs_pending_mask)) {
+- mask = xchg_acquire(&vcpu->arch.irqs_pending_mask, 0);
+- val = READ_ONCE(vcpu->arch.irqs_pending) & mask;
++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++
++ mask = vcpu->arch.irqs_pending_mask;
++ if (mask) {
++ vcpu->arch.irqs_pending_mask = 0;
++ val = vcpu->arch.irqs_pending & mask;
+
+ csr->hvip &= ~mask;
+ csr->hvip |= val;
+ }
++
++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+ }
+
+ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
+ {
+ unsigned long hvip;
++ unsigned long flags;
+ struct kvm_vcpu_arch *v = &vcpu->arch;
+ struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
+
+@@ -700,32 +714,40 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
+
+ /* Sync-up HVIP.VSSIP bit changes does by Guest */
+ hvip = csr_read(CSR_HVIP);
++
++ raw_spin_lock_irqsave(&v->irqs_pending_lock, flags);
++
+ if ((csr->hvip ^ hvip) & (1UL << IRQ_VS_SOFT)) {
+ if (hvip & (1UL << IRQ_VS_SOFT)) {
+- if (!test_and_set_bit(IRQ_VS_SOFT,
+- &v->irqs_pending_mask))
+- set_bit(IRQ_VS_SOFT, &v->irqs_pending);
++ if (!__test_and_set_bit(IRQ_VS_SOFT,
++ &v->irqs_pending_mask))
++ __set_bit(IRQ_VS_SOFT, &v->irqs_pending);
+ } else {
+- if (!test_and_set_bit(IRQ_VS_SOFT,
+- &v->irqs_pending_mask))
+- clear_bit(IRQ_VS_SOFT, &v->irqs_pending);
++ if (!__test_and_set_bit(IRQ_VS_SOFT,
++ &v->irqs_pending_mask))
++ __clear_bit(IRQ_VS_SOFT, &v->irqs_pending);
+ }
+ }
+
++ raw_spin_unlock_irqrestore(&v->irqs_pending_lock, flags);
++
+ /* Sync-up timer CSRs */
+ kvm_riscv_vcpu_timer_sync(vcpu);
+ }
+
+ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
+ {
++ unsigned long flags;
++
+ if (irq != IRQ_VS_SOFT &&
+ irq != IRQ_VS_TIMER &&
+ irq != IRQ_VS_EXT)
+ return -EINVAL;
+
+- set_bit(irq, &vcpu->arch.irqs_pending);
+- smp_mb__before_atomic();
+- set_bit(irq, &vcpu->arch.irqs_pending_mask);
++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++ __set_bit(irq, &vcpu->arch.irqs_pending);
++ __set_bit(irq, &vcpu->arch.irqs_pending_mask);
++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+
+ kvm_vcpu_kick(vcpu);
+
+@@ -734,24 +756,34 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
+
+ int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
+ {
++ unsigned long flags;
++
+ if (irq != IRQ_VS_SOFT &&
+ irq != IRQ_VS_TIMER &&
+ irq != IRQ_VS_EXT)
+ return -EINVAL;
+
+- clear_bit(irq, &vcpu->arch.irqs_pending);
+- smp_mb__before_atomic();
+- set_bit(irq, &vcpu->arch.irqs_pending_mask);
++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++ __clear_bit(irq, &vcpu->arch.irqs_pending);
++ __set_bit(irq, &vcpu->arch.irqs_pending_mask);
++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+
+ return 0;
+ }
+
+ bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, unsigned long mask)
+ {
+- unsigned long ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK)
+- << VSIP_TO_HVIP_SHIFT) & mask;
++ unsigned long flags;
++ unsigned long ie;
++ bool ret;
++
++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++ ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK)
++ << VSIP_TO_HVIP_SHIFT) & mask;
++ ret = vcpu->arch.irqs_pending & ie;
++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+
+- return (READ_ONCE(vcpu->arch.irqs_pending) & ie) ? true : false;
++ return ret;
+ }
+
+ void kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu)
+--
+2.53.0
+
drm-amdgpu-vce-fix-integer-overflow-in-image-size.patch
drm-amdgpu-fix-division-by-zero-with-invalid-uvd-dimensions.patch
drm-amdgpu-invoke-pm_genpd_remove-before-freeing-genpd.patch
+risc-v-kvm-serialize-virtual-interrupt-pending-state.patch
+i40e-remove-read-access-to-debugfs-files.patch
+ipv6-ndisc-fix-null-deref-in-accept_untracked_na.patch
+tipc-fix-use-after-free-of-the-discoverer-in-tipc_di.patch
+openvswitch-fix-gso-userspace-truncation-underflow.patch
+fscrypt-avoid-dynamic-allocation-in-fscrypt_get_devi.patch
+exfat-validate-cluster-allocation-bits-of-the-alloca.patch
+bpf-drop-bpf_lsm_getselfattr-from-hook-list.patch
--- /dev/null
+From 8d8ea431d77715f6baa5166db1ce2581be317524 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:16:03 +0300
+Subject: tipc: fix use-after-free of the discoverer in tipc_disc_rcv()
+
+From: Weiming Shi <bestswngs@gmail.com>
+
+commit 1579342d71133da7f00daa02c75cebec7372097b upstream.
+
+bearer_disable() frees b->disc with tipc_disc_delete()'s plain kfree(),
+but tipc_disc_rcv() still dereferences b->disc in RX softirq under
+rcu_read_lock() (tipc_udp_recv -> tipc_rcv -> tipc_disc_rcv).
+
+L2 bearers are safe thanks to the synchronize_net() in
+tipc_disable_l2_media(), but the UDP bearer defers that call to the
+cleanup_bearer() workqueue, so the discoverer is freed with no grace
+period:
+
+ BUG: KASAN: slab-use-after-free in tipc_disc_rcv (net/tipc/discover.c:149)
+ Read of size 8 at addr ffff88802348b728 by task poc_tipc/184
+ <IRQ>
+ tipc_disc_rcv (net/tipc/discover.c:149)
+ tipc_rcv (net/tipc/node.c:2126)
+ tipc_udp_recv (net/tipc/udp_media.c:391)
+ udp_rcv (net/ipv4/udp.c:2643)
+ ip_local_deliver_finish (net/ipv4/ip_input.c:241)
+ </IRQ>
+ Freed by task 181:
+ kfree (mm/slub.c:6565)
+ bearer_disable (net/tipc/bearer.c:418)
+ tipc_nl_bearer_disable (net/tipc/bearer.c:1001)
+
+The bearer is freed with kfree_rcu(); free the discoverer the same way.
+Add an rcu_head to struct tipc_discoverer and free it and its skb from an
+RCU callback.
+
+Because the RCU callback (tipc_disc_free_rcu) lives in module text, a
+call_rcu() that is still pending when the tipc module is unloaded would
+invoke a freed function. Add an rcu_barrier() to tipc_exit() after the
+bearer subsystem has been torn down, so all pending discoverer callbacks
+have run before the module text goes away.
+
+Reachable from an unprivileged user namespace: the TIPCv2 genl family is
+netnsok and its bearer commands have no GENL_ADMIN_PERM. Needs CONFIG_TIPC
+and CONFIG_TIPC_MEDIA_UDP.
+
+Fixes: 25b0b9c4e835 ("tipc: handle collisions of 32-bit node address hash values")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Weiming Shi <bestswngs@gmail.com>
+Reviewed-by: Tung Nguyen <tung.quang.nguyen@est.tech>
+Link: https://patch.msgid.link/20260617135744.3383175-3-bestswngs@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Alexander Martyniuk <alexevgmart@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tipc/core.c | 5 +++++
+ net/tipc/discover.c | 14 ++++++++++++--
+ 2 files changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/net/tipc/core.c b/net/tipc/core.c
+index 434e70eabe0812..1ddecea1df6e91 100644
+--- a/net/tipc/core.c
++++ b/net/tipc/core.c
+@@ -218,6 +218,11 @@ static void __exit tipc_exit(void)
+ unregister_pernet_device(&tipc_net_ops);
+ tipc_unregister_sysctl();
+
++ /* TODO: Wait for all timers that called call_rcu() to finish before
++ * calling rcu_barrier().
++ */
++ rcu_barrier();
++
+ pr_info("Deactivated\n");
+ }
+
+diff --git a/net/tipc/discover.c b/net/tipc/discover.c
+index e8dcdf267c0c3f..835ff27f8ea88c 100644
+--- a/net/tipc/discover.c
++++ b/net/tipc/discover.c
+@@ -58,6 +58,7 @@
+ * @skb: request message to be (repeatedly) sent
+ * @timer: timer governing period between requests
+ * @timer_intv: current interval between requests (in ms)
++ * @rcu: RCU head for deferred freeing
+ */
+ struct tipc_discoverer {
+ u32 bearer_id;
+@@ -69,6 +70,7 @@ struct tipc_discoverer {
+ struct sk_buff *skb;
+ struct timer_list timer;
+ unsigned long timer_intv;
++ struct rcu_head rcu;
+ };
+
+ /**
+@@ -382,6 +384,15 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,
+ return 0;
+ }
+
++static void tipc_disc_free_rcu(struct rcu_head *rp)
++{
++ struct tipc_discoverer *d = container_of(rp, struct tipc_discoverer,
++ rcu);
++
++ kfree_skb(d->skb);
++ kfree(d);
++}
++
+ /**
+ * tipc_disc_delete - destroy object sending periodic link setup requests
+ * @d: ptr to link dest structure
+@@ -389,8 +400,7 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,
+ void tipc_disc_delete(struct tipc_discoverer *d)
+ {
+ del_timer_sync(&d->timer);
+- kfree_skb(d->skb);
+- kfree(d);
++ call_rcu(&d->rcu, tipc_disc_free_rcu);
+ }
+
+ /**
+--
+2.53.0
+
--- /dev/null
+From ea0e1a87bc601b21d6366ff7d41e3132d11c4944 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 20:57:44 +0000
+Subject: bpf: Fix same-register dst/src OOB read and pointer leak in sock_ops
+
+From: Jiayuan Chen <jiayuan.chen@linux.dev>
+
+[ Upstream commit 10f86a2a5c91fc4c4d001960f1c21abe52545ef6 ]
+
+When a BPF sock_ops program accesses ctx fields with dst_reg == src_reg,
+the SOCK_OPS_GET_SK() and SOCK_OPS_GET_FIELD() macros fail to zero the
+destination register in the !fullsock / !locked_tcp_sock path.
+
+Both macros borrow a temporary register to check is_fullsock /
+is_locked_tcp_sock when dst_reg == src_reg, because dst_reg holds the
+ctx pointer. When the check is false (e.g., TCP_NEW_SYN_RECV state with
+a request_sock), dst_reg should be zeroed but is not, leaving the stale
+ctx pointer:
+
+ - SOCK_OPS_GET_SK: dst_reg retains the ctx pointer, passes NULL checks
+ as PTR_TO_SOCKET_OR_NULL, and can be used as a bogus socket pointer,
+ leading to stack-out-of-bounds access in helpers like
+ bpf_skc_to_tcp6_sock().
+
+ - SOCK_OPS_GET_FIELD: dst_reg retains the ctx pointer which the
+ verifier believes is a SCALAR_VALUE, leaking a kernel pointer.
+
+Fix both macros by:
+ - Changing JMP_A(1) to JMP_A(2) in the fullsock path to skip the
+ added instruction.
+ - Adding BPF_MOV64_IMM(si->dst_reg, 0) after the temp register
+ restore in the !fullsock path, placed after the restore because
+ dst_reg == src_reg means we need src_reg intact to read ctx->temp.
+
+Fixes: fd09af010788 ("bpf: sock_ops ctx access may stomp registers in corner case")
+Fixes: 84f44df664e9 ("bpf: sock_ops sk access may stomp registers when dst_reg = src_reg")
+Reported-by: Quan Sun <2022090917019@std.uestc.edu.cn>
+Reported-by: Yinhao Hu <dddddd@hust.edu.cn>
+Reported-by: Kaiyan Mei <M202472210@hust.edu.cn>
+Reported-by: Dongliang Mu <dzm91@hust.edu.cn>
+Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
+Closes: https://lore.kernel.org/bpf/6fe1243e-149b-4d3b-99c7-fcc9e2f75787@std.uestc.edu.cn/T/#u
+Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Acked-by: Martin KaFai Lau <martin.lau@kernel.org>
+Link: https://patch.msgid.link/20260407022720.162151-2-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Jay Wang <wanjay@amazon.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/filter.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/net/core/filter.c b/net/core/filter.c
+index f54e7152d68798..90e396423eb7af 100644
+--- a/net/core/filter.c
++++ b/net/core/filter.c
+@@ -10483,10 +10483,11 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type,
+ si->dst_reg, si->dst_reg, \
+ offsetof(OBJ, OBJ_FIELD)); \
+ if (si->dst_reg == si->src_reg) { \
+- *insn++ = BPF_JMP_A(1); \
++ *insn++ = BPF_JMP_A(2); \
+ *insn++ = BPF_LDX_MEM(BPF_DW, reg, si->src_reg, \
+ offsetof(struct bpf_sock_ops_kern, \
+ temp)); \
++ *insn++ = BPF_MOV64_IMM(si->dst_reg, 0); \
+ } \
+ } while (0)
+
+@@ -10520,10 +10521,11 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type,
+ si->dst_reg, si->src_reg, \
+ offsetof(struct bpf_sock_ops_kern, sk));\
+ if (si->dst_reg == si->src_reg) { \
+- *insn++ = BPF_JMP_A(1); \
++ *insn++ = BPF_JMP_A(2); \
+ *insn++ = BPF_LDX_MEM(BPF_DW, reg, si->src_reg, \
+ offsetof(struct bpf_sock_ops_kern, \
+ temp)); \
++ *insn++ = BPF_MOV64_IMM(si->dst_reg, 0); \
+ } \
+ } while (0)
+
+--
+2.53.0
+
--- /dev/null
+From f3abd7090f53979185c1aa4dcc6a1f5b5d55c098 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 23:33:40 -0700
+Subject: drm/amd/display: Fix DTB DTO updates breaking live pixel rate sources
+
+From: Harry Wentland <harry.wentland@amd.com>
+
+commit 76a2db58e95e328007043f54ac3c7336ccbee440 upstream.
+
+dcn32_update_clocks_update_dtb_dto() and its dcn35 counterpart reprogram
+the DTB DTO of every timing generator in the context whenever the DTBCLK
+reference changes, passing a zeroed pixel rate and never setting
+is_hdmi. Both dccg set_dtbclk_dto() implementations treat a zero pixel
+rate as a disable request. On dcn32 that branch drives PIPE_DTO_SRC_SEL
+to the DP DTO source, so a timing generator actively scanning out an
+HDMI stream has its pixel rate source re-muxed out from under the live
+raster and the OTG stops on the spot. On dcn35 it clears
+DTBCLK_DTO_ENABLE and restores DTBCLK_Pn clock gating, which does the
+same to a live 128b/132b stream.
+
+Two displays where only one runs a 128b/132b link hit this reliably.
+is_dtbclk_required() holds the DTBCLK reference high while both are
+active, and the moment the 128b/132b stream is torn down (compositor
+switch, display disable, hot-unplug) the next safe_to_lower pass drops
+the reference to the lowest DPM level and the DTO walk freezes the
+surviving screen. On Navi31 the DAL mailbox then goes deaf on the
+DISPCLK hard-min that follows the walk in dcn32_update_clocks(),
+stranding both SMU mailboxes until reboot.
+
+Set is_hdmi for HDMI and DVI signals so the disable path leaves the
+pixel rate source selection on the HDMI path, and pass the real pixel
+rate for 128b/132b streams so a reference change rescales their DTO
+instead of disabling it.
+
+Fixes: 128c1ca0303f ("drm/amd/display: Update DTBCLK for DCN32")
+Fixes: 8774029f76b9 ("drm/amd/display: Add DCN35 CLK_MGR")
+Signed-off-by: Harry Wentland <harry.wentland@amd.com>
+Reviewed-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
+Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+[ mschwartz: dcn32 and dcn35 clk_mgr hunks only. The rest is HDMI FRL
+ enablement, absent before 7.2, so the FRL conditions and the
+ req_audio_dtbclk_khz assignment they guard are dropped and the
+ FRL-centric changelog is rewritten. Added the pipe_ctx->stream check
+ the new dereferences need. ]
+Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c | 9 ++++++++-
+ .../gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 9 ++++++++-
+ 2 files changed, 16 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+index 084994c650c4c9..285689d7ecc4ea 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+@@ -276,13 +276,20 @@ static void dcn32_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
+ struct dtbclk_dto_params dto_params = {0};
+
+ /* use mask to program DTO once per tg */
+- if (pipe_ctx->stream_res.tg &&
++ if (pipe_ctx->stream && pipe_ctx->stream_res.tg &&
+ !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) {
+ tg_mask |= (1 << pipe_ctx->stream_res.tg->inst);
+
+ dto_params.otg_inst = pipe_ctx->stream_res.tg->inst;
+ dto_params.ref_dtbclk_khz = ref_dtbclk_khz;
+
++ if (dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))
++ dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
++
++ if (dc_is_hdmi_signal(pipe_ctx->stream->signal) ||
++ dc_is_dvi_signal(pipe_ctx->stream->signal))
++ dto_params.is_hdmi = true;
++
+ dccg->funcs->set_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ //dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
+index 33ee7e81b1b939..05e4dbc7fb8398 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
+@@ -247,13 +247,20 @@ static void dcn35_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
+ struct dtbclk_dto_params dto_params = {0};
+
+ /* use mask to program DTO once per tg */
+- if (pipe_ctx->stream_res.tg &&
++ if (pipe_ctx->stream && pipe_ctx->stream_res.tg &&
+ !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) {
+ tg_mask |= (1 << pipe_ctx->stream_res.tg->inst);
+
+ dto_params.otg_inst = pipe_ctx->stream_res.tg->inst;
+ dto_params.ref_dtbclk_khz = ref_dtbclk_khz;
+
++ if (dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))
++ dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
++
++ if (dc_is_hdmi_signal(pipe_ctx->stream->signal) ||
++ dc_is_dvi_signal(pipe_ctx->stream->signal))
++ dto_params.is_hdmi = true;
++
+ dccg->funcs->set_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ //dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ }
+--
+2.53.0
+
--- /dev/null
+From c370485aebc4396b217143cdbeecdc4bc06b5c51 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 08:21:27 -0700
+Subject: fscrypt: Avoid dynamic allocation in fscrypt_get_devices()
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 6fe4e4b8259e1330945b5f3c9476e08473b8e0e8 upstream.
+
+When a blk_crypto_key starts being used or is evicted, fs/crypto/ calls
+fscrypt_get_devices() to get the filesystem's list of block devices,
+then iterates over them and calls blk_crypto_config_supported(),
+blk_crypto_start_using_key(), or blk_crypto_evict_key() on each one.
+
+Currently, the block device pointers are placed in a dynamically
+allocated array. This dynamic allocation is problematic because:
+
+- It can fail, especially at the fscrypt_destroy_inline_crypt_key() call
+ site when it's invoked for inode eviction under direct reclaim.
+
+- fscrypt_destroy_inline_crypt_key() doesn't handle the failure. It
+ just zeroizes and frees the blk_crypto_key without calling
+ blk_crypto_evict_key(). That causes a use-after-free.
+
+For now, let's fix this in the straightforward and easily-backportable
+way by switching to an on-stack array. Currently the fscrypt
+multi-device functionality is used only by f2fs, which has a hardcoded
+limit of 8 block devices. An on-stack array works fine for that.
+
+(Of course, this solution won't scale up to large number of block
+devices. For that we'd need a different solution, like moving the block
+device iteration into the filesystem. Or in the case of btrfs, which
+will only support blk-crypto-fallback, we should make it just call
+blk-crypto-fallback directly, so the block devices won't be needed.)
+
+Fixes: 22e9947a4b2b ("fscrypt: stop holding extra request_queue references")
+Cc: stable@vger.kernel.org
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Closes: https://sashiko.dev/#/patchset/20260713023708.9245-1-ebiggers%40kernel.org
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Link: https://patch.msgid.link/20260719055602.78828-1-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/crypto/inline_crypt.c | 57 ++++++++++++++--------------------------
+ fs/f2fs/super.c | 25 ++++++++++--------
+ include/linux/fscrypt.h | 18 +++++++------
+ 3 files changed, 44 insertions(+), 56 deletions(-)
+
+diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
+index 4b1f10f1cbd85e..0a216d20e6950d 100644
+--- a/fs/crypto/inline_crypt.c
++++ b/fs/crypto/inline_crypt.c
+@@ -21,22 +21,14 @@
+
+ #include "fscrypt_private.h"
+
+-static struct block_device **fscrypt_get_devices(struct super_block *sb,
+- unsigned int *num_devs)
++static unsigned int
++fscrypt_get_devices(struct super_block *sb,
++ struct block_device *devs[FSCRYPT_MAX_DEVICES])
+ {
+- struct block_device **devs;
+-
+- if (sb->s_cop->get_devices) {
+- devs = sb->s_cop->get_devices(sb, num_devs);
+- if (devs)
+- return devs;
+- }
+- devs = kmalloc(sizeof(*devs), GFP_KERNEL);
+- if (!devs)
+- return ERR_PTR(-ENOMEM);
++ if (sb->s_cop->get_devices)
++ return sb->s_cop->get_devices(sb, devs);
+ devs[0] = sb->s_bdev;
+- *num_devs = 1;
+- return devs;
++ return 1;
+ }
+
+ static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_inode_info *ci)
+@@ -94,7 +86,7 @@ int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci)
+ const struct inode *inode = ci->ci_inode;
+ struct super_block *sb = inode->i_sb;
+ struct blk_crypto_config crypto_cfg;
+- struct block_device **devs;
++ struct block_device *devs[FSCRYPT_MAX_DEVICES];
+ unsigned int num_devs;
+ unsigned int i;
+
+@@ -131,20 +123,15 @@ int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci)
+ crypto_cfg.data_unit_size = 1U << ci->ci_data_unit_bits;
+ crypto_cfg.dun_bytes = fscrypt_get_dun_bytes(ci);
+
+- devs = fscrypt_get_devices(sb, &num_devs);
+- if (IS_ERR(devs))
+- return PTR_ERR(devs);
+-
++ num_devs = fscrypt_get_devices(sb, devs);
+ for (i = 0; i < num_devs; i++) {
+ if (!blk_crypto_config_supported(devs[i], &crypto_cfg))
+- goto out_free_devs;
++ return 0;
+ }
+
+ fscrypt_log_blk_crypto_impl(ci->ci_mode, devs, num_devs, &crypto_cfg);
+
+ ci->ci_inlinecrypt = true;
+-out_free_devs:
+- kfree(devs);
+
+ return 0;
+ }
+@@ -157,7 +144,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
+ struct super_block *sb = inode->i_sb;
+ enum blk_crypto_mode_num crypto_mode = ci->ci_mode->blk_crypto_mode;
+ struct blk_crypto_key *blk_key;
+- struct block_device **devs;
++ struct block_device *devs[FSCRYPT_MAX_DEVICES];
+ unsigned int num_devs;
+ unsigned int i;
+ int err;
+@@ -175,17 +162,12 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
+ }
+
+ /* Start using blk-crypto on all the filesystem's block devices. */
+- devs = fscrypt_get_devices(sb, &num_devs);
+- if (IS_ERR(devs)) {
+- err = PTR_ERR(devs);
+- goto fail;
+- }
++ num_devs = fscrypt_get_devices(sb, devs);
+ for (i = 0; i < num_devs; i++) {
+ err = blk_crypto_start_using_key(devs[i], blk_key);
+ if (err)
+ break;
+ }
+- kfree(devs);
+ if (err) {
+ fscrypt_err(inode, "error %d starting to use blk-crypto", err);
+ goto fail;
+@@ -203,20 +185,21 @@ void fscrypt_destroy_inline_crypt_key(struct super_block *sb,
+ struct fscrypt_prepared_key *prep_key)
+ {
+ struct blk_crypto_key *blk_key = prep_key->blk_key;
+- struct block_device **devs;
++ struct block_device *devs[FSCRYPT_MAX_DEVICES];
+ unsigned int num_devs;
+ unsigned int i;
+
+ if (!blk_key)
+ return;
+
+- /* Evict the key from all the filesystem's block devices. */
+- devs = fscrypt_get_devices(sb, &num_devs);
+- if (!IS_ERR(devs)) {
+- for (i = 0; i < num_devs; i++)
+- blk_crypto_evict_key(devs[i], blk_key);
+- kfree(devs);
+- }
++ /*
++ * Evict the key from all the filesystem's block devices.
++ * This *must* be done before the key is freed.
++ */
++ num_devs = fscrypt_get_devices(sb, devs);
++ for (i = 0; i < num_devs; i++)
++ blk_crypto_evict_key(devs[i], blk_key);
++
+ kfree_sensitive(blk_key);
+ }
+
+diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
+index 1bce35d6f4e253..8ceffecf28c80c 100644
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -3282,24 +3282,27 @@ static bool f2fs_has_stable_inodes(struct super_block *sb)
+ return true;
+ }
+
+-static struct block_device **f2fs_get_devices(struct super_block *sb,
+- unsigned int *num_devs)
++static unsigned int
++f2fs_get_devices(struct super_block *sb,
++ struct block_device *devs[FSCRYPT_MAX_DEVICES])
+ {
+ struct f2fs_sb_info *sbi = F2FS_SB(sb);
+- struct block_device **devs;
++ int ndevs;
+ int i;
+
+- if (!f2fs_is_multi_device(sbi))
+- return NULL;
++ static_assert(MAX_DEVICES <= FSCRYPT_MAX_DEVICES);
+
+- devs = kmalloc_array(sbi->s_ndevs, sizeof(*devs), GFP_KERNEL);
+- if (!devs)
+- return ERR_PTR(-ENOMEM);
++ if (!f2fs_is_multi_device(sbi)) {
++ devs[0] = sb->s_bdev;
++ return 1;
++ }
++ ndevs = sbi->s_ndevs;
++ if (WARN_ON_ONCE(ndevs > FSCRYPT_MAX_DEVICES))
++ ndevs = FSCRYPT_MAX_DEVICES;
+
+- for (i = 0; i < sbi->s_ndevs; i++)
++ for (i = 0; i < ndevs; i++)
+ devs[i] = FDEV(i).bdev;
+- *num_devs = sbi->s_ndevs;
+- return devs;
++ return ndevs;
+ }
+
+ static const struct fscrypt_operations f2fs_cryptops = {
+diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
+index 772f822dc6b82e..3cb1e449d8cfc1 100644
+--- a/include/linux/fscrypt.h
++++ b/include/linux/fscrypt.h
+@@ -57,6 +57,9 @@ struct fscrypt_name {
+ /* Maximum value for the third parameter of fscrypt_operations.set_context(). */
+ #define FSCRYPT_SET_CONTEXT_MAX_SIZE 40
+
++/* Maximum supported number of block devices per filesystem */
++#define FSCRYPT_MAX_DEVICES 8
++
+ #ifdef CONFIG_FS_ENCRYPTION
+
+ /* Crypto operations for filesystems */
+@@ -175,21 +178,20 @@ struct fscrypt_operations {
+ bool (*has_stable_inodes)(struct super_block *sb);
+
+ /*
+- * Return an array of pointers to the block devices to which the
+- * filesystem may write encrypted file contents, NULL if the filesystem
+- * only has a single such block device, or an ERR_PTR() on error.
++ * Retrieve the list of block devices to which the filesystem may write
++ * encrypted file contents.
+ *
+- * On successful non-NULL return, *num_devs is set to the number of
+- * devices in the returned array. The caller must free the returned
+- * array using kfree().
++ * This writes the block_device pointers to @devs and returns the count
++ * (between 1 and FSCRYPT_MAX_DEVICES inclusively).
+ *
+ * If the filesystem can use multiple block devices (other than block
+ * devices that aren't used for encrypted file contents, such as
+ * external journal devices), and wants to support inline encryption,
+ * then it must implement this function. Otherwise it's not needed.
+ */
+- struct block_device **(*get_devices)(struct super_block *sb,
+- unsigned int *num_devs);
++ unsigned int (*get_devices)(
++ struct super_block *sb,
++ struct block_device *devs[FSCRYPT_MAX_DEVICES]);
+ };
+
+ int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags);
+--
+2.53.0
+
--- /dev/null
+From 08992b716aca4b7af5b7cba422443014751e8aca Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 14:21:22 -0700
+Subject: gve: fix Rx queue stall on alloc failure
+
+From: Eddie Phillips <eddiephillips@google.com>
+
+commit b65352a1bac64442ad95e64f385b40ccb9f1b0db upstream.
+
+When the system is under extreme memory pressure, page allocations can
+fail during the Rx buffer refill loop. If the number of buffers posted
+to hardware falls below a critical low threshold and the refill loop
+exits due to allocation failures, the queue can stall:
+
+1. The device drops incoming packets because there are no descriptors.
+2. Since no packets are processed, no Rx completions are generated.
+3. Because no completions occur, NAPI is never scheduled, preventing
+ the refill loop from running again even after memory is freed.
+
+This results in a permanent queue stall.
+
+Resolve this by introducing a starvation recovery timer for each Rx queue.
+If the number of buffers posted to hardware falls below a critical low
+threshold, start a timer to periodically reschedule NAPI. Once NAPI runs
+and successfully refills the queue above the threshold, the timer is
+not rescheduled.
+
+The threshold is set to 32 because a single maximum-sized Receive Segment
+Coalescing (RSC) packet can consume up to 19 descriptors in the Rx path.
+Lower thresholds (such as 8 or 16) would be insufficient to process a
+complete maximum-sized RSC packet, risking packet drops or unexpected
+hardware behavior under memory pressure. Setting the threshold to 32
+guarantees a safe margin to handle at least one full RSC packet.
+
+Cc: stable@vger.kernel.org
+Fixes: 9b8dd5e5ea48 ("gve: DQO: Add RX path")
+Reviewed-by: Jordan Rhee <jordanrhee@google.com>
+Signed-off-by: Eddie Phillips <eddiephillips@google.com>
+Signed-off-by: Harshitha Ramamurthy <hramamurthy@google.com>
+Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
+Link: https://patch.msgid.link/20260709211906.3322883-1-hramamurthy@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/google/gve/gve.h | 3 ++
+ drivers/net/ethernet/google/gve/gve_rx_dqo.c | 36 ++++++++++++++++++++
+ 2 files changed, 39 insertions(+)
+
+diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h
+index 8ddd366d9fde54..e19d722e8e9a18 100644
+--- a/drivers/net/ethernet/google/gve/gve.h
++++ b/drivers/net/ethernet/google/gve/gve.h
+@@ -12,6 +12,7 @@
+ #include <linux/ethtool_netlink.h>
+ #include <linux/netdevice.h>
+ #include <linux/pci.h>
++#include <linux/timer.h>
+ #include <linux/u64_stats_sync.h>
+ #include <net/xdp.h>
+
+@@ -38,6 +39,7 @@
+
+ /* Interval to schedule a stats report update, 20000ms. */
+ #define GVE_STATS_REPORT_TIMER_PERIOD 20000
++#define GVE_RX_NAPI_RESCHED_MS 20 /* msecs */
+
+ /* Numbers of NIC tx/rx stats in stats report. */
+ #define NIC_TX_STATS_REPORT_NUM 0
+@@ -311,6 +313,7 @@ struct gve_rx_ring {
+ struct xdp_rxq_info xsk_rxq;
+ struct xsk_buff_pool *xsk_pool;
+ struct page_frag_cache page_cache; /* Page cache to allocate XDP frames */
++ struct timer_list starvation_timer; /* for queue starvation recovery */
+ };
+
+ /* A TX desc ring entry */
+diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+index 1154c1d8f66f05..2f7f31e4797cd2 100644
+--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c
++++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+@@ -199,6 +199,16 @@ static int gve_alloc_page_dqo(struct gve_rx_ring *rx,
+ return 0;
+ }
+
++static void gve_rx_starvation_timer(struct timer_list *t)
++{
++ struct gve_rx_ring *rx = from_timer(rx, t, starvation_timer);
++ struct gve_priv *priv = rx->gve;
++ struct gve_notify_block *block;
++
++ block = &priv->ntfy_blocks[rx->ntfy_id];
++ napi_schedule(&block->napi);
++}
++
+ static void gve_rx_free_hdr_bufs(struct gve_priv *priv, struct gve_rx_ring *rx)
+ {
+ struct device *hdev = &priv->pdev->dev;
+@@ -290,10 +300,13 @@ static void gve_rx_reset_ring_dqo(struct gve_priv *priv, int idx)
+ void gve_rx_stop_ring_dqo(struct gve_priv *priv, int idx)
+ {
+ int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx);
++ struct gve_rx_ring *rx = &priv->rx[idx];
+
+ if (!gve_rx_was_added_to_block(priv, idx))
+ return;
+
++ timer_shutdown_sync(&rx->starvation_timer);
++
+ gve_remove_napi(priv, ntfy_idx);
+ gve_rx_remove_from_block(priv, idx);
+ gve_rx_reset_ring_dqo(priv, idx);
+@@ -371,8 +384,10 @@ static int gve_rx_alloc_hdr_bufs(struct gve_priv *priv, struct gve_rx_ring *rx,
+ void gve_rx_start_ring_dqo(struct gve_priv *priv, int idx)
+ {
+ int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx);
++ struct gve_rx_ring *rx = &priv->rx[idx];
+
+ gve_rx_add_to_block(priv, idx);
++ timer_setup(&rx->starvation_timer, gve_rx_starvation_timer, 0);
+ gve_add_napi(priv, ntfy_idx, gve_napi_poll_dqo);
+ }
+
+@@ -511,6 +526,7 @@ void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx)
+ struct gve_rx_compl_queue_dqo *complq = &rx->dqo.complq;
+ struct gve_rx_buf_queue_dqo *bufq = &rx->dqo.bufq;
+ struct gve_priv *priv = rx->gve;
++ u32 num_bufs_avail_to_hw;
+ u32 num_avail_slots;
+ u32 num_full_slots;
+ u32 num_posted = 0;
+@@ -555,6 +571,26 @@ void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx)
+ }
+
+ rx->fill_cnt += num_posted;
++
++ /* If the queue has fewer than GVE_RX_BUF_THRESH_DQO descriptors
++ * visible to the hardware, the hardware is in danger of starving
++ * and cannot trigger interrupts.
++ *
++ * We use a threshold of 32 because a single maximum-sized RSC
++ * packet can consume up to 19 descriptors in the Rx path. Lower
++ * thresholds (e.g., 8 or 16) would be unsafe as they could cause
++ * the device to drop/stall on a maximum-sized RSC packet.
++ *
++ * Start the timer to periodically reschedule NAPI and recover.
++ */
++ num_bufs_avail_to_hw =
++ ((bufq->tail & ~(GVE_RX_BUF_THRESH_DQO - 1)) -
++ bufq->head) & bufq->mask;
++
++ if (num_bufs_avail_to_hw < GVE_RX_BUF_THRESH_DQO) {
++ mod_timer(&rx->starvation_timer,
++ jiffies + msecs_to_jiffies(GVE_RX_NAPI_RESCHED_MS));
++ }
+ }
+
+ static void gve_try_recycle_buf(struct gve_priv *priv, struct gve_rx_ring *rx,
+--
+2.53.0
+
--- /dev/null
+From 81d8d44182357233d4b17914d1436ddcef521cd0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Jul 2026 20:45:51 +0800
+Subject: io_uring/rw: fix missing ERESTARTSYS conversion in read paths
+
+From: Yitang Yang <yi1tang.yang@gmail.com>
+
+commit ab05caca123c6d0b41850b7c05b246e4dca4a770 upstream.
+
+Both read and write may receive internal restart error codes from
+the filesystem layer and should be converted to -EINTR. However,
+when multishot read support was added, the error code normalization
+was lost for both io_read() and io_read_mshot().
+
+Extract the conversion into io_fixup_restart_res() and apply it
+in all three locations: io_rw_done(), io_read(), and io_read_mshot().
+
+Fixes: a08d195b586a ("io_uring/rw: split io_read() into a helper")
+Cc: stable@vger.kernel.org
+Signed-off-by: Yitang Yang <yi1tang.yang@gmail.com>
+Link: https://patch.msgid.link/20260722124551.130563-1-yi1tang.yang@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ io_uring/rw.c | 42 +++++++++++++++++++++++++-----------------
+ 1 file changed, 25 insertions(+), 17 deletions(-)
+
+diff --git a/io_uring/rw.c b/io_uring/rw.c
+index a744cb5d235a6a..a74664c4a05efe 100644
+--- a/io_uring/rw.c
++++ b/io_uring/rw.c
+@@ -560,6 +560,24 @@ static void io_complete_rw_iopoll(struct kiocb *kiocb, long res)
+ smp_store_release(&req->iopoll_completed, 1);
+ }
+
++static inline ssize_t io_fixup_restart_res(ssize_t ret)
++{
++ switch (ret) {
++ case -ERESTARTSYS:
++ case -ERESTARTNOINTR:
++ case -ERESTARTNOHAND:
++ case -ERESTART_RESTARTBLOCK:
++ /*
++ * We can't just restart the syscall, since previously
++ * submitted sqes may already be in progress. Just fail
++ * this IO with EINTR.
++ */
++ return -EINTR;
++ default:
++ return ret;
++ }
++}
++
+ static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret)
+ {
+ /* IO was queued async, completion will happen later */
+@@ -567,21 +585,8 @@ static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret)
+ return;
+
+ /* transform internal restart error codes */
+- if (unlikely(ret < 0)) {
+- switch (ret) {
+- case -ERESTARTSYS:
+- case -ERESTARTNOINTR:
+- case -ERESTARTNOHAND:
+- case -ERESTART_RESTARTBLOCK:
+- /*
+- * We can't just restart the syscall, since previously
+- * submitted sqes may already be in progress. Just fail
+- * this IO with EINTR.
+- */
+- ret = -EINTR;
+- break;
+- }
+- }
++ if (unlikely(ret < 0))
++ ret = io_fixup_restart_res(ret);
+
+ INDIRECT_CALL_2(kiocb->ki_complete, io_complete_rw_iopoll,
+ io_complete_rw, kiocb, ret);
+@@ -961,7 +966,8 @@ int io_read(struct io_kiocb *req, unsigned int issue_flags)
+
+ if (req->flags & REQ_F_BUFFERS_COMMIT)
+ io_kbuf_recycle(req, sel.buf_list, issue_flags);
+- return ret;
++
++ return io_fixup_restart_res(ret);
+ }
+
+ int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
+@@ -995,8 +1001,10 @@ int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
+ return -EAGAIN;
+ } else if (ret <= 0) {
+ io_kbuf_recycle(req, sel.buf_list, issue_flags);
+- if (ret < 0)
++ if (ret < 0) {
++ ret = io_fixup_restart_res(ret);
+ req_set_fail(req);
++ }
+ } else if (!(req->flags & REQ_F_APOLL_MULTISHOT)) {
+ cflags = io_put_kbuf(req, ret, sel.buf_list);
+ } else {
+--
+2.53.0
+
--- /dev/null
+From d61d1255f5ee090b6c70083ca1d9b0029c81c41f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:26 +0800
+Subject: ksmbd: bound DACL dedup walk to copied ACEs
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+commit 58d97fcd0bf1aee694e244cc28635b9df95b543b upstream.
+
+set_ntacl_dacl() can stop copying ACEs before consuming the full input
+DACL when size accounting overflows.
+
+When that happens, num_aces reflects only the ACEs that were actually
+copied into the output DACL, but set_posix_acl_entries_dacl() still
+receives nt_num_aces and uses it to walk the existing ACE array during
+dedup.
+
+That makes the dedup walk scan past the copied ACE array and inspect
+buffer tail that does not contain valid ACEs.
+
+Split the two meanings currently carried by the NT ACE count. Pass the
+number of copied NT ACEs to bound the dedup walk, and preserve the
+original "input DACL had NT ACEs" state separately for the
+Everyone/default ACL fallback.
+
+This keeps the dedup walk aligned with the ACEs that are actually
+present in the rebuilt DACL.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index ca0e4aab6dd87f..b0677e095c3292 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -595,7 +595,8 @@ static void parse_dacl(struct mnt_idmap *idmap,
+ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ struct smb_ace *pndace,
+ struct smb_fattr *fattr, u16 *num_aces,
+- u16 *size, u32 nt_aces_num)
++ u16 *size, u16 existing_nt_aces,
++ bool had_nt_aces)
+ {
+ struct posix_acl_entry *pace;
+ struct smb_sid *sid;
+@@ -627,14 +628,14 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+
+ gid = posix_acl_gid_translate(idmap, pace);
+ id_to_sid(gid, SIDUNIX_GROUP, sid);
+- } else if (pace->e_tag == ACL_OTHER && !nt_aces_num) {
++ } else if (pace->e_tag == ACL_OTHER && !had_nt_aces) {
+ smb_copy_sid(sid, &sid_everyone);
+ } else {
+ kfree(sid);
+ continue;
+ }
+ ntace = pndace;
+- for (j = 0; j < nt_aces_num; j++) {
++ for (j = 0; j < existing_nt_aces; j++) {
+ if (ntace->sid.sub_auth[ntace->sid.num_subauth - 1] ==
+ sid->sub_auth[sid->num_subauth - 1])
+ goto pass_same_sid;
+@@ -678,7 +679,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ kfree(sid);
+ }
+
+- if (nt_aces_num)
++ if (had_nt_aces)
+ return;
+
+ posix_default_acl:
+@@ -732,6 +733,7 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ {
+ struct smb_ace *ntace, *pndace;
+ u16 nt_num_aces = le16_to_cpu(nt_dacl->num_aces), num_aces = 0;
++ u16 copied_nt_aces;
+ unsigned short size = 0;
+ int i;
+
+@@ -765,8 +767,10 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ }
+ }
+
++ copied_nt_aces = num_aces;
+ set_posix_acl_entries_dacl(idmap, pndace, fattr,
+- &num_aces, &size, nt_num_aces);
++ &num_aces, &size, copied_nt_aces,
++ nt_num_aces != 0);
+ pndacl->num_aces = cpu_to_le16(num_aces);
+ pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
+ }
+@@ -784,7 +788,7 @@ static void set_mode_dacl(struct mnt_idmap *idmap,
+
+ if (fattr->cf_acls) {
+ set_posix_acl_entries_dacl(idmap, pndace, fattr,
+- &num_aces, &size, num_aces);
++ &num_aces, &size, num_aces, false);
+ goto out;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 1bab68be16153e851ad5a153a0806fd3133a5934 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:24 +0800
+Subject: ksmbd: restore DACL size on check_add_overflow() to avoid malformed
+ ACL
+
+From: Wentao Guan <guanwentao@uniontech.com>
+
+commit bbf0a8e931204ecdab494a88d43b0a24a04285c5 upstream.
+
+check_add_overflow() unconditionally writes the truncated sum into *d
+even on overflow, per its contract in include/linux/overflow.h.
+The four check_add_overflow() guards in set_posix_acl_entries_dacl()
+and set_ntacl_dacl() break out of the ACE-building loops on overflow,
+but the truncated *size is then consumed downstream at the end of
+set_ntacl_dacl():
+
+ pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
+
+This produces an on-wire NT ACL whose pndacl->size under-reports the
+bytes actually written by the preceding fill_ace_for_sid()/memcpy()
+calls, yielding a malformed ACL that can trigger out-of-bounds reads
+when re-parsed by clients or ksmbd itself.
+
+Restore *size to its pre-addition value on each overflow branch (via
+`*size -= ace_sz` / `size -= nt_ace_size`) so that after the break,
+*size once again holds the cumulative size of the successfully-written
+ACEs. The committed ACL is then truncated-but-self-consistent rather
+than malformed.
+
+The ksmbd DACL builders are the only check_add_overflow() sites found
+where an overflow path breaks out of a loop and the destination value
+is consumed afterward. The other nearby break-style cases either
+return -EINVAL on overflow (transport_ipc.c) or break without
+consuming the overflowed destination value afterward (buildid.c).
+
+Fixes: 299f962c0b02 ("ksmbd: use check_add_overflow() to prevent u16 DACL size overflow")
+Assisted-by: atomcode:glm-5.2
+Assisted-by: Codex:gpt-5.5
+Cc: stable@vger.kernel.org
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index 173469d112f101..ca0e4aab6dd87f 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -649,6 +649,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags,
+ pace->e_perm, 0777);
+ if (check_add_overflow(*size, ace_sz, size)) {
++ *size -= ace_sz;
+ kfree(sid);
+ break;
+ }
+@@ -663,6 +664,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED,
+ 0x03, pace->e_perm, 0777);
+ if (check_add_overflow(*size, ace_sz, size)) {
++ *size -= ace_sz;
+ kfree(sid);
+ break;
+ }
+@@ -708,6 +710,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b,
+ pace->e_perm, 0777);
+ if (check_add_overflow(*size, ace_sz, size)) {
++ *size -= ace_sz;
+ kfree(sid);
+ break;
+ }
+@@ -750,8 +753,10 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ goto next_ace;
+
+ memcpy((char *)pndace + size, ntace, nt_ace_size);
+- if (check_add_overflow(size, nt_ace_size, &size))
++ if (check_add_overflow(size, nt_ace_size, &size)) {
++ size -= nt_ace_size;
+ break;
++ }
+ num_aces++;
+
+ next_ace:
+--
+2.53.0
+
--- /dev/null
+From 113d16c1d1d164a09d9bbf13ec5161040bd6153f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:29 +0800
+Subject: ksmbd: validate ACE size against SID sub-authorities
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+commit 5152c6d49e3fd4e9f2e857c57527aead752f1f87 upstream.
+
+set_ntacl_dacl() validates sid.num_subauth before copying an ACE, but
+does not verify that the declared ACE size contains all sub-authorities
+described by that field. An undersized ACE can therefore be copied
+and later make the POSIX ACL deduplication walk inspect data beyond
+the copied ACE boundary.
+
+The existing initial bound check is also too small. It only ensures
+that the ACE size field is accessible before set_ntacl_dacl() reads
+sid.num_subauth farther into the input buffer.
+
+Require enough input for the fixed SID header before accessing
+num_subauth, reject ACEs smaller than that header, and skip ACEs
+whose declared size cannot contain the complete SID. This makes the
+validation consistent with the other ACE walk paths.
+
+Reported-by: LocalHost <localhost.detect@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index b0677e095c3292..d3d0a22620f96d 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -743,15 +743,22 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ for (i = 0; i < nt_num_aces; i++) {
+ unsigned short nt_ace_size;
+
+- if (offsetof(struct smb_ace, access_req) > aces_size)
++ if (aces_size < offsetof(struct smb_ace, sid) +
++ CIFS_SID_BASE_SIZE)
+ break;
+
+ nt_ace_size = le16_to_cpu(ntace->size);
+- if (nt_ace_size > aces_size)
++ if (nt_ace_size > aces_size ||
++ nt_ace_size < offsetof(struct smb_ace, sid) +
++ CIFS_SID_BASE_SIZE)
+ break;
+
+ if (ntace->sid.num_subauth == 0 ||
+- ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES)
++ ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
++ nt_ace_size < offsetof(struct smb_ace, sid) +
++ CIFS_SID_BASE_SIZE +
++ sizeof(__le32) *
++ ntace->sid.num_subauth)
+ goto next_ace;
+
+ memcpy((char *)pndace + size, ntace, nt_ace_size);
+--
+2.53.0
+
--- /dev/null
+From 2b3dbbd54bbfe19417d782eecbad72514b3244f0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:22 +0800
+Subject: ksmbd: validate num_subauth when copying ACE in set_ntacl_dacl
+
+From: Haofeng Li <lihaofeng@kylinos.cn>
+
+commit 47f0b34f6bc98ed85bfdc293e8f3e432ec24958d upstream.
+
+set_ntacl_dacl() copies each ACE from the attacker-controlled stored
+security descriptor verbatim into the response DACL without checking
+sid.num_subauth. The ACE bytes (including an unchecked num_subauth)
+originate from an authenticated SMB2_SET_INFO(SecInfo=DACL) that is
+stored raw via ksmbd_vfs_set_sd_xattr(); parse_dacl() rejects a bad ACE
+with `break` rather than an error, so parse_sec_desc() still returns
+success and the malformed SD reaches the xattr intact.
+
+On a subsequent SMB2_QUERY_INFO(SecInfo=DACL) for an inode carrying a
+POSIX access ACL, build_sec_desc() -> set_ntacl_dacl() ->
+set_posix_acl_entries_dacl() walks the copied ACEs and reads
+
+ ntace->sid.sub_auth[ntace->sid.num_subauth - 1]
+
+with num_subauth taken straight from the stored SD. Since sub_auth[]
+is fixed at SID_MAX_SUB_AUTHORITIES (15), a crafted num_subauth (e.g.
+255) drives an out-of-bounds heap read of ~1 KB with an offset fully
+controlled by an authenticated client.
+
+The sibling functions already gate this field:
+ parse_dacl() -- num_subauth == 0 || > SID_MAX_SUB_AUTHORITIES
+ parse_sid() -- num_subauth > SID_MAX_SUB_AUTHORITIES
+ smb_copy_sid() -- min_t(u8, num_subauth, SID_MAX_SUB_AUTHORITIES)
+set_ntacl_dacl() is the lone inconsistent path that omits the check.
+
+Add the same num_subauth validation in set_ntacl_dacl() before copying
+the ACE, matching the gate already enforced by parse_dacl().
+
+Signed-off-by: Haofeng Li <lihaofeng@kylinos.cn>
+Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
+Suggested-by: Namjae Jeon <linkinjeon@kernel.org>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index b09bc8d9389a2a..173469d112f101 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -745,12 +745,18 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ if (nt_ace_size > aces_size)
+ break;
+
++ if (ntace->sid.num_subauth == 0 ||
++ ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES)
++ goto next_ace;
++
+ memcpy((char *)pndace + size, ntace, nt_ace_size);
+ if (check_add_overflow(size, nt_ace_size, &size))
+ break;
++ num_aces++;
++
++next_ace:
+ aces_size -= nt_ace_size;
+ ntace = (struct smb_ace *)((char *)ntace + nt_ace_size);
+- num_aces++;
+ }
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 7883170aa7261bc2f85784d1a61623c6463a888e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:14:26 +0800
+Subject: net: pcs: xpcs: fix SGMII state reading
+
+From: Coia Prant <coiaprant@gmail.com>
+
+commit def9a4745e105145133e442dd8a1c126caf0f553 upstream.
+
+Commit 2a22b7ae2fa3 ("net: pcs: xpcs: adapt Wangxun NICs for SGMII mode")
+added a path in xpcs_get_state_c37_sgmii() that reads speed/duplex from
+BMCR after AN completes. However, BMCR does not reflect the negotiated
+result on the hardware where this has been tested:
+
+- On RK3568 (MAC side SGMII), BMCR returns a fixed hardware reset value
+- Wangxun engineer Jiawen Wu confirmed that on their side, "BMCR looks
+ like it only wants to be return as 0" [0]
+
+The correct information is available in CL37_ANSGM_STS, which contains
+the actual link status and negotiated speed/duplex.
+
+This bug was previously masked by phylink core, which overrides the PCS
+link state with the PHY state when a PHY is present:
+
+ /* If we have a phy, the "up" state is the union of both the
+ * PHY and the MAC
+ */
+ if (phy)
+ link_state.link &= pl->phy_state.link;
+
+Thus, when the link is down, the PHY's link_down state is applied on top
+of whatever the PCS reports, hiding the broken PCS state reading path.
+
+Modify xpcs_get_state_c37_sgmii() to:
+1. Read link state from CL37_ANSGM_STS
+2. If link is up, report speed/duplex from CL37_ANSGM_STS
+3. Remove the broken BMCR reading path entirely
+
+Also properly set state->an_complete to reflect the AN completion status,
+and clear CL37_ANCMPLT_INTR when link is down to avoid stale state.
+
+[0] https://lore.kernel.org/all/000c01dd1593$2ac0b0f0$804212d0$@trustnetic.com/
+
+Fixes: 2a22b7ae2fa3 ("net: pcs: xpcs: adapt Wangxun NICs for SGMII mode")
+Cc: stable@vger.kernel.org
+Tested-by: Jiawen Wu <jiawenwu@trustnetic.com>
+Signed-off-by: Coia Prant <coiaprant@gmail.com>
+Tested-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Link: https://patch.msgid.link/20260717074324.3250043-2-coiaprant@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/pcs/pcs-xpcs.c | 32 +++++++-------------------------
+ 1 file changed, 7 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
+index 82463f9d50c85c..0152f820c1bbe5 100644
+--- a/drivers/net/pcs/pcs-xpcs.c
++++ b/drivers/net/pcs/pcs-xpcs.c
+@@ -973,6 +973,7 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
+
+ /* Reset link_state */
+ state->link = false;
++ state->an_complete = false;
+ state->speed = SPEED_UNKNOWN;
+ state->duplex = DUPLEX_UNKNOWN;
+ state->pause = 0;
+@@ -984,6 +985,8 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
+ if (ret < 0)
+ return ret;
+
++ state->an_complete = ret & DW_VR_MII_AN_STS_C37_ANCMPLT_INTR;
++
+ if (ret & DW_VR_MII_C37_ANSGM_SP_LNKSTS) {
+ int speed_value;
+
+@@ -1002,34 +1005,13 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
+ state->duplex = DUPLEX_FULL;
+ else
+ state->duplex = DUPLEX_HALF;
+- } else if (ret == DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
+- int speed, duplex;
+-
+- state->link = true;
+-
+- speed = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
+- if (speed < 0)
+- return speed;
+-
+- speed &= SGMII_SPEED_SS13 | SGMII_SPEED_SS6;
+- if (speed == SGMII_SPEED_SS6)
+- state->speed = SPEED_1000;
+- else if (speed == SGMII_SPEED_SS13)
+- state->speed = SPEED_100;
+- else if (speed == 0)
+- state->speed = SPEED_10;
+-
+- duplex = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_ADVERTISE);
+- if (duplex < 0)
+- return duplex;
+
+- if (duplex & DW_FULL_DUPLEX)
+- state->duplex = DUPLEX_FULL;
+- else if (duplex & DW_HALF_DUPLEX)
+- state->duplex = DUPLEX_HALF;
++ return 0;
++ }
+
++ /* Clear AN complete status or interrupt */
++ if (state->an_complete)
+ xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
+- }
+
+ return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From fd0dd4e746e330ebc74b67549536bc6eb82de15a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 17:04:11 +0200
+Subject: net: qrtr: ns: Raise node count limit to 512
+
+From: Youssef Samir <youssef.abdulrahman@oss.qualcomm.com>
+
+commit ff194cffd586cbd4cc49eccb002c65f2a902a277 upstream.
+
+The current node limit of 64 breaks the functionality for a number of AI200
+deployments that have up to 384 nodes. Raise the limit to 512.
+
+Fixes: 27d5e84e810b ("net: qrtr: ns: Limit the total number of nodes")
+Cc: stable@vger.kernel.org
+Signed-off-by: Youssef Samir <youssef.abdulrahman@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260713145901.212396-1-youssef.abdulrahman@oss.qualcomm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Youssef Samir <youssef.abdulrahman@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/ns.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c
+index a10e8de4f7e105..e8e3ba1b3b8239 100644
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -85,9 +85,9 @@ struct qrtr_node {
+ /* Max nodes limit is chosen based on the current platform requirements.
+ * If the requirement changes in the future, this value can be increased.
+ */
+-#define QRTR_NS_MAX_NODES 64
++#define QRTR_NS_MAX_NODES 512
+
+-static u8 node_count;
++static u16 node_count;
+
+ static struct qrtr_node *node_get(unsigned int node_id)
+ {
+--
+2.53.0
+
drm-amdgpu-invoke-pm_genpd_remove-before-freeing-genpd.patch
drm-amdgpu-fix-aperture-mapping-leak.patch
drm-amd-pm-fix-smu13-power-limit-range-calculation.patch
+bpf-fix-same-register-dst-src-oob-read-and-pointer-l.patch
+net-qrtr-ns-raise-node-count-limit-to-512.patch
+ksmbd-validate-num_subauth-when-copying-ace-in-set_n.patch
+ksmbd-restore-dacl-size-on-check_add_overflow-to-avo.patch
+ksmbd-bound-dacl-dedup-walk-to-copied-aces.patch
+ksmbd-validate-ace-size-against-sid-sub-authorities.patch
+fscrypt-avoid-dynamic-allocation-in-fscrypt_get_devi.patch
+drm-amd-display-fix-dtb-dto-updates-breaking-live-pi.patch
+io_uring-rw-fix-missing-erestartsys-conversion-in-re.patch
+net-pcs-xpcs-fix-sgmii-state-reading.patch
+gve-fix-rx-queue-stall-on-alloc-failure.patch
--- /dev/null
+From 9cfb9b37e6091da08fa39cfcdaf9952b6a9f4f9a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 20:26:58 +0000
+Subject: bpf: Fix same-register dst/src OOB read and pointer leak in sock_ops
+
+From: Jiayuan Chen <jiayuan.chen@linux.dev>
+
+[ Upstream commit 10f86a2a5c91fc4c4d001960f1c21abe52545ef6 ]
+
+When a BPF sock_ops program accesses ctx fields with dst_reg == src_reg,
+the SOCK_OPS_GET_SK() and SOCK_OPS_GET_FIELD() macros fail to zero the
+destination register in the !fullsock / !locked_tcp_sock path.
+
+Both macros borrow a temporary register to check is_fullsock /
+is_locked_tcp_sock when dst_reg == src_reg, because dst_reg holds the
+ctx pointer. When the check is false (e.g., TCP_NEW_SYN_RECV state with
+a request_sock), dst_reg should be zeroed but is not, leaving the stale
+ctx pointer:
+
+ - SOCK_OPS_GET_SK: dst_reg retains the ctx pointer, passes NULL checks
+ as PTR_TO_SOCKET_OR_NULL, and can be used as a bogus socket pointer,
+ leading to stack-out-of-bounds access in helpers like
+ bpf_skc_to_tcp6_sock().
+
+ - SOCK_OPS_GET_FIELD: dst_reg retains the ctx pointer which the
+ verifier believes is a SCALAR_VALUE, leaking a kernel pointer.
+
+Fix both macros by:
+ - Changing JMP_A(1) to JMP_A(2) in the fullsock path to skip the
+ added instruction.
+ - Adding BPF_MOV64_IMM(si->dst_reg, 0) after the temp register
+ restore in the !fullsock path, placed after the restore because
+ dst_reg == src_reg means we need src_reg intact to read ctx->temp.
+
+Fixes: fd09af010788 ("bpf: sock_ops ctx access may stomp registers in corner case")
+Fixes: 84f44df664e9 ("bpf: sock_ops sk access may stomp registers when dst_reg = src_reg")
+Reported-by: Quan Sun <2022090917019@std.uestc.edu.cn>
+Reported-by: Yinhao Hu <dddddd@hust.edu.cn>
+Reported-by: Kaiyan Mei <M202472210@hust.edu.cn>
+Reported-by: Dongliang Mu <dzm91@hust.edu.cn>
+Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
+Closes: https://lore.kernel.org/bpf/6fe1243e-149b-4d3b-99c7-fcc9e2f75787@std.uestc.edu.cn/T/#u
+Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Acked-by: Martin KaFai Lau <martin.lau@kernel.org>
+Link: https://patch.msgid.link/20260407022720.162151-2-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Jay Wang <wanjay@amazon.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/filter.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/net/core/filter.c b/net/core/filter.c
+index 42385e79043131..332f4986376f11 100644
+--- a/net/core/filter.c
++++ b/net/core/filter.c
+@@ -10539,10 +10539,11 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type,
+ si->dst_reg, si->dst_reg, \
+ offsetof(OBJ, OBJ_FIELD)); \
+ if (si->dst_reg == si->src_reg) { \
+- *insn++ = BPF_JMP_A(1); \
++ *insn++ = BPF_JMP_A(2); \
+ *insn++ = BPF_LDX_MEM(BPF_DW, reg, si->src_reg, \
+ offsetof(struct bpf_sock_ops_kern, \
+ temp)); \
++ *insn++ = BPF_MOV64_IMM(si->dst_reg, 0); \
+ } \
+ } while (0)
+
+@@ -10576,10 +10577,11 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type,
+ si->dst_reg, si->src_reg, \
+ offsetof(struct bpf_sock_ops_kern, sk));\
+ if (si->dst_reg == si->src_reg) { \
+- *insn++ = BPF_JMP_A(1); \
++ *insn++ = BPF_JMP_A(2); \
+ *insn++ = BPF_LDX_MEM(BPF_DW, reg, si->src_reg, \
+ offsetof(struct bpf_sock_ops_kern, \
+ temp)); \
++ *insn++ = BPF_MOV64_IMM(si->dst_reg, 0); \
+ } \
+ } while (0)
+
+--
+2.53.0
+
--- /dev/null
+From 9e736361849fce698d2af96ba009e236b6c26cd7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 22:19:07 -0700
+Subject: dm-verity-fec: fix reading parity bytes split across blocks (take 3)
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 430a05cb926f6bdf53e81460a2c3a553257f3f61 upstream.
+
+fec_decode_bufs() assumes that the parity bytes of the first RS codeword
+it decodes are never split across parity blocks.
+
+This assumption is false. Consider v->fec->block_size == 4096 &&
+v->fec->roots == 17 && fio->nbufs == 1, for example. In that case, each
+call to fec_decode_bufs() consumes v->fec->roots * (fio->nbufs <<
+DM_VERITY_FEC_BUF_RS_BITS) = 272 parity bytes.
+
+Considering that the parity data for each message block starts on a
+block boundary, the byte alignment in the parity data will iterate
+through 272*i mod 4096 until the 3 parity blocks have been consumed. On
+the 16th call (i=15), the alignment will be 4080 bytes into the first
+block. Only 16 bytes remain in that block, but 17 parity bytes will be
+needed. The code reads out-of-bounds from the parity block buffer.
+
+Fortunately this doesn't normally happen, since it can occur only for
+certain non-default values of fec_roots *and* when the maximum number of
+buffers couldn't be allocated due to low memory. For example with
+block_size=4096 only the following cases are affected:
+
+ fec_roots=17: nbufs in [1, 3, 5, 15]
+ fec_roots=19: nbufs in [1, 229]
+ fec_roots=21: nbufs in [1, 3, 5, 13, 15, 39, 65, 195]
+ fec_roots=23: nbufs in [1, 89]
+
+Regardless, fix it by refactoring how the parity blocks are read.
+
+Fixes: 6df90c02bae4 ("dm-verity FEC: Fix RS FEC repair for roots unaligned to block size (take 2)")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/md/dm-verity-fec.c | 100 ++++++++++++++++---------------------
+ 1 file changed, 44 insertions(+), 56 deletions(-)
+
+diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
+index 03e59b85132aa7..a8fbf97b97517f 100644
+--- a/drivers/md/dm-verity-fec.c
++++ b/drivers/md/dm-verity-fec.c
+@@ -39,36 +39,6 @@ static inline u64 fec_interleave(struct dm_verity *v, u64 offset)
+ return offset + mod * (v->fec->rounds << v->data_dev_block_bits);
+ }
+
+-/*
+- * Read error-correcting codes for the requested RS block. Returns a pointer
+- * to the data block. Caller is responsible for releasing buf.
+- */
+-static u8 *fec_read_parity(struct dm_verity *v, u64 rsb, int index,
+- unsigned int *offset, unsigned int par_buf_offset,
+- struct dm_buffer **buf, unsigned short ioprio)
+-{
+- u64 position, block, rem;
+- u8 *res;
+-
+- /* We have already part of parity bytes read, skip to the next block */
+- if (par_buf_offset)
+- index++;
+-
+- position = (index + rsb) * v->fec->roots;
+- block = div64_u64_rem(position, v->fec->io_size, &rem);
+- *offset = par_buf_offset ? 0 : (unsigned int)rem;
+-
+- res = dm_bufio_read_with_ioprio(v->fec->bufio, block, buf, ioprio);
+- if (IS_ERR(res)) {
+- DMERR("%s: FEC %llu: parity read failed (block %llu): %ld",
+- v->data_dev->name, (unsigned long long)rsb,
+- (unsigned long long)block, PTR_ERR(res));
+- *buf = NULL;
+- }
+-
+- return res;
+-}
+-
+ /* Loop over each preallocated buffer slot. */
+ #define fec_for_each_prealloc_buffer(__i) \
+ for (__i = 0; __i < DM_VERITY_FEC_BUF_PREALLOC; __i++)
+@@ -116,15 +86,29 @@ static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_io *io,
+ {
+ int r, corrected = 0, res;
+ struct dm_buffer *buf;
+- unsigned int n, i, j, offset, par_buf_offset = 0;
++ unsigned int n, i, j, parity_pos, to_copy;
+ uint16_t par_buf[DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN];
+ u8 *par, *block;
++ u64 parity_block;
+ struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
+
+- par = fec_read_parity(v, rsb, block_offset, &offset,
+- par_buf_offset, &buf, bio->bi_ioprio);
+- if (IS_ERR(par))
++ /*
++ * Compute the index of the first parity block that will be needed and
++ * the starting position in that block. Then read that block.
++ *
++ * io_size is always a power of 2, but roots might not be. Note that
++ * when it's not, a codeword's parity bytes can span a block boundary.
++ */
++ parity_block = (rsb + block_offset) * v->fec->roots;
++ parity_pos = parity_block & (v->fec->io_size - 1);
++ parity_block >>= v->data_dev_block_bits;
++ par = dm_bufio_read_with_ioprio(v->fec->bufio, parity_block, &buf,
++ bio->bi_ioprio);
++ if (IS_ERR(par)) {
++ DMERR("%s: FEC %llu: parity read failed (block %llu): %ld",
++ v->data_dev->name, rsb, parity_block, PTR_ERR(par));
+ return PTR_ERR(par);
++ }
+
+ /*
+ * Decode the RS blocks we have in bufs. Each RS block results in
+@@ -132,8 +116,32 @@ static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_io *io,
+ */
+ fec_for_each_buffer_rs_block(fio, n, i) {
+ block = fec_buffer_rs_block(v, fio, n, i);
+- for (j = 0; j < v->fec->roots - par_buf_offset; j++)
+- par_buf[par_buf_offset + j] = par[offset + j];
++
++ /*
++ * Copy the next 'roots' parity bytes to 'par_buf', reading
++ * another parity block if needed.
++ */
++ to_copy = min(v->fec->io_size - parity_pos, v->fec->roots);
++ for (j = 0; j < to_copy; j++)
++ par_buf[j] = par[parity_pos++];
++ if (to_copy < v->fec->roots) {
++ parity_block++;
++ parity_pos = 0;
++
++ dm_bufio_release(buf);
++ par = dm_bufio_read_with_ioprio(v->fec->bufio,
++ parity_block, &buf,
++ bio->bi_ioprio);
++ if (IS_ERR(par)) {
++ DMERR("%s: FEC %llu: parity read failed (block %llu): %ld",
++ v->data_dev->name, rsb, parity_block,
++ PTR_ERR(par));
++ return PTR_ERR(par);
++ }
++ for (; j < v->fec->roots; j++)
++ par_buf[j] = par[parity_pos++];
++ }
++
+ /* Decode an RS block using Reed-Solomon */
+ res = decode_rs8(fio->rs, block, par_buf, v->fec->rsn,
+ NULL, neras, fio->erasures, 0, NULL);
+@@ -148,26 +156,6 @@ static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_io *io,
+ block_offset++;
+ if (block_offset >= 1 << v->data_dev_block_bits)
+ goto done;
+-
+- /* Read the next block when we run out of parity bytes */
+- offset += (v->fec->roots - par_buf_offset);
+- /* Check if parity bytes are split between blocks */
+- if (offset < v->fec->io_size && (offset + v->fec->roots) > v->fec->io_size) {
+- par_buf_offset = v->fec->io_size - offset;
+- for (j = 0; j < par_buf_offset; j++)
+- par_buf[j] = par[offset + j];
+- offset += par_buf_offset;
+- } else
+- par_buf_offset = 0;
+-
+- if (offset >= v->fec->io_size) {
+- dm_bufio_release(buf);
+-
+- par = fec_read_parity(v, rsb, block_offset, &offset,
+- par_buf_offset, &buf, bio->bi_ioprio);
+- if (IS_ERR(par))
+- return PTR_ERR(par);
+- }
+ }
+ done:
+ r = corrected;
+--
+2.53.0
+
--- /dev/null
+From 1be9e43a1d32e34c4a864b389c956c19023c88ec Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 22:19:06 -0700
+Subject: dm-verity-fec: fix the size of dm_verity_fec_io::erasures
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit a7fca324d7d90f7b139d4d32747c83a629fdb446 upstream.
+
+At most 25 entries in dm_verity_fec_io::erasures are used: the maximum
+number of FEC roots plus one. Therefore, set the array size
+accordingly. This reduces the size of dm_verity_fec_io by 912 bytes.
+
+Note: a later commit introduces a constant DM_VERITY_FEC_MAX_ROOTS,
+which allows the size to be more clearly expressed as
+DM_VERITY_FEC_MAX_ROOTS + 1. This commit just fixes the size first.
+
+Fixes: a739ff3f543a ("dm verity: add support for forward error correction")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/md/dm-verity-fec.h | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/md/dm-verity-fec.h b/drivers/md/dm-verity-fec.h
+index ec37e607cb3f09..90a0af3f35d31a 100644
+--- a/drivers/md/dm-verity-fec.h
++++ b/drivers/md/dm-verity-fec.h
+@@ -50,7 +50,8 @@ struct dm_verity_fec {
+ /* per-bio data */
+ struct dm_verity_fec_io {
+ struct rs_control *rs; /* Reed-Solomon state */
+- int erasures[DM_VERITY_FEC_MAX_RSN]; /* erasures for decode_rs8 */
++ /* erasures for decode_rs8 */
++ int erasures[DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN + 1];
+ u8 *bufs[DM_VERITY_FEC_BUF_MAX]; /* bufs for deinterleaving */
+ unsigned int nbufs; /* number of buffers allocated */
+ u8 *output; /* buffer for corrected output */
+--
+2.53.0
+
--- /dev/null
+From fe297b15822c386e22dde9e44294a8b284030c08 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 22:19:08 -0700
+Subject: dm-verity-fec: replace {MAX,MIN}_RSN with {MIN,MAX}_ROOTS
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 82fbd6a3e29a329d439690cd7ccc4162c9cd8db6 upstream.
+
+Every time DM_VERITY_FEC_{MAX,MIN}_RSN are used, they are subtracted
+from DM_VERITY_FEC_RSM to get the bounds on the number of roots.
+Therefore, replace these with {MIN,MAX}_ROOTS constants which are more
+directly useful. (Note the inversion, where MAX_RSN maps to MIN_ROOTS
+and MIN_RSN maps to MAX_ROOTS.) No functional change.
+
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/md/dm-verity-fec.c | 6 +++---
+ drivers/md/dm-verity-fec.h | 7 +++----
+ 2 files changed, 6 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
+index a8fbf97b97517f..cebcc8fd25d700 100644
+--- a/drivers/md/dm-verity-fec.c
++++ b/drivers/md/dm-verity-fec.c
+@@ -87,7 +87,7 @@ static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_io *io,
+ int r, corrected = 0, res;
+ struct dm_buffer *buf;
+ unsigned int n, i, j, parity_pos, to_copy;
+- uint16_t par_buf[DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN];
++ uint16_t par_buf[DM_VERITY_FEC_MAX_ROOTS];
+ u8 *par, *block;
+ u64 parity_block;
+ struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
+@@ -605,8 +605,8 @@ int verity_fec_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
+
+ } else if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_ROOTS)) {
+ if (sscanf(arg_value, "%hhu%c", &num_c, &dummy) != 1 || !num_c ||
+- num_c < (DM_VERITY_FEC_RSM - DM_VERITY_FEC_MAX_RSN) ||
+- num_c > (DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN)) {
++ num_c < DM_VERITY_FEC_MIN_ROOTS ||
++ num_c > DM_VERITY_FEC_MAX_ROOTS) {
+ ti->error = "Invalid " DM_VERITY_OPT_FEC_ROOTS;
+ return -EINVAL;
+ }
+diff --git a/drivers/md/dm-verity-fec.h b/drivers/md/dm-verity-fec.h
+index 90a0af3f35d31a..b3460103e0e109 100644
+--- a/drivers/md/dm-verity-fec.h
++++ b/drivers/md/dm-verity-fec.h
+@@ -13,8 +13,8 @@
+
+ /* Reed-Solomon(M, N) parameters */
+ #define DM_VERITY_FEC_RSM 255
+-#define DM_VERITY_FEC_MAX_RSN 253
+-#define DM_VERITY_FEC_MIN_RSN 231 /* ~10% space overhead */
++#define DM_VERITY_FEC_MIN_ROOTS 2 /* RS(255, 253): ~0.8% space overhead */
++#define DM_VERITY_FEC_MAX_ROOTS 24 /* RS(255, 231): ~10% space overhead */
+
+ /* buffers for deinterleaving and decoding */
+ #define DM_VERITY_FEC_BUF_PREALLOC 1 /* buffers to preallocate */
+@@ -50,8 +50,7 @@ struct dm_verity_fec {
+ /* per-bio data */
+ struct dm_verity_fec_io {
+ struct rs_control *rs; /* Reed-Solomon state */
+- /* erasures for decode_rs8 */
+- int erasures[DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN + 1];
++ int erasures[DM_VERITY_FEC_MAX_ROOTS + 1]; /* erasures for decode_rs8 */
+ u8 *bufs[DM_VERITY_FEC_BUF_MAX]; /* bufs for deinterleaving */
+ unsigned int nbufs; /* number of buffers allocated */
+ u8 *output; /* buffer for corrected output */
+--
+2.53.0
+
--- /dev/null
+From e4db88b48fb6a9ca5ee904c1b6cd92839dbbfa4c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 22:19:09 -0700
+Subject: dm-verity: fix buffer overflow in FEC calculation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 31d6e6c0ba8d5a7bd59660035a089307100c5e8e upstream.
+
+There's a buffer overflow in dm-verity-fec:
+
+if (neras && *neras <= v->fec->roots)
+ fio->erasures[(*neras)++] = i;
+
+This allows *neras to reach roots + 1 (the post-increment pushes it past
+roots). This value is then passed as no_eras to decode_rs8(). Inside the
+RS decoder (lib/reed_solomon/decode_rs.c:113-121), the erasure locator
+polynomial loop writes lambda[j] where j can reach nroots + 1 — one
+element past the end of lambda[] (which is sized nroots + 1, valid
+indices 0..nroots). The out-of-bounds write lands on syn[0], corrupting
+the syndrome buffer.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Assisted-by: Claude:claude-opus-4-6
+Cc: stable@vger.kernel.org
+Fixes: a739ff3f543a ("dm verity: add support for forward error correction")
+Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/md/dm-verity-fec.c | 4 ++--
+ drivers/md/dm-verity-fec.h | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
+index cebcc8fd25d700..d1e4fbc5a21d9b 100644
+--- a/drivers/md/dm-verity-fec.c
++++ b/drivers/md/dm-verity-fec.c
+@@ -250,7 +250,7 @@ static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,
+ (unsigned long long)block, PTR_ERR(bbuf));
+
+ /* assume the block is corrupted */
+- if (neras && *neras <= v->fec->roots)
++ if (neras && *neras < v->fec->roots)
+ fio->erasures[(*neras)++] = i;
+
+ continue;
+@@ -268,7 +268,7 @@ static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,
+ * skip if we have already found the theoretical
+ * maximum number (i.e. fec->roots) of erasures
+ */
+- if (neras && *neras <= v->fec->roots &&
++ if (neras && *neras < v->fec->roots &&
+ fec_is_erasure(v, io, want_digest, bbuf))
+ fio->erasures[(*neras)++] = i;
+ }
+diff --git a/drivers/md/dm-verity-fec.h b/drivers/md/dm-verity-fec.h
+index b3460103e0e109..8552b5d3c91527 100644
+--- a/drivers/md/dm-verity-fec.h
++++ b/drivers/md/dm-verity-fec.h
+@@ -50,7 +50,7 @@ struct dm_verity_fec {
+ /* per-bio data */
+ struct dm_verity_fec_io {
+ struct rs_control *rs; /* Reed-Solomon state */
+- int erasures[DM_VERITY_FEC_MAX_ROOTS + 1]; /* erasures for decode_rs8 */
++ int erasures[DM_VERITY_FEC_MAX_ROOTS]; /* erasures for decode_rs8 */
+ u8 *bufs[DM_VERITY_FEC_BUF_MAX]; /* bufs for deinterleaving */
+ unsigned int nbufs; /* number of buffers allocated */
+ u8 *output; /* buffer for corrected output */
+--
+2.53.0
+
--- /dev/null
+From 4085c33cb874858a1fdcc8df79dc6342fa2c7c9f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 23:33:40 -0700
+Subject: drm/amd/display: Fix DTB DTO updates breaking live pixel rate sources
+
+From: Harry Wentland <harry.wentland@amd.com>
+
+commit 76a2db58e95e328007043f54ac3c7336ccbee440 upstream.
+
+dcn32_update_clocks_update_dtb_dto() and its dcn35 counterpart reprogram
+the DTB DTO of every timing generator in the context whenever the DTBCLK
+reference changes, passing a zeroed pixel rate and never setting
+is_hdmi. Both dccg set_dtbclk_dto() implementations treat a zero pixel
+rate as a disable request. On dcn32 that branch drives PIPE_DTO_SRC_SEL
+to the DP DTO source, so a timing generator actively scanning out an
+HDMI stream has its pixel rate source re-muxed out from under the live
+raster and the OTG stops on the spot. On dcn35 it clears
+DTBCLK_DTO_ENABLE and restores DTBCLK_Pn clock gating, which does the
+same to a live 128b/132b stream.
+
+Two displays where only one runs a 128b/132b link hit this reliably.
+is_dtbclk_required() holds the DTBCLK reference high while both are
+active, and the moment the 128b/132b stream is torn down (compositor
+switch, display disable, hot-unplug) the next safe_to_lower pass drops
+the reference to the lowest DPM level and the DTO walk freezes the
+surviving screen. On Navi31 the DAL mailbox then goes deaf on the
+DISPCLK hard-min that follows the walk in dcn32_update_clocks(),
+stranding both SMU mailboxes until reboot.
+
+Set is_hdmi for HDMI and DVI signals so the disable path leaves the
+pixel rate source selection on the HDMI path, and pass the real pixel
+rate for 128b/132b streams so a reference change rescales their DTO
+instead of disabling it.
+
+Fixes: 128c1ca0303f ("drm/amd/display: Update DTBCLK for DCN32")
+Fixes: 8774029f76b9 ("drm/amd/display: Add DCN35 CLK_MGR")
+Signed-off-by: Harry Wentland <harry.wentland@amd.com>
+Reviewed-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
+Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+[ mschwartz: dcn32 and dcn35 clk_mgr hunks only. The rest is HDMI FRL
+ enablement, absent before 7.2, so the FRL conditions and the
+ req_audio_dtbclk_khz assignment they guard are dropped and the
+ FRL-centric changelog is rewritten. Added the pipe_ctx->stream check
+ the new dereferences need. ]
+Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c | 9 ++++++++-
+ .../gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 9 ++++++++-
+ 2 files changed, 16 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+index 7da7b41bd09256..b98d946a8d2ee6 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+@@ -276,13 +276,20 @@ static void dcn32_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
+ struct dtbclk_dto_params dto_params = {0};
+
+ /* use mask to program DTO once per tg */
+- if (pipe_ctx->stream_res.tg &&
++ if (pipe_ctx->stream && pipe_ctx->stream_res.tg &&
+ !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) {
+ tg_mask |= (1 << pipe_ctx->stream_res.tg->inst);
+
+ dto_params.otg_inst = pipe_ctx->stream_res.tg->inst;
+ dto_params.ref_dtbclk_khz = ref_dtbclk_khz;
+
++ if (dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))
++ dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
++
++ if (dc_is_hdmi_signal(pipe_ctx->stream->signal) ||
++ dc_is_dvi_signal(pipe_ctx->stream->signal))
++ dto_params.is_hdmi = true;
++
+ dccg->funcs->set_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ //dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
+index 817a0253d10e52..d1785a5c7f85fd 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
+@@ -264,13 +264,20 @@ static void dcn35_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
+ struct dtbclk_dto_params dto_params = {0};
+
+ /* use mask to program DTO once per tg */
+- if (pipe_ctx->stream_res.tg &&
++ if (pipe_ctx->stream && pipe_ctx->stream_res.tg &&
+ !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) {
+ tg_mask |= (1 << pipe_ctx->stream_res.tg->inst);
+
+ dto_params.otg_inst = pipe_ctx->stream_res.tg->inst;
+ dto_params.ref_dtbclk_khz = ref_dtbclk_khz;
+
++ if (dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))
++ dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
++
++ if (dc_is_hdmi_signal(pipe_ctx->stream->signal) ||
++ dc_is_dvi_signal(pipe_ctx->stream->signal))
++ dto_params.is_hdmi = true;
++
+ dccg->funcs->set_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ //dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ }
+--
+2.53.0
+
--- /dev/null
+From 821812229a4be5ee65ccc501052d8727f2937cfc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 14:37:59 +0000
+Subject: drm/xe/uapi: Reject coh_none PAT index for CPU_ADDR_MIRROR
+
+From: Jia Yao <jia.yao@intel.com>
+
+commit 4d58d7535e826a3175527b6174502f0db319d7f6 upstream.
+
+Add validation in xe_vm_bind_ioctl() to reject PAT indices
+with XE_COH_NONE coherency mode when used with
+DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR.
+
+CPU address mirror mappings use system memory that is CPU
+cached, which makes them incompatible with COH_NONE PAT
+indices. Allowing COH_NONE with CPU cached buffers is a
+security risk, as the GPU may bypass CPU caches and read
+stale sensitive data from DRAM.
+
+Although CPU_ADDR_MIRROR does not create an immediate
+mapping, the backing system memory is still CPU cached.
+Apply the same PAT coherency restrictions as
+DRM_XE_VM_BIND_OP_MAP_USERPTR.
+
+v2:
+- Correct fix tag
+
+v6:
+- No change
+
+v7:
+- Correct fix tag
+
+v8:
+- Rebase
+
+v9:
+- Limit the restrictions to iGPU
+
+v10:
+- Just add the iGPU logic but keep dGPU logic
+
+Fixes: b43e864af0d4 ("drm/xe/uapi: Add DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR")
+Cc: <stable@vger.kernel.org> # v6.15+
+Cc: Shuicheng Lin <shuicheng.lin@intel.com>
+Cc: Mathew Alwin <alwin.mathew@intel.com>
+Cc: Michal Mrozek <michal.mrozek@intel.com>
+Cc: Matthew Brost <matthew.brost@intel.com>
+Cc: Matthew Auld <matthew.auld@intel.com>
+Signed-off-by: Jia Yao <jia.yao@intel.com>
+Reviewed-by: Matthew Auld <matthew.auld@intel.com>
+Acked-by: Michal Mrozek <michal.mrozek@intel.com>
+Signed-off-by: Matthew Auld <matthew.auld@intel.com>
+Link: https://patch.msgid.link/20260417055917.2027459-3-jia.yao@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_vm.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
+index b00da90e399135..ed0c8acd0fe27c 100644
+--- a/drivers/gpu/drm/xe/xe_vm.c
++++ b/drivers/gpu/drm/xe/xe_vm.c
+@@ -3393,6 +3393,8 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm,
+ op == DRM_XE_VM_BIND_OP_MAP_USERPTR) ||
+ XE_IOCTL_DBG(xe, coh_mode == XE_COH_NONE &&
+ op == DRM_XE_VM_BIND_OP_MAP_USERPTR) ||
++ XE_IOCTL_DBG(xe, !IS_DGFX(xe) && coh_mode == XE_COH_NONE &&
++ is_cpu_addr_mirror) ||
+ XE_IOCTL_DBG(xe, op == DRM_XE_VM_BIND_OP_MAP_USERPTR &&
+ !IS_ENABLED(CONFIG_DRM_GPUSVM)) ||
+ XE_IOCTL_DBG(xe, obj &&
+--
+2.53.0
+
--- /dev/null
+From 9fd3191eb8cae8af20fd863d7e121c8d49c98c78 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 08:19:05 -0700
+Subject: fscrypt: Avoid dynamic allocation in fscrypt_get_devices()
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 6fe4e4b8259e1330945b5f3c9476e08473b8e0e8 upstream.
+
+When a blk_crypto_key starts being used or is evicted, fs/crypto/ calls
+fscrypt_get_devices() to get the filesystem's list of block devices,
+then iterates over them and calls blk_crypto_config_supported(),
+blk_crypto_start_using_key(), or blk_crypto_evict_key() on each one.
+
+Currently, the block device pointers are placed in a dynamically
+allocated array. This dynamic allocation is problematic because:
+
+- It can fail, especially at the fscrypt_destroy_inline_crypt_key() call
+ site when it's invoked for inode eviction under direct reclaim.
+
+- fscrypt_destroy_inline_crypt_key() doesn't handle the failure. It
+ just zeroizes and frees the blk_crypto_key without calling
+ blk_crypto_evict_key(). That causes a use-after-free.
+
+For now, let's fix this in the straightforward and easily-backportable
+way by switching to an on-stack array. Currently the fscrypt
+multi-device functionality is used only by f2fs, which has a hardcoded
+limit of 8 block devices. An on-stack array works fine for that.
+
+(Of course, this solution won't scale up to large number of block
+devices. For that we'd need a different solution, like moving the block
+device iteration into the filesystem. Or in the case of btrfs, which
+will only support blk-crypto-fallback, we should make it just call
+blk-crypto-fallback directly, so the block devices won't be needed.)
+
+Fixes: 22e9947a4b2b ("fscrypt: stop holding extra request_queue references")
+Cc: stable@vger.kernel.org
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Closes: https://sashiko.dev/#/patchset/20260713023708.9245-1-ebiggers%40kernel.org
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Link: https://patch.msgid.link/20260719055602.78828-1-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/crypto/inline_crypt.c | 57 ++++++++++++++--------------------------
+ fs/f2fs/super.c | 25 ++++++++++--------
+ include/linux/fscrypt.h | 18 +++++++------
+ 3 files changed, 44 insertions(+), 56 deletions(-)
+
+diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
+index 645cc493607294..500397ca8a26fa 100644
+--- a/fs/crypto/inline_crypt.c
++++ b/fs/crypto/inline_crypt.c
+@@ -22,22 +22,14 @@
+
+ #include "fscrypt_private.h"
+
+-static struct block_device **fscrypt_get_devices(struct super_block *sb,
+- unsigned int *num_devs)
++static unsigned int
++fscrypt_get_devices(struct super_block *sb,
++ struct block_device *devs[FSCRYPT_MAX_DEVICES])
+ {
+- struct block_device **devs;
+-
+- if (sb->s_cop->get_devices) {
+- devs = sb->s_cop->get_devices(sb, num_devs);
+- if (devs)
+- return devs;
+- }
+- devs = kmalloc(sizeof(*devs), GFP_KERNEL);
+- if (!devs)
+- return ERR_PTR(-ENOMEM);
++ if (sb->s_cop->get_devices)
++ return sb->s_cop->get_devices(sb, devs);
+ devs[0] = sb->s_bdev;
+- *num_devs = 1;
+- return devs;
++ return 1;
+ }
+
+ static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_inode_info *ci)
+@@ -96,7 +88,7 @@ int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,
+ const struct inode *inode = ci->ci_inode;
+ struct super_block *sb = inode->i_sb;
+ struct blk_crypto_config crypto_cfg;
+- struct block_device **devs;
++ struct block_device *devs[FSCRYPT_MAX_DEVICES];
+ unsigned int num_devs;
+ unsigned int i;
+
+@@ -135,20 +127,15 @@ int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,
+ crypto_cfg.key_type = is_hw_wrapped_key ?
+ BLK_CRYPTO_KEY_TYPE_HW_WRAPPED : BLK_CRYPTO_KEY_TYPE_RAW;
+
+- devs = fscrypt_get_devices(sb, &num_devs);
+- if (IS_ERR(devs))
+- return PTR_ERR(devs);
+-
++ num_devs = fscrypt_get_devices(sb, devs);
+ for (i = 0; i < num_devs; i++) {
+ if (!blk_crypto_config_supported(devs[i], &crypto_cfg))
+- goto out_free_devs;
++ return 0;
+ }
+
+ fscrypt_log_blk_crypto_impl(ci->ci_mode, devs, num_devs, &crypto_cfg);
+
+ ci->ci_inlinecrypt = true;
+-out_free_devs:
+- kfree(devs);
+
+ return 0;
+ }
+@@ -164,7 +151,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
+ enum blk_crypto_key_type key_type = is_hw_wrapped ?
+ BLK_CRYPTO_KEY_TYPE_HW_WRAPPED : BLK_CRYPTO_KEY_TYPE_RAW;
+ struct blk_crypto_key *blk_key;
+- struct block_device **devs;
++ struct block_device *devs[FSCRYPT_MAX_DEVICES];
+ unsigned int num_devs;
+ unsigned int i;
+ int err;
+@@ -182,17 +169,12 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
+ }
+
+ /* Start using blk-crypto on all the filesystem's block devices. */
+- devs = fscrypt_get_devices(sb, &num_devs);
+- if (IS_ERR(devs)) {
+- err = PTR_ERR(devs);
+- goto fail;
+- }
++ num_devs = fscrypt_get_devices(sb, devs);
+ for (i = 0; i < num_devs; i++) {
+ err = blk_crypto_start_using_key(devs[i], blk_key);
+ if (err)
+ break;
+ }
+- kfree(devs);
+ if (err) {
+ fscrypt_err(inode, "error %d starting to use blk-crypto", err);
+ goto fail;
+@@ -210,20 +192,21 @@ void fscrypt_destroy_inline_crypt_key(struct super_block *sb,
+ struct fscrypt_prepared_key *prep_key)
+ {
+ struct blk_crypto_key *blk_key = prep_key->blk_key;
+- struct block_device **devs;
++ struct block_device *devs[FSCRYPT_MAX_DEVICES];
+ unsigned int num_devs;
+ unsigned int i;
+
+ if (!blk_key)
+ return;
+
+- /* Evict the key from all the filesystem's block devices. */
+- devs = fscrypt_get_devices(sb, &num_devs);
+- if (!IS_ERR(devs)) {
+- for (i = 0; i < num_devs; i++)
+- blk_crypto_evict_key(devs[i], blk_key);
+- kfree(devs);
+- }
++ /*
++ * Evict the key from all the filesystem's block devices.
++ * This *must* be done before the key is freed.
++ */
++ num_devs = fscrypt_get_devices(sb, devs);
++ for (i = 0; i < num_devs; i++)
++ blk_crypto_evict_key(devs[i], blk_key);
++
+ kfree_sensitive(blk_key);
+ }
+
+diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
+index f6b75ce11d1c1a..6f787cbeefd096 100644
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -3659,24 +3659,27 @@ static bool f2fs_has_stable_inodes(struct super_block *sb)
+ return true;
+ }
+
+-static struct block_device **f2fs_get_devices(struct super_block *sb,
+- unsigned int *num_devs)
++static unsigned int
++f2fs_get_devices(struct super_block *sb,
++ struct block_device *devs[FSCRYPT_MAX_DEVICES])
+ {
+ struct f2fs_sb_info *sbi = F2FS_SB(sb);
+- struct block_device **devs;
++ int ndevs;
+ int i;
+
+- if (!f2fs_is_multi_device(sbi))
+- return NULL;
++ static_assert(MAX_DEVICES <= FSCRYPT_MAX_DEVICES);
+
+- devs = kmalloc_array(sbi->s_ndevs, sizeof(*devs), GFP_KERNEL);
+- if (!devs)
+- return ERR_PTR(-ENOMEM);
++ if (!f2fs_is_multi_device(sbi)) {
++ devs[0] = sb->s_bdev;
++ return 1;
++ }
++ ndevs = sbi->s_ndevs;
++ if (WARN_ON_ONCE(ndevs > FSCRYPT_MAX_DEVICES))
++ ndevs = FSCRYPT_MAX_DEVICES;
+
+- for (i = 0; i < sbi->s_ndevs; i++)
++ for (i = 0; i < ndevs; i++)
+ devs[i] = FDEV(i).bdev;
+- *num_devs = sbi->s_ndevs;
+- return devs;
++ return ndevs;
+ }
+
+ static const struct fscrypt_operations f2fs_cryptops = {
+diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
+index 516aba5b858b54..c009d4afe91857 100644
+--- a/include/linux/fscrypt.h
++++ b/include/linux/fscrypt.h
+@@ -57,6 +57,9 @@ struct fscrypt_name {
+ /* Maximum value for the third parameter of fscrypt_operations.set_context(). */
+ #define FSCRYPT_SET_CONTEXT_MAX_SIZE 40
+
++/* Maximum supported number of block devices per filesystem */
++#define FSCRYPT_MAX_DEVICES 8
++
+ #ifdef CONFIG_FS_ENCRYPTION
+
+ /* Crypto operations for filesystems */
+@@ -181,21 +184,20 @@ struct fscrypt_operations {
+ bool (*has_stable_inodes)(struct super_block *sb);
+
+ /*
+- * Return an array of pointers to the block devices to which the
+- * filesystem may write encrypted file contents, NULL if the filesystem
+- * only has a single such block device, or an ERR_PTR() on error.
++ * Retrieve the list of block devices to which the filesystem may write
++ * encrypted file contents.
+ *
+- * On successful non-NULL return, *num_devs is set to the number of
+- * devices in the returned array. The caller must free the returned
+- * array using kfree().
++ * This writes the block_device pointers to @devs and returns the count
++ * (between 1 and FSCRYPT_MAX_DEVICES inclusively).
+ *
+ * If the filesystem can use multiple block devices (other than block
+ * devices that aren't used for encrypted file contents, such as
+ * external journal devices), and wants to support inline encryption,
+ * then it must implement this function. Otherwise it's not needed.
+ */
+- struct block_device **(*get_devices)(struct super_block *sb,
+- unsigned int *num_devs);
++ unsigned int (*get_devices)(
++ struct super_block *sb,
++ struct block_device *devs[FSCRYPT_MAX_DEVICES]);
+ };
+
+ int fscrypt_d_revalidate(struct inode *dir, const struct qstr *name,
+--
+2.53.0
+
--- /dev/null
+From 39af2ca655959402ad7f642cd73c1efba607da83 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:26 +0800
+Subject: ksmbd: bound DACL dedup walk to copied ACEs
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+commit 58d97fcd0bf1aee694e244cc28635b9df95b543b upstream.
+
+set_ntacl_dacl() can stop copying ACEs before consuming the full input
+DACL when size accounting overflows.
+
+When that happens, num_aces reflects only the ACEs that were actually
+copied into the output DACL, but set_posix_acl_entries_dacl() still
+receives nt_num_aces and uses it to walk the existing ACE array during
+dedup.
+
+That makes the dedup walk scan past the copied ACE array and inspect
+buffer tail that does not contain valid ACEs.
+
+Split the two meanings currently carried by the NT ACE count. Pass the
+number of copied NT ACEs to bound the dedup walk, and preserve the
+original "input DACL had NT ACEs" state separately for the
+Everyone/default ACL fallback.
+
+This keeps the dedup walk aligned with the ACEs that are actually
+present in the rebuilt DACL.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index ca0e4aab6dd87f..b0677e095c3292 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -595,7 +595,8 @@ static void parse_dacl(struct mnt_idmap *idmap,
+ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ struct smb_ace *pndace,
+ struct smb_fattr *fattr, u16 *num_aces,
+- u16 *size, u32 nt_aces_num)
++ u16 *size, u16 existing_nt_aces,
++ bool had_nt_aces)
+ {
+ struct posix_acl_entry *pace;
+ struct smb_sid *sid;
+@@ -627,14 +628,14 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+
+ gid = posix_acl_gid_translate(idmap, pace);
+ id_to_sid(gid, SIDUNIX_GROUP, sid);
+- } else if (pace->e_tag == ACL_OTHER && !nt_aces_num) {
++ } else if (pace->e_tag == ACL_OTHER && !had_nt_aces) {
+ smb_copy_sid(sid, &sid_everyone);
+ } else {
+ kfree(sid);
+ continue;
+ }
+ ntace = pndace;
+- for (j = 0; j < nt_aces_num; j++) {
++ for (j = 0; j < existing_nt_aces; j++) {
+ if (ntace->sid.sub_auth[ntace->sid.num_subauth - 1] ==
+ sid->sub_auth[sid->num_subauth - 1])
+ goto pass_same_sid;
+@@ -678,7 +679,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ kfree(sid);
+ }
+
+- if (nt_aces_num)
++ if (had_nt_aces)
+ return;
+
+ posix_default_acl:
+@@ -732,6 +733,7 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ {
+ struct smb_ace *ntace, *pndace;
+ u16 nt_num_aces = le16_to_cpu(nt_dacl->num_aces), num_aces = 0;
++ u16 copied_nt_aces;
+ unsigned short size = 0;
+ int i;
+
+@@ -765,8 +767,10 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ }
+ }
+
++ copied_nt_aces = num_aces;
+ set_posix_acl_entries_dacl(idmap, pndace, fattr,
+- &num_aces, &size, nt_num_aces);
++ &num_aces, &size, copied_nt_aces,
++ nt_num_aces != 0);
+ pndacl->num_aces = cpu_to_le16(num_aces);
+ pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
+ }
+@@ -784,7 +788,7 @@ static void set_mode_dacl(struct mnt_idmap *idmap,
+
+ if (fattr->cf_acls) {
+ set_posix_acl_entries_dacl(idmap, pndace, fattr,
+- &num_aces, &size, num_aces);
++ &num_aces, &size, num_aces, false);
+ goto out;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From fa6bae8f4562d2aaea7639b95e8badb13808e45b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:24 +0800
+Subject: ksmbd: restore DACL size on check_add_overflow() to avoid malformed
+ ACL
+
+From: Wentao Guan <guanwentao@uniontech.com>
+
+commit bbf0a8e931204ecdab494a88d43b0a24a04285c5 upstream.
+
+check_add_overflow() unconditionally writes the truncated sum into *d
+even on overflow, per its contract in include/linux/overflow.h.
+The four check_add_overflow() guards in set_posix_acl_entries_dacl()
+and set_ntacl_dacl() break out of the ACE-building loops on overflow,
+but the truncated *size is then consumed downstream at the end of
+set_ntacl_dacl():
+
+ pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
+
+This produces an on-wire NT ACL whose pndacl->size under-reports the
+bytes actually written by the preceding fill_ace_for_sid()/memcpy()
+calls, yielding a malformed ACL that can trigger out-of-bounds reads
+when re-parsed by clients or ksmbd itself.
+
+Restore *size to its pre-addition value on each overflow branch (via
+`*size -= ace_sz` / `size -= nt_ace_size`) so that after the break,
+*size once again holds the cumulative size of the successfully-written
+ACEs. The committed ACL is then truncated-but-self-consistent rather
+than malformed.
+
+The ksmbd DACL builders are the only check_add_overflow() sites found
+where an overflow path breaks out of a loop and the destination value
+is consumed afterward. The other nearby break-style cases either
+return -EINVAL on overflow (transport_ipc.c) or break without
+consuming the overflowed destination value afterward (buildid.c).
+
+Fixes: 299f962c0b02 ("ksmbd: use check_add_overflow() to prevent u16 DACL size overflow")
+Assisted-by: atomcode:glm-5.2
+Assisted-by: Codex:gpt-5.5
+Cc: stable@vger.kernel.org
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index 173469d112f101..ca0e4aab6dd87f 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -649,6 +649,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags,
+ pace->e_perm, 0777);
+ if (check_add_overflow(*size, ace_sz, size)) {
++ *size -= ace_sz;
+ kfree(sid);
+ break;
+ }
+@@ -663,6 +664,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED,
+ 0x03, pace->e_perm, 0777);
+ if (check_add_overflow(*size, ace_sz, size)) {
++ *size -= ace_sz;
+ kfree(sid);
+ break;
+ }
+@@ -708,6 +710,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b,
+ pace->e_perm, 0777);
+ if (check_add_overflow(*size, ace_sz, size)) {
++ *size -= ace_sz;
+ kfree(sid);
+ break;
+ }
+@@ -750,8 +753,10 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ goto next_ace;
+
+ memcpy((char *)pndace + size, ntace, nt_ace_size);
+- if (check_add_overflow(size, nt_ace_size, &size))
++ if (check_add_overflow(size, nt_ace_size, &size)) {
++ size -= nt_ace_size;
+ break;
++ }
+ num_aces++;
+
+ next_ace:
+--
+2.53.0
+
--- /dev/null
+From 3837abbd7fee312caf7a7f1d59a930820304bcea Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:29 +0800
+Subject: ksmbd: validate ACE size against SID sub-authorities
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+commit 5152c6d49e3fd4e9f2e857c57527aead752f1f87 upstream.
+
+set_ntacl_dacl() validates sid.num_subauth before copying an ACE, but
+does not verify that the declared ACE size contains all sub-authorities
+described by that field. An undersized ACE can therefore be copied
+and later make the POSIX ACL deduplication walk inspect data beyond
+the copied ACE boundary.
+
+The existing initial bound check is also too small. It only ensures
+that the ACE size field is accessible before set_ntacl_dacl() reads
+sid.num_subauth farther into the input buffer.
+
+Require enough input for the fixed SID header before accessing
+num_subauth, reject ACEs smaller than that header, and skip ACEs
+whose declared size cannot contain the complete SID. This makes the
+validation consistent with the other ACE walk paths.
+
+Reported-by: LocalHost <localhost.detect@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index b0677e095c3292..d3d0a22620f96d 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -743,15 +743,22 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ for (i = 0; i < nt_num_aces; i++) {
+ unsigned short nt_ace_size;
+
+- if (offsetof(struct smb_ace, access_req) > aces_size)
++ if (aces_size < offsetof(struct smb_ace, sid) +
++ CIFS_SID_BASE_SIZE)
+ break;
+
+ nt_ace_size = le16_to_cpu(ntace->size);
+- if (nt_ace_size > aces_size)
++ if (nt_ace_size > aces_size ||
++ nt_ace_size < offsetof(struct smb_ace, sid) +
++ CIFS_SID_BASE_SIZE)
+ break;
+
+ if (ntace->sid.num_subauth == 0 ||
+- ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES)
++ ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
++ nt_ace_size < offsetof(struct smb_ace, sid) +
++ CIFS_SID_BASE_SIZE +
++ sizeof(__le32) *
++ ntace->sid.num_subauth)
+ goto next_ace;
+
+ memcpy((char *)pndace + size, ntace, nt_ace_size);
+--
+2.53.0
+
--- /dev/null
+From 7ea8988d4f8530f73e1f589a9dfd0e31ed0557d4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:22 +0800
+Subject: ksmbd: validate num_subauth when copying ACE in set_ntacl_dacl
+
+From: Haofeng Li <lihaofeng@kylinos.cn>
+
+commit 47f0b34f6bc98ed85bfdc293e8f3e432ec24958d upstream.
+
+set_ntacl_dacl() copies each ACE from the attacker-controlled stored
+security descriptor verbatim into the response DACL without checking
+sid.num_subauth. The ACE bytes (including an unchecked num_subauth)
+originate from an authenticated SMB2_SET_INFO(SecInfo=DACL) that is
+stored raw via ksmbd_vfs_set_sd_xattr(); parse_dacl() rejects a bad ACE
+with `break` rather than an error, so parse_sec_desc() still returns
+success and the malformed SD reaches the xattr intact.
+
+On a subsequent SMB2_QUERY_INFO(SecInfo=DACL) for an inode carrying a
+POSIX access ACL, build_sec_desc() -> set_ntacl_dacl() ->
+set_posix_acl_entries_dacl() walks the copied ACEs and reads
+
+ ntace->sid.sub_auth[ntace->sid.num_subauth - 1]
+
+with num_subauth taken straight from the stored SD. Since sub_auth[]
+is fixed at SID_MAX_SUB_AUTHORITIES (15), a crafted num_subauth (e.g.
+255) drives an out-of-bounds heap read of ~1 KB with an offset fully
+controlled by an authenticated client.
+
+The sibling functions already gate this field:
+ parse_dacl() -- num_subauth == 0 || > SID_MAX_SUB_AUTHORITIES
+ parse_sid() -- num_subauth > SID_MAX_SUB_AUTHORITIES
+ smb_copy_sid() -- min_t(u8, num_subauth, SID_MAX_SUB_AUTHORITIES)
+set_ntacl_dacl() is the lone inconsistent path that omits the check.
+
+Add the same num_subauth validation in set_ntacl_dacl() before copying
+the ACE, matching the gate already enforced by parse_dacl().
+
+Signed-off-by: Haofeng Li <lihaofeng@kylinos.cn>
+Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
+Suggested-by: Namjae Jeon <linkinjeon@kernel.org>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index b09bc8d9389a2a..173469d112f101 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -745,12 +745,18 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ if (nt_ace_size > aces_size)
+ break;
+
++ if (ntace->sid.num_subauth == 0 ||
++ ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES)
++ goto next_ace;
++
+ memcpy((char *)pndace + size, ntace, nt_ace_size);
+ if (check_add_overflow(size, nt_ace_size, &size))
+ break;
++ num_aces++;
++
++next_ace:
+ aces_size -= nt_ace_size;
+ ntace = (struct smb_ace *)((char *)ntace + nt_ace_size);
+- num_aces++;
+ }
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 18d67bbb41d94a682b51e189b14ad14cc2dbf220 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 17:02:11 +0200
+Subject: net: qrtr: ns: Raise node count limit to 512
+
+From: Youssef Samir <youssef.abdulrahman@oss.qualcomm.com>
+
+commit ff194cffd586cbd4cc49eccb002c65f2a902a277 upstream.
+
+The current node limit of 64 breaks the functionality for a number of AI200
+deployments that have up to 384 nodes. Raise the limit to 512.
+
+Fixes: 27d5e84e810b ("net: qrtr: ns: Limit the total number of nodes")
+Cc: stable@vger.kernel.org
+Signed-off-by: Youssef Samir <youssef.abdulrahman@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260713145901.212396-1-youssef.abdulrahman@oss.qualcomm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/ns.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c
+index a10e8de4f7e105..e8e3ba1b3b8239 100644
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -85,9 +85,9 @@ struct qrtr_node {
+ /* Max nodes limit is chosen based on the current platform requirements.
+ * If the requirement changes in the future, this value can be increased.
+ */
+-#define QRTR_NS_MAX_NODES 64
++#define QRTR_NS_MAX_NODES 512
+
+-static u8 node_count;
++static u16 node_count;
+
+ static struct qrtr_node *node_get(unsigned int node_id)
+ {
+--
+2.53.0
+
drm-amdgpu-fix-aperture-mapping-leak.patch
drm-amd-pm-fix-smu13-power-limit-range-calculation.patch
drm-amdgpu-fix-check-in-amdgpu_hmm_invalidate_gfx.patch
+bpf-fix-same-register-dst-src-oob-read-and-pointer-l.patch
+dm-verity-fec-fix-the-size-of-dm_verity_fec_io-erasu.patch
+dm-verity-fec-fix-reading-parity-bytes-split-across-.patch
+dm-verity-fec-replace-max-min-_rsn-with-min-max-_roo.patch
+dm-verity-fix-buffer-overflow-in-fec-calculation.patch
+drm-xe-uapi-reject-coh_none-pat-index-for-cpu_addr_m.patch
+ublk-wait-on-ublk_dev_ready-instead-of-ub-completion.patch
+net-qrtr-ns-raise-node-count-limit-to-512.patch
+ksmbd-validate-num_subauth-when-copying-ace-in-set_n.patch
+ksmbd-restore-dacl-size-on-check_add_overflow-to-avo.patch
+ksmbd-bound-dacl-dedup-walk-to-copied-aces.patch
+ksmbd-validate-ace-size-against-sid-sub-authorities.patch
+fscrypt-avoid-dynamic-allocation-in-fscrypt_get_devi.patch
+drm-amd-display-fix-dtb-dto-updates-breaking-live-pi.patch
--- /dev/null
+From a6ec00fd3b4005da76c38cbcf2c9309f8ad59c2b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 09:48:06 -0500
+Subject: ublk: wait on ublk_dev_ready() instead of ub->completion
+
+From: Ming Lei <tom.leiming@gmail.com>
+
+commit 432a9b2780c0a01caf547bd1fc2fcf28aeb8d173 upstream.
+
+ub->completion is only re-armed by a successful START_USER_RECOVERY. If
+the ublk server sends END_USER_RECOVERY without one - e.g. its START
+failed with -EBUSY and the error was ignored - the wait is satisfied by
+the stale completion of the previous recovery cycle, and the device is
+marked LIVE and the requeue list kicked while the FETCH stream is still
+running and ubq->canceling is still set. The kick redispatches a
+previously requeued request, __ublk_queue_rq_common() sees ->canceling
+and parks it again via __ublk_abort_rq(), and after the last FETCH
+clears ->canceling nothing ever kicks the requeue list again: the
+request is stranded there while holding its tag. If it is the flush
+machinery's flush_rq, every subsequent fsync piles up in uninterruptible
+sleep and teardown hangs on tag draining. This matches a report of a
+lost PREFLUSH with ext4 on top of ublk after daemon crash recovery.
+
+ub->completion is an edge-triggered latch used as a proxy for the level
+condition "every queue has fetched all I/O commands", which can regress
+(F_BATCH's UNPREP, daemon death) and whose re-arm can be skipped. Drop
+it and wait on the real condition instead: the new helper
+ublk_wait_dev_ready_and_lock() waits on ublk_dev_ready() via
+wait_var_event_interruptible(), woken from ublk_mark_io_ready(), then
+re-checks it under ub->mutex, waiting again on regression, and returns
+with the mutex held and readiness guaranteed.
+
+Readiness becomes true in the same ub->mutex critical section that
+clears the last queue's ->canceling, so END_USER_RECOVERY marks the
+device LIVE and kicks the requeue list strictly after ->canceling
+clears. The wait stays interruptible, so a server whose daemon died can
+still be signalled out. For ublk_ctrl_start_dev() this replaces the
+fail-fast -EINVAL on an F_BATCH ready->UNPREP regression with waiting
+until the device is ready again.
+
+Reported-by: George Salisbury <gsalisbury@apnic.net>
+Fixes: 728cbac5fe21 ("ublk: move device reset into ublk_ch_release()")
+Cc: stable@vger.kernel.org
+Signed-off-by: Ming Lei <tom.leiming@gmail.com>
+Link: https://patch.msgid.link/20260719134540.120269-1-tom.leiming@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+
+[ 6.18.y tracks readiness per fetched I/O command in ->nr_io_ready rather
+ than per queue in ->nr_queue_ready, so wait and wake on that counter;
+ ->canceling is cleared by ublk_reset_io_flags(), which stays in
+ ublk_mark_io_ready(). UBLK_F_BATCH_IO does not exist here, so
+ ublk_ctrl_start_dev() has no F_BATCH readiness re-check to replace, and
+ readiness can only regress via ublk_reset_ch_dev() on daemon death. ]
+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/block/ublk_drv.c | 52 ++++++++++++++++++++++++++++------------
+ 1 file changed, 37 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
+index c339222513b03c..cb31e96f01cdd6 100644
+--- a/drivers/block/ublk_drv.c
++++ b/drivers/block/ublk_drv.c
+@@ -19,6 +19,7 @@
+ #include <linux/errno.h>
+ #include <linux/major.h>
+ #include <linux/wait.h>
++#include <linux/wait_bit.h>
+ #include <linux/blkdev.h>
+ #include <linux/init.h>
+ #include <linux/swap.h>
+@@ -26,7 +27,6 @@
+ #include <linux/compat.h>
+ #include <linux/mutex.h>
+ #include <linux/writeback.h>
+-#include <linux/completion.h>
+ #include <linux/highmem.h>
+ #include <linux/sysfs.h>
+ #include <linux/miscdevice.h>
+@@ -230,7 +230,6 @@ struct ublk_device {
+
+ struct ublk_params params;
+
+- struct completion completion;
+ u32 nr_io_ready;
+ bool unprivileged_daemons;
+ struct mutex cancel_mutex;
+@@ -2150,9 +2149,13 @@ static void ublk_mark_io_ready(struct ublk_device *ub)
+
+ ub->nr_io_ready++;
+ if (ublk_dev_ready(ub)) {
+- /* now we are ready for handling ublk io request */
++ /*
++ * now we are ready for handling ublk io request, clear
++ * device-level canceling flag and wake ublk_dev_ready()
++ * waiters
++ */
+ ublk_reset_io_flags(ub);
+- complete_all(&ub->completion);
++ wake_up_var(&ub->nr_io_ready);
+ }
+ }
+
+@@ -2829,7 +2832,6 @@ static int ublk_init_queues(struct ublk_device *ub)
+ goto fail;
+ }
+
+- init_completion(&ub->completion);
+ return 0;
+
+ fail:
+@@ -2966,6 +2968,26 @@ static bool ublk_validate_user_pid(struct ublk_device *ub, pid_t ublksrv_pid)
+ return ub->ublksrv_tgid == ublksrv_pid;
+ }
+
++/*
++ * Wait until all queues have fetched their I/O commands, and return with
++ * ub->mutex held and readiness guaranteed: then every queue's ->canceling
++ * is cleared. Ready may regress between wakeup and mutex_lock() (daemon
++ * death), so re-check it under the mutex and wait again.
++ */
++static int ublk_wait_dev_ready_and_lock(struct ublk_device *ub)
++{
++ while (true) {
++ if (wait_var_event_interruptible(&ub->nr_io_ready,
++ ublk_dev_ready(ub)))
++ return -EINTR;
++
++ mutex_lock(&ub->mutex);
++ if (ublk_dev_ready(ub))
++ return 0;
++ mutex_unlock(&ub->mutex);
++ }
++}
++
+ static int ublk_ctrl_start_dev(struct ublk_device *ub,
+ const struct ublksrv_ctrl_cmd *header)
+ {
+@@ -3031,13 +3053,13 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub,
+ lim.max_segments = ub->params.seg.max_segments;
+ }
+
+- if (wait_for_completion_interruptible(&ub->completion) != 0)
++ if (ublk_wait_dev_ready_and_lock(ub))
+ return -EINTR;
+
+- if (!ublk_validate_user_pid(ub, ublksrv_pid))
+- return -EINVAL;
+-
+- mutex_lock(&ub->mutex);
++ if (!ublk_validate_user_pid(ub, ublksrv_pid)) {
++ ret = -EINVAL;
++ goto out_unlock;
++ }
+ if (ub->dev_info.state == UBLK_S_DEV_LIVE ||
+ test_bit(UB_STATE_USED, &ub->state)) {
+ ret = -EEXIST;
+@@ -3549,7 +3571,6 @@ static int ublk_ctrl_start_recovery(struct ublk_device *ub,
+ goto out_unlock;
+ }
+ pr_devel("%s: start recovery for dev id %d.\n", __func__, header->dev_id);
+- init_completion(&ub->completion);
+ ret = 0;
+ out_unlock:
+ mutex_unlock(&ub->mutex);
+@@ -3565,16 +3586,17 @@ static int ublk_ctrl_end_recovery(struct ublk_device *ub,
+ pr_devel("%s: Waiting for all FETCH_REQs, dev id %d...\n", __func__,
+ header->dev_id);
+
+- if (wait_for_completion_interruptible(&ub->completion))
++ if (ublk_wait_dev_ready_and_lock(ub))
+ return -EINTR;
+
+ pr_devel("%s: All FETCH_REQs received, dev id %d\n", __func__,
+ header->dev_id);
+
+- if (!ublk_validate_user_pid(ub, ublksrv_pid))
+- return -EINVAL;
++ if (!ublk_validate_user_pid(ub, ublksrv_pid)) {
++ ret = -EINVAL;
++ goto out_unlock;
++ }
+
+- mutex_lock(&ub->mutex);
+ if (ublk_nosrv_should_stop_dev(ub))
+ goto out_unlock;
+
+--
+2.53.0
+
--- /dev/null
+From cd1ca230d9660cad7b34efb020f95b7f97ffe49a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 22:51:57 +0800
+Subject: bpf: drop bpf_lsm_getselfattr from hook list
+
+From: Wentao Guan <guanwentao@uniontech.com>
+
+Backport ("bpf, lsm: Add disabled BPF LSM hook list") for v6.6.y bring the
+warning "WARN: resolve_btfids: unresolved symbol bpf_lsm_getselfattr".
+
+The lsm_getselfattr from commit a04a1198088a
+("LSM: syscalls for current process attributes"), no need to backport
+the huge patch, simply drop the entry to fix the noise.
+
+This is a fix for stable v6.6.145 backport commit, so no upstream commit.
+
+Fixes: b3b4719429d5 ("bpf, lsm: Add disabled BPF LSM hook list")
+Link: https://lore.kernel.org/stable/20260728225520.stable-0003@kernel.org/
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/bpf_lsm.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
+index 147c3a8ad4e8e0..984e944a0221d9 100644
+--- a/kernel/bpf/bpf_lsm.c
++++ b/kernel/bpf/bpf_lsm.c
+@@ -42,7 +42,6 @@ BTF_ID(func, bpf_lsm_inode_need_killpriv)
+ BTF_ID(func, bpf_lsm_inode_getsecurity)
+ BTF_ID(func, bpf_lsm_inode_listsecurity)
+ BTF_ID(func, bpf_lsm_inode_copy_up_xattr)
+-BTF_ID(func, bpf_lsm_getselfattr)
+ BTF_ID(func, bpf_lsm_getprocattr)
+ BTF_ID(func, bpf_lsm_setprocattr)
+ #ifdef CONFIG_KEYS
+--
+2.53.0
+
--- /dev/null
+From 56bf217ba747159cefeccef17c74ca38e2523140 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 23:34:52 -0700
+Subject: drm/amd/display: Fix dcn32 DTB DTO update breaking live pixel rate
+ sources
+
+From: Harry Wentland <harry.wentland@amd.com>
+
+commit 76a2db58e95e328007043f54ac3c7336ccbee440 upstream.
+
+dcn32_update_clocks_update_dtb_dto() reprograms the DTB DTO of every
+timing generator in the context whenever the DTBCLK reference changes,
+passing a zeroed pixel rate and never setting is_hdmi.
+dccg32_set_dtbclk_dto() treats a zero pixel rate as a disable request,
+and that branch drives PIPE_DTO_SRC_SEL to the DP DTO source. A timing
+generator actively scanning out an HDMI stream therefore has its pixel
+rate source re-muxed out from under the live raster, and the OTG stops
+on the spot.
+
+Two displays where only one runs a 128b/132b link hit this reliably.
+is_dtbclk_required() holds the DTBCLK reference high while both are
+active, and the moment the 128b/132b stream is torn down (compositor
+switch, display disable, hot-unplug) the next safe_to_lower pass drops
+the reference to the lowest DPM level and the DTO walk freezes the
+surviving screen. On Navi31 the DAL mailbox then goes deaf on the
+DISPCLK hard-min that follows the walk in dcn32_update_clocks(),
+stranding both SMU mailboxes until reboot.
+
+Set is_hdmi for HDMI and DVI signals so the disable path leaves the
+pixel rate source selection on the HDMI path, and pass the real pixel
+rate for 128b/132b streams so a reference change rescales their DTO
+instead of disabling it.
+
+Fixes: 128c1ca0303f ("drm/amd/display: Update DTBCLK for DCN32")
+Signed-off-by: Harry Wentland <harry.wentland@amd.com>
+Reviewed-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
+Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+[ mschwartz: dcn32 clk_mgr hunk only, as 6.6.y predates the dcn35
+ clk_mgr. The rest is HDMI FRL enablement, absent before 7.2, so the
+ FRL conditions and the req_audio_dtbclk_khz assignment they guard are
+ dropped and the FRL-centric changelog is rewritten. Added the
+ pipe_ctx->stream check the new dereferences need. ]
+Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+index 1c5ae4d62e37b7..65344d0c7c10d2 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+@@ -255,13 +255,20 @@ static void dcn32_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
+ struct dtbclk_dto_params dto_params = {0};
+
+ /* use mask to program DTO once per tg */
+- if (pipe_ctx->stream_res.tg &&
++ if (pipe_ctx->stream && pipe_ctx->stream_res.tg &&
+ !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) {
+ tg_mask |= (1 << pipe_ctx->stream_res.tg->inst);
+
+ dto_params.otg_inst = pipe_ctx->stream_res.tg->inst;
+ dto_params.ref_dtbclk_khz = ref_dtbclk_khz;
+
++ if (dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))
++ dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
++
++ if (dc_is_hdmi_signal(pipe_ctx->stream->signal) ||
++ dc_is_dvi_signal(pipe_ctx->stream->signal))
++ dto_params.is_hdmi = true;
++
+ dccg->funcs->set_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ //dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ }
+--
+2.53.0
+
--- /dev/null
+From 7d72d3d196ecfb3fbf6c226afe2f16602710edef Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 20:49:38 +0000
+Subject: exfat: validate cluster allocation bits of the allocation bitmap
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 79c1587b6cda74deb0c86fc7ba194b92958c793c ]
+
+syzbot created an exfat image with cluster bits not set for the allocation
+bitmap. exfat-fs reads and uses the allocation bitmap without checking
+this. The problem is that if the start cluster of the allocation bitmap
+is 6, cluster 6 can be allocated when creating a directory with mkdir.
+exfat zeros out this cluster in exfat_mkdir, which can delete existing
+entries. This can reallocate the allocated entries. In addition,
+the allocation bitmap is also zeroed out, so cluster 6 can be reallocated.
+This patch adds exfat_test_bitmap_range to validate that clusters used for
+the allocation bitmap are correctly marked as in-use.
+
+Reported-by: syzbot+a725ab460fc1def9896f@syzkaller.appspotmail.com
+Tested-by: syzbot+a725ab460fc1def9896f@syzkaller.appspotmail.com
+Reviewed-by: Yuezhang Mo <Yuezhang.Mo@sony.com>
+Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+[Adapted to 6.6: replaced __le_long/lel_to_cpu word-level bitmap access
+ with per-bit test_bit_le() calls, as __le_long and lel_to_cpu do not
+ exist in 6.6. Uses same test_bit_le API as rest of exfat bitmap code.]
+Signed-off-by: Jay Wang <wanjay@amazon.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/exfat/balloc.c | 54 ++++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 42 insertions(+), 12 deletions(-)
+
+diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c
+index 32209acd51be4f..2d4fe3d754bbc5 100644
+--- a/fs/exfat/balloc.c
++++ b/fs/exfat/balloc.c
+@@ -45,12 +45,37 @@ static const unsigned char used_bit[] = {
+ /*
+ * Allocation Bitmap Management Functions
+ */
++static bool exfat_test_bitmap_range(struct super_block *sb, unsigned int clu,
++ unsigned int count)
++{
++ struct exfat_sb_info *sbi = EXFAT_SB(sb);
++ unsigned int start = clu;
++ unsigned int end = clu + count;
++ unsigned int ent_idx, i, b;
++
++ if (!is_valid_cluster(sbi, start) || !is_valid_cluster(sbi, end - 1))
++ return false;
++
++ while (start < end) {
++ ent_idx = CLUSTER_TO_BITMAP_ENT(start);
++ i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
++ b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
++
++ if (!test_bit_le(b, sbi->vol_amap[i]->b_data))
++ return false;
++
++ start++;
++ }
++
++ return true;
++}
++
+ static int exfat_allocate_bitmap(struct super_block *sb,
+ struct exfat_dentry *ep)
+ {
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ long long map_size;
+- unsigned int i, need_map_size;
++ unsigned int i, j, need_map_size;
+ sector_t sector;
+
+ sbi->map_clu = le32_to_cpu(ep->dentry.bitmap.start_clu);
+@@ -77,20 +102,25 @@ static int exfat_allocate_bitmap(struct super_block *sb,
+ sector = exfat_cluster_to_sector(sbi, sbi->map_clu);
+ for (i = 0; i < sbi->map_sectors; i++) {
+ sbi->vol_amap[i] = sb_bread(sb, sector + i);
+- if (!sbi->vol_amap[i]) {
+- /* release all buffers and free vol_amap */
+- int j = 0;
+-
+- while (j < i)
+- brelse(sbi->vol_amap[j++]);
+-
+- kvfree(sbi->vol_amap);
+- sbi->vol_amap = NULL;
+- return -EIO;
+- }
++ if (!sbi->vol_amap[i])
++ goto err_out;
+ }
+
++ if (exfat_test_bitmap_range(sb, sbi->map_clu,
++ EXFAT_B_TO_CLU_ROUND_UP(map_size, sbi)) == false)
++ goto err_out;
++
+ return 0;
++
++err_out:
++ j = 0;
++ /* release all buffers and free vol_amap */
++ while (j < i)
++ brelse(sbi->vol_amap[j++]);
++
++ kvfree(sbi->vol_amap);
++ sbi->vol_amap = NULL;
++ return -EIO;
+ }
+
+ int exfat_load_bitmap(struct super_block *sb)
+--
+2.53.0
+
--- /dev/null
+From 82bbfd4286c9a388cf4faef124a349bfe147b994 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 08:25:39 -0700
+Subject: fscrypt: Avoid dynamic allocation in fscrypt_get_devices()
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 6fe4e4b8259e1330945b5f3c9476e08473b8e0e8 upstream.
+
+When a blk_crypto_key starts being used or is evicted, fs/crypto/ calls
+fscrypt_get_devices() to get the filesystem's list of block devices,
+then iterates over them and calls blk_crypto_config_supported(),
+blk_crypto_start_using_key(), or blk_crypto_evict_key() on each one.
+
+Currently, the block device pointers are placed in a dynamically
+allocated array. This dynamic allocation is problematic because:
+
+- It can fail, especially at the fscrypt_destroy_inline_crypt_key() call
+ site when it's invoked for inode eviction under direct reclaim.
+
+- fscrypt_destroy_inline_crypt_key() doesn't handle the failure. It
+ just zeroizes and frees the blk_crypto_key without calling
+ blk_crypto_evict_key(). That causes a use-after-free.
+
+For now, let's fix this in the straightforward and easily-backportable
+way by switching to an on-stack array. Currently the fscrypt
+multi-device functionality is used only by f2fs, which has a hardcoded
+limit of 8 block devices. An on-stack array works fine for that.
+
+(Of course, this solution won't scale up to large number of block
+devices. For that we'd need a different solution, like moving the block
+device iteration into the filesystem. Or in the case of btrfs, which
+will only support blk-crypto-fallback, we should make it just call
+blk-crypto-fallback directly, so the block devices won't be needed.)
+
+Fixes: 22e9947a4b2b ("fscrypt: stop holding extra request_queue references")
+Cc: stable@vger.kernel.org
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Closes: https://sashiko.dev/#/patchset/20260713023708.9245-1-ebiggers%40kernel.org
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Link: https://patch.msgid.link/20260719055602.78828-1-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/crypto/inline_crypt.c | 57 ++++++++++++++--------------------------
+ fs/f2fs/super.c | 25 ++++++++++--------
+ include/linux/fscrypt.h | 18 +++++++------
+ 3 files changed, 44 insertions(+), 56 deletions(-)
+
+diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
+index 8bfb3ce864766e..47645c5539bc84 100644
+--- a/fs/crypto/inline_crypt.c
++++ b/fs/crypto/inline_crypt.c
+@@ -21,22 +21,14 @@
+
+ #include "fscrypt_private.h"
+
+-static struct block_device **fscrypt_get_devices(struct super_block *sb,
+- unsigned int *num_devs)
++static unsigned int
++fscrypt_get_devices(struct super_block *sb,
++ struct block_device *devs[FSCRYPT_MAX_DEVICES])
+ {
+- struct block_device **devs;
+-
+- if (sb->s_cop->get_devices) {
+- devs = sb->s_cop->get_devices(sb, num_devs);
+- if (devs)
+- return devs;
+- }
+- devs = kmalloc(sizeof(*devs), GFP_KERNEL);
+- if (!devs)
+- return ERR_PTR(-ENOMEM);
++ if (sb->s_cop->get_devices)
++ return sb->s_cop->get_devices(sb, devs);
+ devs[0] = sb->s_bdev;
+- *num_devs = 1;
+- return devs;
++ return 1;
+ }
+
+ static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_info *ci)
+@@ -95,7 +87,7 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci)
+ const struct inode *inode = ci->ci_inode;
+ struct super_block *sb = inode->i_sb;
+ struct blk_crypto_config crypto_cfg;
+- struct block_device **devs;
++ struct block_device *devs[FSCRYPT_MAX_DEVICES];
+ unsigned int num_devs;
+ unsigned int i;
+
+@@ -132,20 +124,15 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci)
+ crypto_cfg.data_unit_size = sb->s_blocksize;
+ crypto_cfg.dun_bytes = fscrypt_get_dun_bytes(ci);
+
+- devs = fscrypt_get_devices(sb, &num_devs);
+- if (IS_ERR(devs))
+- return PTR_ERR(devs);
+-
++ num_devs = fscrypt_get_devices(sb, devs);
+ for (i = 0; i < num_devs; i++) {
+ if (!blk_crypto_config_supported(devs[i], &crypto_cfg))
+- goto out_free_devs;
++ return 0;
+ }
+
+ fscrypt_log_blk_crypto_impl(ci->ci_mode, devs, num_devs, &crypto_cfg);
+
+ ci->ci_inlinecrypt = true;
+-out_free_devs:
+- kfree(devs);
+
+ return 0;
+ }
+@@ -158,7 +145,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
+ struct super_block *sb = inode->i_sb;
+ enum blk_crypto_mode_num crypto_mode = ci->ci_mode->blk_crypto_mode;
+ struct blk_crypto_key *blk_key;
+- struct block_device **devs;
++ struct block_device *devs[FSCRYPT_MAX_DEVICES];
+ unsigned int num_devs;
+ unsigned int i;
+ int err;
+@@ -175,17 +162,12 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
+ }
+
+ /* Start using blk-crypto on all the filesystem's block devices. */
+- devs = fscrypt_get_devices(sb, &num_devs);
+- if (IS_ERR(devs)) {
+- err = PTR_ERR(devs);
+- goto fail;
+- }
++ num_devs = fscrypt_get_devices(sb, devs);
+ for (i = 0; i < num_devs; i++) {
+ err = blk_crypto_start_using_key(devs[i], blk_key);
+ if (err)
+ break;
+ }
+- kfree(devs);
+ if (err) {
+ fscrypt_err(inode, "error %d starting to use blk-crypto", err);
+ goto fail;
+@@ -209,20 +191,21 @@ void fscrypt_destroy_inline_crypt_key(struct super_block *sb,
+ struct fscrypt_prepared_key *prep_key)
+ {
+ struct blk_crypto_key *blk_key = prep_key->blk_key;
+- struct block_device **devs;
++ struct block_device *devs[FSCRYPT_MAX_DEVICES];
+ unsigned int num_devs;
+ unsigned int i;
+
+ if (!blk_key)
+ return;
+
+- /* Evict the key from all the filesystem's block devices. */
+- devs = fscrypt_get_devices(sb, &num_devs);
+- if (!IS_ERR(devs)) {
+- for (i = 0; i < num_devs; i++)
+- blk_crypto_evict_key(devs[i], blk_key);
+- kfree(devs);
+- }
++ /*
++ * Evict the key from all the filesystem's block devices.
++ * This *must* be done before the key is freed.
++ */
++ num_devs = fscrypt_get_devices(sb, devs);
++ for (i = 0; i < num_devs; i++)
++ blk_crypto_evict_key(devs[i], blk_key);
++
+ kfree_sensitive(blk_key);
+ }
+
+diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
+index c018d548e16348..95adc2c4c3c087 100644
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -3248,24 +3248,27 @@ static void f2fs_get_ino_and_lblk_bits(struct super_block *sb,
+ *lblk_bits_ret = 8 * sizeof(block_t);
+ }
+
+-static struct block_device **f2fs_get_devices(struct super_block *sb,
+- unsigned int *num_devs)
++static unsigned int
++f2fs_get_devices(struct super_block *sb,
++ struct block_device *devs[FSCRYPT_MAX_DEVICES])
+ {
+ struct f2fs_sb_info *sbi = F2FS_SB(sb);
+- struct block_device **devs;
++ int ndevs;
+ int i;
+
+- if (!f2fs_is_multi_device(sbi))
+- return NULL;
++ static_assert(MAX_DEVICES <= FSCRYPT_MAX_DEVICES);
+
+- devs = kmalloc_array(sbi->s_ndevs, sizeof(*devs), GFP_KERNEL);
+- if (!devs)
+- return ERR_PTR(-ENOMEM);
++ if (!f2fs_is_multi_device(sbi)) {
++ devs[0] = sb->s_bdev;
++ return 1;
++ }
++ ndevs = sbi->s_ndevs;
++ if (WARN_ON_ONCE(ndevs > FSCRYPT_MAX_DEVICES))
++ ndevs = FSCRYPT_MAX_DEVICES;
+
+- for (i = 0; i < sbi->s_ndevs; i++)
++ for (i = 0; i < ndevs; i++)
+ devs[i] = FDEV(i).bdev;
+- *num_devs = sbi->s_ndevs;
+- return devs;
++ return ndevs;
+ }
+
+ static const struct fscrypt_operations f2fs_cryptops = {
+diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
+index c895b12737a193..e55ba9f1e38398 100644
+--- a/include/linux/fscrypt.h
++++ b/include/linux/fscrypt.h
+@@ -57,6 +57,9 @@ struct fscrypt_name {
+ /* Maximum value for the third parameter of fscrypt_operations.set_context(). */
+ #define FSCRYPT_SET_CONTEXT_MAX_SIZE 40
+
++/* Maximum supported number of block devices per filesystem */
++#define FSCRYPT_MAX_DEVICES 8
++
+ #ifdef CONFIG_FS_ENCRYPTION
+
+ /*
+@@ -161,21 +164,20 @@ struct fscrypt_operations {
+ int *ino_bits_ret, int *lblk_bits_ret);
+
+ /*
+- * Return an array of pointers to the block devices to which the
+- * filesystem may write encrypted file contents, NULL if the filesystem
+- * only has a single such block device, or an ERR_PTR() on error.
++ * Retrieve the list of block devices to which the filesystem may write
++ * encrypted file contents.
+ *
+- * On successful non-NULL return, *num_devs is set to the number of
+- * devices in the returned array. The caller must free the returned
+- * array using kfree().
++ * This writes the block_device pointers to @devs and returns the count
++ * (between 1 and FSCRYPT_MAX_DEVICES inclusively).
+ *
+ * If the filesystem can use multiple block devices (other than block
+ * devices that aren't used for encrypted file contents, such as
+ * external journal devices), and wants to support inline encryption,
+ * then it must implement this function. Otherwise it's not needed.
+ */
+- struct block_device **(*get_devices)(struct super_block *sb,
+- unsigned int *num_devs);
++ unsigned int (*get_devices)(
++ struct super_block *sb,
++ struct block_device *devs[FSCRYPT_MAX_DEVICES]);
+ };
+
+ static inline struct fscrypt_info *fscrypt_get_info(const struct inode *inode)
+--
+2.53.0
+
--- /dev/null
+From 675b9cae644aa0ce18e99b2ecd989911ce957023 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 21:07:15 +0000
+Subject: i40e: remove read access to debugfs files
+
+From: Jacob Keller <jacob.e.keller@intel.com>
+
+[ Upstream commit 9fcdb1c3c4ba134434694c001dbff343f1ffa319 ]
+
+The 'command' and 'netdev_ops' debugfs files are a legacy debugging
+interface supported by the i40e driver since its early days by commit
+02e9c290814c ("i40e: debugfs interface").
+
+Both of these debugfs files provide a read handler which is mostly useless,
+and which is implemented with questionable logic. They both use a static
+256 byte buffer which is initialized to the empty string. In the case of
+the 'command' file this buffer is literally never used and simply wastes
+space. In the case of the 'netdev_ops' file, the last command written is
+saved here.
+
+On read, the files contents are presented as the name of the device
+followed by a colon and then the contents of their respective static
+buffer. For 'command' this will always be "<device>: ". For 'netdev_ops',
+this will be "<device>: <last command written>". But note the buffer is
+shared between all devices operated by this module. At best, it is mostly
+meaningless information, and at worse it could be accessed simultaneously
+as there doesn't appear to be any locking mechanism.
+
+We have also recently received multiple reports for both read functions
+about their use of snprintf and potential overflow that could result in
+reading arbitrary kernel memory. For the 'command' file, this is
+definitely impossible, since the static buffer is always zero and never
+written to. For the 'netdev_ops' file, it does appear to be possible, if
+the user carefully crafts the command input, it will be copied into the
+buffer, which could be large enough to cause snprintf to truncate, which
+then causes the copy_to_user to read beyond the length of the buffer
+allocated by kzalloc.
+
+A minimal fix would be to replace snprintf() with scnprintf() which would
+cap the return to the number of bytes written, preventing an overflow. A
+more involved fix would be to drop the mostly useless static buffers,
+saving 512 bytes and modifying the read functions to stop needing those as
+input.
+
+Instead, lets just completely drop the read access to these files. These
+are debug interfaces exposed as part of debugfs, and I don't believe that
+dropping read access will break any script, as the provided output is
+pretty useless. You can find the netdev name through other more standard
+interfaces, and the 'netdev_ops' interface can easily result in garbage if
+you issue simultaneous writes to multiple devices at once.
+
+In order to properly remove the i40e_dbg_netdev_ops_buf, we need to
+refactor its write function to avoid using the static buffer. Instead, use
+the same logic as the i40e_dbg_command_write, with an allocated buffer.
+Update the code to use this instead of the static buffer, and ensure we
+free the buffer on exit. This fixes simultaneous writes to 'netdev_ops' on
+multiple devices, and allows us to remove the now unused static buffer
+along with removing the read access.
+
+Fixes: 02e9c290814c ("i40e: debugfs interface")
+Reported-by: Kunwu Chan <chentao@kylinos.cn>
+Closes: https://lore.kernel.org/intel-wired-lan/20231208031950.47410-1-chentao@kylinos.cn/
+Reported-by: Wang Haoran <haoranwangsec@gmail.com>
+Closes: https://lore.kernel.org/all/CANZ3JQRRiOdtfQJoP9QM=6LS1Jto8PGBGw6y7-TL=BcnzHQn1Q@mail.gmail.com/
+Reported-by: Amir Mohammad Jahangirzad <a.jahangirzad@gmail.com>
+Closes: https://lore.kernel.org/all/20250722115017.206969-1-a.jahangirzad@gmail.com/
+Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
+Reviewed-by: Dawid Osuchowski <dawid.osuchowski@linux.intel.com>
+Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Reviewed-by: Kunwu Chan <kunwu.chan@linux.dev>
+Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+[Adapted to 6.6: context conflict due to 6.6 using pf->vsi[pf->lan_vsi]
+ vs i40e_pf_get_main_vsi(pf) in the removed read functions; resolution
+ is simply to delete the 6.6 version of those functions.]
+Signed-off-by: Jay Wang <wanjay@amazon.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/intel/i40e/i40e_debugfs.c | 121 +++---------------
+ 1 file changed, 19 insertions(+), 102 deletions(-)
+
+diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+index a2fca58a91c332..35ce578dd6f350 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
++++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+@@ -58,47 +58,6 @@ static struct i40e_veb *i40e_dbg_find_veb(struct i40e_pf *pf, int seid)
+ * setup, adding or removing filters, or other things. Many of
+ * these will be useful for some forms of unit testing.
+ **************************************************************/
+-static char i40e_dbg_command_buf[256] = "";
+-
+-/**
+- * i40e_dbg_command_read - read for command datum
+- * @filp: the opened file
+- * @buffer: where to write the data for the user to read
+- * @count: the size of the user's buffer
+- * @ppos: file position offset
+- **/
+-static ssize_t i40e_dbg_command_read(struct file *filp, char __user *buffer,
+- size_t count, loff_t *ppos)
+-{
+- struct i40e_pf *pf = filp->private_data;
+- int bytes_not_copied;
+- int buf_size = 256;
+- char *buf;
+- int len;
+-
+- /* don't allow partial reads */
+- if (*ppos != 0)
+- return 0;
+- if (count < buf_size)
+- return -ENOSPC;
+-
+- buf = kzalloc(buf_size, GFP_KERNEL);
+- if (!buf)
+- return -ENOSPC;
+-
+- len = snprintf(buf, buf_size, "%s: %s\n",
+- pf->vsi[pf->lan_vsi]->netdev->name,
+- i40e_dbg_command_buf);
+-
+- bytes_not_copied = copy_to_user(buffer, buf, len);
+- kfree(buf);
+-
+- if (bytes_not_copied)
+- return -EFAULT;
+-
+- *ppos = len;
+- return len;
+-}
+
+ static char *i40e_filter_state_string[] = {
+ "INVALID",
+@@ -1637,7 +1596,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
+ static const struct file_operations i40e_dbg_command_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+- .read = i40e_dbg_command_read,
+ .write = i40e_dbg_command_write,
+ };
+
+@@ -1646,47 +1604,6 @@ static const struct file_operations i40e_dbg_command_fops = {
+ * The netdev_ops entry in debugfs is for giving the driver commands
+ * to be executed from the netdev operations.
+ **************************************************************/
+-static char i40e_dbg_netdev_ops_buf[256] = "";
+-
+-/**
+- * i40e_dbg_netdev_ops_read - read for netdev_ops datum
+- * @filp: the opened file
+- * @buffer: where to write the data for the user to read
+- * @count: the size of the user's buffer
+- * @ppos: file position offset
+- **/
+-static ssize_t i40e_dbg_netdev_ops_read(struct file *filp, char __user *buffer,
+- size_t count, loff_t *ppos)
+-{
+- struct i40e_pf *pf = filp->private_data;
+- int bytes_not_copied;
+- int buf_size = 256;
+- char *buf;
+- int len;
+-
+- /* don't allow partal reads */
+- if (*ppos != 0)
+- return 0;
+- if (count < buf_size)
+- return -ENOSPC;
+-
+- buf = kzalloc(buf_size, GFP_KERNEL);
+- if (!buf)
+- return -ENOSPC;
+-
+- len = snprintf(buf, buf_size, "%s: %s\n",
+- pf->vsi[pf->lan_vsi]->netdev->name,
+- i40e_dbg_netdev_ops_buf);
+-
+- bytes_not_copied = copy_to_user(buffer, buf, len);
+- kfree(buf);
+-
+- if (bytes_not_copied)
+- return -EFAULT;
+-
+- *ppos = len;
+- return len;
+-}
+
+ /**
+ * i40e_dbg_netdev_ops_write - write into netdev_ops datum
+@@ -1700,35 +1617,36 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
+ size_t count, loff_t *ppos)
+ {
+ struct i40e_pf *pf = filp->private_data;
++ char *cmd_buf, *buf_tmp;
+ int bytes_not_copied;
+ struct i40e_vsi *vsi;
+- char *buf_tmp;
+ int vsi_seid;
+ int i, cnt;
+
+ /* don't allow partial writes */
+ if (*ppos != 0)
+ return 0;
+- if (count >= sizeof(i40e_dbg_netdev_ops_buf))
+- return -ENOSPC;
+
+- memset(i40e_dbg_netdev_ops_buf, 0, sizeof(i40e_dbg_netdev_ops_buf));
+- bytes_not_copied = copy_from_user(i40e_dbg_netdev_ops_buf,
+- buffer, count);
+- if (bytes_not_copied)
++ cmd_buf = kzalloc(count + 1, GFP_KERNEL);
++ if (!cmd_buf)
++ return count;
++ bytes_not_copied = copy_from_user(cmd_buf, buffer, count);
++ if (bytes_not_copied) {
++ kfree(cmd_buf);
+ return -EFAULT;
+- i40e_dbg_netdev_ops_buf[count] = '\0';
++ }
++ cmd_buf[count] = '\0';
+
+- buf_tmp = strchr(i40e_dbg_netdev_ops_buf, '\n');
++ buf_tmp = strchr(cmd_buf, '\n');
+ if (buf_tmp) {
+ *buf_tmp = '\0';
+- count = buf_tmp - i40e_dbg_netdev_ops_buf + 1;
++ count = buf_tmp - cmd_buf + 1;
+ }
+
+- if (strncmp(i40e_dbg_netdev_ops_buf, "change_mtu", 10) == 0) {
++ if (strncmp(cmd_buf, "change_mtu", 10) == 0) {
+ int mtu;
+
+- cnt = sscanf(&i40e_dbg_netdev_ops_buf[11], "%i %i",
++ cnt = sscanf(&cmd_buf[11], "%i %i",
+ &vsi_seid, &mtu);
+ if (cnt != 2) {
+ dev_info(&pf->pdev->dev, "change_mtu <vsi_seid> <mtu>\n");
+@@ -1750,8 +1668,8 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
+ dev_info(&pf->pdev->dev, "Could not acquire RTNL - please try again\n");
+ }
+
+- } else if (strncmp(i40e_dbg_netdev_ops_buf, "set_rx_mode", 11) == 0) {
+- cnt = sscanf(&i40e_dbg_netdev_ops_buf[11], "%i", &vsi_seid);
++ } else if (strncmp(cmd_buf, "set_rx_mode", 11) == 0) {
++ cnt = sscanf(&cmd_buf[11], "%i", &vsi_seid);
+ if (cnt != 1) {
+ dev_info(&pf->pdev->dev, "set_rx_mode <vsi_seid>\n");
+ goto netdev_ops_write_done;
+@@ -1771,8 +1689,8 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
+ dev_info(&pf->pdev->dev, "Could not acquire RTNL - please try again\n");
+ }
+
+- } else if (strncmp(i40e_dbg_netdev_ops_buf, "napi", 4) == 0) {
+- cnt = sscanf(&i40e_dbg_netdev_ops_buf[4], "%i", &vsi_seid);
++ } else if (strncmp(cmd_buf, "napi", 4) == 0) {
++ cnt = sscanf(&cmd_buf[4], "%i", &vsi_seid);
+ if (cnt != 1) {
+ dev_info(&pf->pdev->dev, "napi <vsi_seid>\n");
+ goto netdev_ops_write_done;
+@@ -1790,21 +1708,20 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
+ dev_info(&pf->pdev->dev, "napi called\n");
+ }
+ } else {
+- dev_info(&pf->pdev->dev, "unknown command '%s'\n",
+- i40e_dbg_netdev_ops_buf);
++ dev_info(&pf->pdev->dev, "unknown command '%s'\n", cmd_buf);
+ dev_info(&pf->pdev->dev, "available commands\n");
+ dev_info(&pf->pdev->dev, " change_mtu <vsi_seid> <mtu>\n");
+ dev_info(&pf->pdev->dev, " set_rx_mode <vsi_seid>\n");
+ dev_info(&pf->pdev->dev, " napi <vsi_seid>\n");
+ }
+ netdev_ops_write_done:
++ kfree(cmd_buf);
+ return count;
+ }
+
+ static const struct file_operations i40e_dbg_netdev_ops_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+- .read = i40e_dbg_netdev_ops_read,
+ .write = i40e_dbg_netdev_ops_write,
+ };
+
+--
+2.53.0
+
--- /dev/null
+From f2ae29fc341747d7cbe529eb045dc4ae7744dcb4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Jul 2026 20:45:51 +0800
+Subject: io_uring/rw: fix missing ERESTARTSYS conversion in read paths
+
+From: Yitang Yang <yi1tang.yang@gmail.com>
+
+commit ab05caca123c6d0b41850b7c05b246e4dca4a770 upstream.
+
+Both read and write may receive internal restart error codes from
+the filesystem layer and should be converted to -EINTR. However,
+when multishot read support was added, the error code normalization
+was lost for both io_read() and io_read_mshot().
+
+Extract the conversion into io_fixup_restart_res() and apply it
+in all three locations: io_rw_done(), io_read(), and io_read_mshot().
+
+[ 6.6 doesn't have multishot read, drop the io_read_mshot() hunk and
+ adapt io_rw_done() to the older calling convention ]
+
+Fixes: a08d195b586a ("io_uring/rw: split io_read() into a helper")
+Cc: stable@vger.kernel.org
+Signed-off-by: Yitang Yang <yi1tang.yang@gmail.com>
+Link: https://patch.msgid.link/20260722124551.130563-1-yi1tang.yang@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ io_uring/rw.c | 28 +++++++++++++++++++---------
+ 1 file changed, 19 insertions(+), 9 deletions(-)
+
+diff --git a/io_uring/rw.c b/io_uring/rw.c
+index 4ff3442ac2eeea..f2ab967b95072a 100644
+--- a/io_uring/rw.c
++++ b/io_uring/rw.c
+@@ -140,27 +140,37 @@ void io_readv_writev_cleanup(struct io_kiocb *req)
+ kfree(io->free_iovec);
+ }
+
+-static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret)
++static inline ssize_t io_fixup_restart_res(ssize_t ret)
+ {
+ switch (ret) {
+- case -EIOCBQUEUED:
+- break;
+ case -ERESTARTSYS:
+ case -ERESTARTNOINTR:
+ case -ERESTARTNOHAND:
+ case -ERESTART_RESTARTBLOCK:
+ /*
+ * We can't just restart the syscall, since previously
+- * submitted sqes may already be in progress. Just fail this
+- * IO with EINTR.
++ * submitted sqes may already be in progress. Just fail
++ * this IO with EINTR.
+ */
+- ret = -EINTR;
+- fallthrough;
++ return -EINTR;
+ default:
+- kiocb->ki_complete(kiocb, ret);
++ return ret;
+ }
+ }
+
++static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret)
++{
++ /* IO was queued async, completion will happen later */
++ if (ret == -EIOCBQUEUED)
++ return;
++
++ /* transform internal restart error codes */
++ if (unlikely(ret < 0))
++ ret = io_fixup_restart_res(ret);
++
++ kiocb->ki_complete(kiocb, ret);
++}
++
+ static inline loff_t *io_kiocb_update_pos(struct io_kiocb *req)
+ {
+ struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
+@@ -885,7 +895,7 @@ int io_read(struct io_kiocb *req, unsigned int issue_flags)
+ if (ret >= 0)
+ return kiocb_done(req, ret, issue_flags);
+
+- return ret;
++ return io_fixup_restart_res(ret);
+ }
+
+ static bool io_kiocb_start_write(struct io_kiocb *req, struct kiocb *kiocb)
+--
+2.53.0
+
--- /dev/null
+From 11af4fe2e0d42d45b8b9784936c18c66b862bf09 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 12:08:56 +0300
+Subject: ipv6: ndisc: fix NULL deref in accept_untracked_na()
+
+From: Weiming Shi <bestswngs@gmail.com>
+
+commit d186e942365acece7c56d39da05dd63bf95b280a upstream.
+
+accept_untracked_na() re-fetches the inet6_dev with __in6_dev_get(dev)
+and dereferences idev->cnf.accept_untracked_na without a NULL check,
+even though its only caller ndisc_recv_na() already fetched and
+NULL-checked idev for the same device.
+
+Both reads of dev->ip6_ptr run in the same RCU read-side critical
+section, but a concurrent addrconf_ifdown() can clear dev->ip6_ptr
+between them: lowering the MTU below IPV6_MIN_MTU calls addrconf_ifdown()
+without the synchronize_net() that orders the unregister path, so the
+re-fetch returns NULL and oopses:
+
+ BUG: KASAN: null-ptr-deref in ndisc_recv_na (net/ipv6/ndisc.c:974)
+ Read of size 4 at addr 0000000000000364
+ Call Trace:
+ <IRQ>
+ ndisc_recv_na (net/ipv6/ndisc.c:974)
+ icmpv6_rcv (net/ipv6/icmp.c:1193)
+ ip6_protocol_deliver_rcu (net/ipv6/ip6_input.c:479)
+ ip6_input_finish (net/ipv6/ip6_input.c:534)
+ ip6_input (net/ipv6/ip6_input.c:545)
+ ip6_mc_input (net/ipv6/ip6_input.c:635)
+ ipv6_rcv (net/ipv6/ip6_input.c:351)
+ </IRQ>
+
+It is reachable by an unprivileged user via a network namespace.
+
+Pass the caller's already validated idev instead of re-fetching it; the
+idev stays alive for the whole RCU critical section, so it is safe even
+after dev->ip6_ptr has been cleared.
+
+Fixes: aaa5f515b16b ("net: ipv6: new accept_untracked_na option to accept na only if in-network")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Weiming Shi <bestswngs@gmail.com>
+Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Link: https://patch.msgid.link/20260617065512.2529757-2-bestswngs@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Alexander Martyniuk <alexevgmart@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ndisc.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
+index ee34831f5621a8..342e7066f765f5 100644
+--- a/net/ipv6/ndisc.c
++++ b/net/ipv6/ndisc.c
+@@ -973,10 +973,8 @@ static enum skb_drop_reason ndisc_recv_ns(struct sk_buff *skb)
+ return reason;
+ }
+
+-static int accept_untracked_na(struct net_device *dev, struct in6_addr *saddr)
++static int accept_untracked_na(struct inet6_dev *idev, struct in6_addr *saddr)
+ {
+- struct inet6_dev *idev = __in6_dev_get(dev);
+-
+ switch (READ_ONCE(idev->cnf.accept_untracked_na)) {
+ case 0: /* Don't accept untracked na (absent in neighbor cache) */
+ return 0;
+@@ -986,7 +984,7 @@ static int accept_untracked_na(struct net_device *dev, struct in6_addr *saddr)
+ * same subnet as an address configured on the interface that
+ * received the na
+ */
+- return !!ipv6_chk_prefix(saddr, dev);
++ return !!ipv6_chk_prefix(saddr, idev->dev);
+ default:
+ return 0;
+ }
+@@ -1085,7 +1083,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
+ */
+ new_state = msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE;
+ if (!neigh && lladdr && idev && idev->cnf.forwarding) {
+- if (accept_untracked_na(dev, saddr)) {
++ if (accept_untracked_na(idev, saddr)) {
+ neigh = neigh_create(&nd_tbl, &msg->target, dev);
+ new_state = NUD_STALE;
+ }
+--
+2.53.0
+
--- /dev/null
+From 1ad49c043b94f05bad5a928d08c3ff8a77661733 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:26 +0800
+Subject: ksmbd: bound DACL dedup walk to copied ACEs
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+commit 58d97fcd0bf1aee694e244cc28635b9df95b543b upstream.
+
+set_ntacl_dacl() can stop copying ACEs before consuming the full input
+DACL when size accounting overflows.
+
+When that happens, num_aces reflects only the ACEs that were actually
+copied into the output DACL, but set_posix_acl_entries_dacl() still
+receives nt_num_aces and uses it to walk the existing ACE array during
+dedup.
+
+That makes the dedup walk scan past the copied ACE array and inspect
+buffer tail that does not contain valid ACEs.
+
+Split the two meanings currently carried by the NT ACE count. Pass the
+number of copied NT ACEs to bound the dedup walk, and preserve the
+original "input DACL had NT ACEs" state separately for the
+Everyone/default ACL fallback.
+
+This keeps the dedup walk aligned with the ACEs that are actually
+present in the rebuilt DACL.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index 3f0f1d9c98d1b7..3cd0d1e1ddc224 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -595,7 +595,8 @@ static void parse_dacl(struct mnt_idmap *idmap,
+ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ struct smb_ace *pndace,
+ struct smb_fattr *fattr, u16 *num_aces,
+- u16 *size, u32 nt_aces_num)
++ u16 *size, u16 existing_nt_aces,
++ bool had_nt_aces)
+ {
+ struct posix_acl_entry *pace;
+ struct smb_sid *sid;
+@@ -627,14 +628,14 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+
+ gid = posix_acl_gid_translate(idmap, pace);
+ id_to_sid(gid, SIDUNIX_GROUP, sid);
+- } else if (pace->e_tag == ACL_OTHER && !nt_aces_num) {
++ } else if (pace->e_tag == ACL_OTHER && !had_nt_aces) {
+ smb_copy_sid(sid, &sid_everyone);
+ } else {
+ kfree(sid);
+ continue;
+ }
+ ntace = pndace;
+- for (j = 0; j < nt_aces_num; j++) {
++ for (j = 0; j < existing_nt_aces; j++) {
+ if (ntace->sid.sub_auth[ntace->sid.num_subauth - 1] ==
+ sid->sub_auth[sid->num_subauth - 1])
+ goto pass_same_sid;
+@@ -678,7 +679,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ kfree(sid);
+ }
+
+- if (nt_aces_num)
++ if (had_nt_aces)
+ return;
+
+ posix_default_acl:
+@@ -732,6 +733,7 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ {
+ struct smb_ace *ntace, *pndace;
+ u16 nt_num_aces = le16_to_cpu(nt_dacl->num_aces), num_aces = 0;
++ u16 copied_nt_aces;
+ unsigned short size = 0;
+ int i;
+
+@@ -765,8 +767,10 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ }
+ }
+
++ copied_nt_aces = num_aces;
+ set_posix_acl_entries_dacl(idmap, pndace, fattr,
+- &num_aces, &size, nt_num_aces);
++ &num_aces, &size, copied_nt_aces,
++ nt_num_aces != 0);
+ pndacl->num_aces = cpu_to_le16(num_aces);
+ pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
+ }
+@@ -784,7 +788,7 @@ static void set_mode_dacl(struct mnt_idmap *idmap,
+
+ if (fattr->cf_acls) {
+ set_posix_acl_entries_dacl(idmap, pndace, fattr,
+- &num_aces, &size, num_aces);
++ &num_aces, &size, num_aces, false);
+ goto out;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From cd4adb90f76a16e5a378a07f7aa7e8f03fedeaee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:24 +0800
+Subject: ksmbd: restore DACL size on check_add_overflow() to avoid malformed
+ ACL
+
+From: Wentao Guan <guanwentao@uniontech.com>
+
+commit bbf0a8e931204ecdab494a88d43b0a24a04285c5 upstream.
+
+check_add_overflow() unconditionally writes the truncated sum into *d
+even on overflow, per its contract in include/linux/overflow.h.
+The four check_add_overflow() guards in set_posix_acl_entries_dacl()
+and set_ntacl_dacl() break out of the ACE-building loops on overflow,
+but the truncated *size is then consumed downstream at the end of
+set_ntacl_dacl():
+
+ pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
+
+This produces an on-wire NT ACL whose pndacl->size under-reports the
+bytes actually written by the preceding fill_ace_for_sid()/memcpy()
+calls, yielding a malformed ACL that can trigger out-of-bounds reads
+when re-parsed by clients or ksmbd itself.
+
+Restore *size to its pre-addition value on each overflow branch (via
+`*size -= ace_sz` / `size -= nt_ace_size`) so that after the break,
+*size once again holds the cumulative size of the successfully-written
+ACEs. The committed ACL is then truncated-but-self-consistent rather
+than malformed.
+
+The ksmbd DACL builders are the only check_add_overflow() sites found
+where an overflow path breaks out of a loop and the destination value
+is consumed afterward. The other nearby break-style cases either
+return -EINVAL on overflow (transport_ipc.c) or break without
+consuming the overflowed destination value afterward (buildid.c).
+
+Fixes: 299f962c0b02 ("ksmbd: use check_add_overflow() to prevent u16 DACL size overflow")
+Assisted-by: atomcode:glm-5.2
+Assisted-by: Codex:gpt-5.5
+Cc: stable@vger.kernel.org
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index e87f25f4e672fb..3f0f1d9c98d1b7 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -649,6 +649,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags,
+ pace->e_perm, 0777);
+ if (check_add_overflow(*size, ace_sz, size)) {
++ *size -= ace_sz;
+ kfree(sid);
+ break;
+ }
+@@ -663,6 +664,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED,
+ 0x03, pace->e_perm, 0777);
+ if (check_add_overflow(*size, ace_sz, size)) {
++ *size -= ace_sz;
+ kfree(sid);
+ break;
+ }
+@@ -708,6 +710,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b,
+ pace->e_perm, 0777);
+ if (check_add_overflow(*size, ace_sz, size)) {
++ *size -= ace_sz;
+ kfree(sid);
+ break;
+ }
+@@ -750,8 +753,10 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ goto next_ace;
+
+ memcpy((char *)pndace + size, ntace, nt_ace_size);
+- if (check_add_overflow(size, nt_ace_size, &size))
++ if (check_add_overflow(size, nt_ace_size, &size)) {
++ size -= nt_ace_size;
+ break;
++ }
+ num_aces++;
+
+ next_ace:
+--
+2.53.0
+
--- /dev/null
+From be56d8bcc0348506e1bbb8fed3bce258fb11c1b5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:29 +0800
+Subject: ksmbd: validate ACE size against SID sub-authorities
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+commit 5152c6d49e3fd4e9f2e857c57527aead752f1f87 upstream.
+
+set_ntacl_dacl() validates sid.num_subauth before copying an ACE, but
+does not verify that the declared ACE size contains all sub-authorities
+described by that field. An undersized ACE can therefore be copied
+and later make the POSIX ACL deduplication walk inspect data beyond
+the copied ACE boundary.
+
+The existing initial bound check is also too small. It only ensures
+that the ACE size field is accessible before set_ntacl_dacl() reads
+sid.num_subauth farther into the input buffer.
+
+Require enough input for the fixed SID header before accessing
+num_subauth, reject ACEs smaller than that header, and skip ACEs
+whose declared size cannot contain the complete SID. This makes the
+validation consistent with the other ACE walk paths.
+
+Reported-by: LocalHost <localhost.detect@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index 3cd0d1e1ddc224..06936ae521cf00 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -743,15 +743,22 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ for (i = 0; i < nt_num_aces; i++) {
+ unsigned short nt_ace_size;
+
+- if (offsetof(struct smb_ace, access_req) > aces_size)
++ if (aces_size < offsetof(struct smb_ace, sid) +
++ CIFS_SID_BASE_SIZE)
+ break;
+
+ nt_ace_size = le16_to_cpu(ntace->size);
+- if (nt_ace_size > aces_size)
++ if (nt_ace_size > aces_size ||
++ nt_ace_size < offsetof(struct smb_ace, sid) +
++ CIFS_SID_BASE_SIZE)
+ break;
+
+ if (ntace->sid.num_subauth == 0 ||
+- ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES)
++ ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
++ nt_ace_size < offsetof(struct smb_ace, sid) +
++ CIFS_SID_BASE_SIZE +
++ sizeof(__le32) *
++ ntace->sid.num_subauth)
+ goto next_ace;
+
+ memcpy((char *)pndace + size, ntace, nt_ace_size);
+--
+2.53.0
+
--- /dev/null
+From 73a19f39cebe5436125d8eeba15075428d2aa2bd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:22 +0800
+Subject: ksmbd: validate num_subauth when copying ACE in set_ntacl_dacl
+
+From: Haofeng Li <lihaofeng@kylinos.cn>
+
+commit 47f0b34f6bc98ed85bfdc293e8f3e432ec24958d upstream.
+
+set_ntacl_dacl() copies each ACE from the attacker-controlled stored
+security descriptor verbatim into the response DACL without checking
+sid.num_subauth. The ACE bytes (including an unchecked num_subauth)
+originate from an authenticated SMB2_SET_INFO(SecInfo=DACL) that is
+stored raw via ksmbd_vfs_set_sd_xattr(); parse_dacl() rejects a bad ACE
+with `break` rather than an error, so parse_sec_desc() still returns
+success and the malformed SD reaches the xattr intact.
+
+On a subsequent SMB2_QUERY_INFO(SecInfo=DACL) for an inode carrying a
+POSIX access ACL, build_sec_desc() -> set_ntacl_dacl() ->
+set_posix_acl_entries_dacl() walks the copied ACEs and reads
+
+ ntace->sid.sub_auth[ntace->sid.num_subauth - 1]
+
+with num_subauth taken straight from the stored SD. Since sub_auth[]
+is fixed at SID_MAX_SUB_AUTHORITIES (15), a crafted num_subauth (e.g.
+255) drives an out-of-bounds heap read of ~1 KB with an offset fully
+controlled by an authenticated client.
+
+The sibling functions already gate this field:
+ parse_dacl() -- num_subauth == 0 || > SID_MAX_SUB_AUTHORITIES
+ parse_sid() -- num_subauth > SID_MAX_SUB_AUTHORITIES
+ smb_copy_sid() -- min_t(u8, num_subauth, SID_MAX_SUB_AUTHORITIES)
+set_ntacl_dacl() is the lone inconsistent path that omits the check.
+
+Add the same num_subauth validation in set_ntacl_dacl() before copying
+the ACE, matching the gate already enforced by parse_dacl().
+
+Signed-off-by: Haofeng Li <lihaofeng@kylinos.cn>
+Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
+Suggested-by: Namjae Jeon <linkinjeon@kernel.org>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index 420d4e0733e5f1..e87f25f4e672fb 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -745,12 +745,18 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ if (nt_ace_size > aces_size)
+ break;
+
++ if (ntace->sid.num_subauth == 0 ||
++ ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES)
++ goto next_ace;
++
+ memcpy((char *)pndace + size, ntace, nt_ace_size);
+ if (check_add_overflow(size, nt_ace_size, &size))
+ break;
++ num_aces++;
++
++next_ace:
+ aces_size -= nt_ace_size;
+ ntace = (struct smb_ace *)((char *)ntace + nt_ace_size);
+- num_aces++;
+ }
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 0c878ffa9d0d2c05c9a60d1dd8600343177f7538 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:11:08 +0800
+Subject: net: pcs: xpcs: fix SGMII state reading
+
+From: Coia Prant <coiaprant@gmail.com>
+
+commit def9a4745e105145133e442dd8a1c126caf0f553 upstream.
+
+Commit 2a22b7ae2fa3 ("net: pcs: xpcs: adapt Wangxun NICs for SGMII mode")
+added a path in xpcs_get_state_c37_sgmii() that reads speed/duplex from
+BMCR after AN completes. However, BMCR does not reflect the negotiated
+result on the hardware where this has been tested:
+
+- On RK3568 (MAC side SGMII), BMCR returns a fixed hardware reset value
+- Wangxun engineer Jiawen Wu confirmed that on their side, "BMCR looks
+ like it only wants to be return as 0" [0]
+
+The correct information is available in CL37_ANSGM_STS, which contains
+the actual link status and negotiated speed/duplex.
+
+This bug was previously masked by phylink core, which overrides the PCS
+link state with the PHY state when a PHY is present:
+
+ /* If we have a phy, the "up" state is the union of both the
+ * PHY and the MAC
+ */
+ if (phy)
+ link_state.link &= pl->phy_state.link;
+
+Thus, when the link is down, the PHY's link_down state is applied on top
+of whatever the PCS reports, hiding the broken PCS state reading path.
+
+Modify xpcs_get_state_c37_sgmii() to:
+1. Read link state from CL37_ANSGM_STS
+2. If link is up, report speed/duplex from CL37_ANSGM_STS
+3. Remove the broken BMCR reading path entirely
+
+Also properly set state->an_complete to reflect the AN completion status,
+and clear CL37_ANCMPLT_INTR when link is down to avoid stale state.
+
+[0] https://lore.kernel.org/all/000c01dd1593$2ac0b0f0$804212d0$@trustnetic.com/
+
+Fixes: 2a22b7ae2fa3 ("net: pcs: xpcs: adapt Wangxun NICs for SGMII mode")
+Cc: stable@vger.kernel.org
+Tested-by: Jiawen Wu <jiawenwu@trustnetic.com>
+Signed-off-by: Coia Prant <coiaprant@gmail.com>
+Tested-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Link: https://patch.msgid.link/20260717074324.3250043-2-coiaprant@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/pcs/pcs-xpcs.c | 32 +++++++-------------------------
+ 1 file changed, 7 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
+index f0f41e86a4fb32..680e2b2610860f 100644
+--- a/drivers/net/pcs/pcs-xpcs.c
++++ b/drivers/net/pcs/pcs-xpcs.c
+@@ -994,6 +994,7 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
+
+ /* Reset link_state */
+ state->link = false;
++ state->an_complete = false;
+ state->speed = SPEED_UNKNOWN;
+ state->duplex = DUPLEX_UNKNOWN;
+ state->pause = 0;
+@@ -1005,6 +1006,8 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
+ if (ret < 0)
+ return ret;
+
++ state->an_complete = ret & DW_VR_MII_AN_STS_C37_ANCMPLT_INTR;
++
+ if (ret & DW_VR_MII_C37_ANSGM_SP_LNKSTS) {
+ int speed_value;
+
+@@ -1023,34 +1026,13 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
+ state->duplex = DUPLEX_FULL;
+ else
+ state->duplex = DUPLEX_HALF;
+- } else if (ret == DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
+- int speed, duplex;
+-
+- state->link = true;
+-
+- speed = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
+- if (speed < 0)
+- return speed;
+-
+- speed &= SGMII_SPEED_SS13 | SGMII_SPEED_SS6;
+- if (speed == SGMII_SPEED_SS6)
+- state->speed = SPEED_1000;
+- else if (speed == SGMII_SPEED_SS13)
+- state->speed = SPEED_100;
+- else if (speed == 0)
+- state->speed = SPEED_10;
+-
+- duplex = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_ADVERTISE);
+- if (duplex < 0)
+- return duplex;
+
+- if (duplex & DW_FULL_DUPLEX)
+- state->duplex = DUPLEX_FULL;
+- else if (duplex & DW_HALF_DUPLEX)
+- state->duplex = DUPLEX_HALF;
++ return 0;
++ }
+
++ /* Clear AN complete status or interrupt */
++ if (state->an_complete)
+ xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
+- }
+
+ return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From 04acf9e4438cd3fc6c3cbcba78e64dd6e2115fd8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 17:05:32 +0200
+Subject: net: qrtr: ns: Raise node count limit to 512
+
+From: Youssef Samir <youssef.abdulrahman@oss.qualcomm.com>
+
+commit ff194cffd586cbd4cc49eccb002c65f2a902a277 upstream.
+
+The current node limit of 64 breaks the functionality for a number of AI200
+deployments that have up to 384 nodes. Raise the limit to 512.
+
+Fixes: 27d5e84e810b ("net: qrtr: ns: Limit the total number of nodes")
+Cc: stable@vger.kernel.org
+Signed-off-by: Youssef Samir <youssef.abdulrahman@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260713145901.212396-1-youssef.abdulrahman@oss.qualcomm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Youssef Samir <youssef.abdulrahman@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/ns.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c
+index ecf49172307f1b..90244ce7e95e7a 100644
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -85,9 +85,9 @@ struct qrtr_node {
+ /* Max nodes limit is chosen based on the current platform requirements.
+ * If the requirement changes in the future, this value can be increased.
+ */
+-#define QRTR_NS_MAX_NODES 64
++#define QRTR_NS_MAX_NODES 512
+
+-static u8 node_count;
++static u16 node_count;
+
+ static struct qrtr_node *node_get(unsigned int node_id)
+ {
+--
+2.53.0
+
--- /dev/null
+From 338bff8f7214f29c8d7d58e8e0d2b12a32e31d90 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 22:56:07 +0200
+Subject: openvswitch: fix GSO userspace truncation underflow
+
+From: Kyle Zeng <kylebot@openai.com>
+
+[ Upstream commit 4032f8ed10fcb84d41c508dfb04be96589f78dfe ]
+
+OVS_ACTION_ATTR_TRUNC currently stores a delta from the original skb
+length in OVS_CB(skb)->cutlen. When a later userspace action segments a
+GSO skb, queue_gso_packets() reuses that delta for each smaller segment.
+A segment can then reach queue_userspace_packet() with cutlen greater
+than skb->len, underflowing the length passed to skb_zerocopy().
+
+Store the maximum preserved length instead and bound each consumer
+against the current skb length. Use U32_MAX as the no-truncation
+sentinel so the value remains valid if skb geometry changes before a
+consumer handles it.
+
+Fixes: f2a4d086ed4c ("openvswitch: Add packet truncation support.")
+Cc: stable@vger.kernel.org
+Assisted-by: Codex:gpt-5.5
+Signed-off-by: Kyle Zeng <kylebot@openai.com>
+Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
+Reviewed-by: Aaron Conole <aconole@redhat.com>
+Link: https://patch.msgid.link/20260707221635.27489-1-kylebot@openai.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[6.6.y and older don't have OVS_ACTION_ATTR_PSAMPLE]
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/actions.c | 15 +++++----------
+ net/openvswitch/datapath.c | 25 ++++++++++++++-----------
+ net/openvswitch/datapath.h | 2 +-
+ net/openvswitch/vport.c | 2 +-
+ 4 files changed, 21 insertions(+), 23 deletions(-)
+
+diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
+index 0ea4fc2a755bfd..793f86e2475559 100644
+--- a/net/openvswitch/actions.c
++++ b/net/openvswitch/actions.c
+@@ -861,12 +861,8 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
+ u16 mru = OVS_CB(skb)->mru;
+ u32 cutlen = OVS_CB(skb)->cutlen;
+
+- if (unlikely(cutlen > 0)) {
+- if (skb->len - cutlen > ovs_mac_header_len(key))
+- pskb_trim(skb, skb->len - cutlen);
+- else
+- pskb_trim(skb, ovs_mac_header_len(key));
+- }
++ if (unlikely(cutlen < skb->len))
++ pskb_trim(skb, max(cutlen, ovs_mac_header_len(key)));
+
+ if (likely(!mru ||
+ (skb->len <= mru + vport->dev->hard_header_len))) {
+@@ -1258,22 +1254,21 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
+ clone = skb_clone(skb, GFP_ATOMIC);
+ if (clone)
+ do_output(dp, clone, port, key);
+- OVS_CB(skb)->cutlen = 0;
++ OVS_CB(skb)->cutlen = U32_MAX;
+ break;
+ }
+
+ case OVS_ACTION_ATTR_TRUNC: {
+ struct ovs_action_trunc *trunc = nla_data(a);
+
+- if (skb->len > trunc->max_len)
+- OVS_CB(skb)->cutlen = skb->len - trunc->max_len;
++ OVS_CB(skb)->cutlen = trunc->max_len;
+ break;
+ }
+
+ case OVS_ACTION_ATTR_USERSPACE:
+ output_userspace(dp, skb, key, a, attr,
+ len, OVS_CB(skb)->cutlen);
+- OVS_CB(skb)->cutlen = 0;
++ OVS_CB(skb)->cutlen = U32_MAX;
+ if (nla_is_last(a, rem)) {
+ consume_skb(skb);
+ return 0;
+diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
+index 857edc53739332..fb5b72700d82b1 100644
+--- a/net/openvswitch/datapath.c
++++ b/net/openvswitch/datapath.c
+@@ -273,7 +273,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
+ upcall.portid = ovs_vport_find_upcall_portid(p, skb);
+
+ upcall.mru = OVS_CB(skb)->mru;
+- error = ovs_dp_upcall(dp, skb, key, &upcall, 0);
++ error = ovs_dp_upcall(dp, skb, key, &upcall, U32_MAX);
+ switch (error) {
+ case 0:
+ case -EAGAIN:
+@@ -438,7 +438,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ struct sk_buff *nskb = NULL;
+ struct sk_buff *user_skb = NULL; /* to be queued to userspace */
+ struct nlattr *nla;
+- size_t len;
++ size_t msg_size;
++ size_t skb_len;
+ unsigned int hlen;
+ int err, dp_ifindex;
+ u64 hash;
+@@ -459,7 +460,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ skb = nskb;
+ }
+
+- if (nla_attr_size(skb->len) > USHRT_MAX) {
++ skb_len = min(skb->len, cutlen);
++ if (nla_attr_size(skb_len) > USHRT_MAX) {
+ err = -EFBIG;
+ goto out;
+ }
+@@ -474,13 +476,13 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ * padding logic. Only perform zerocopy if padding is not required.
+ */
+ if (dp->user_features & OVS_DP_F_UNALIGNED)
+- hlen = skb_zerocopy_headlen(skb);
++ hlen = min(skb_zerocopy_headlen(skb), cutlen);
+ else
+- hlen = skb->len;
++ hlen = skb_len;
+
+- len = upcall_msg_size(upcall_info, hlen - cutlen,
+- OVS_CB(skb)->acts_origlen);
+- user_skb = genlmsg_new(len, GFP_ATOMIC);
++ msg_size = upcall_msg_size(upcall_info, hlen,
++ OVS_CB(skb)->acts_origlen);
++ user_skb = genlmsg_new(msg_size, GFP_ATOMIC);
+ if (!user_skb) {
+ err = -ENOMEM;
+ goto out;
+@@ -541,7 +543,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ }
+
+ /* Add OVS_PACKET_ATTR_LEN when packet is truncated */
+- if (cutlen > 0 &&
++ if (skb_len < skb->len &&
+ nla_put_u32(user_skb, OVS_PACKET_ATTR_LEN, skb->len)) {
+ err = -ENOBUFS;
+ goto out;
+@@ -566,9 +568,9 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ err = -ENOBUFS;
+ goto out;
+ }
+- nla->nla_len = nla_attr_size(skb->len - cutlen);
++ nla->nla_len = nla_attr_size(skb_len);
+
+- err = skb_zerocopy(user_skb, skb, skb->len - cutlen, hlen);
++ err = skb_zerocopy(user_skb, skb, skb_len, hlen);
+ if (err)
+ goto out;
+
+@@ -625,6 +627,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
+ packet->ignore_df = 1;
+ }
+ OVS_CB(packet)->mru = mru;
++ OVS_CB(packet)->cutlen = U32_MAX;
+
+ if (a[OVS_PACKET_ATTR_HASH]) {
+ hash = nla_get_u64(a[OVS_PACKET_ATTR_HASH]);
+diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
+index 0cd29971a907ca..88156a677f22c5 100644
+--- a/net/openvswitch/datapath.h
++++ b/net/openvswitch/datapath.h
+@@ -114,7 +114,7 @@ struct datapath {
+ * @mru: The maximum received fragement size; 0 if the packet is not
+ * fragmented.
+ * @acts_origlen: The netlink size of the flow actions applied to this skb.
+- * @cutlen: The number of bytes from the packet end to be removed.
++ * @cutlen: The number of bytes in the packet to preserve on output.
+ */
+ struct ovs_skb_cb {
+ struct vport *input_vport;
+diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
+index a0a8854e9f19e8..eb0eb57dabe2f9 100644
+--- a/net/openvswitch/vport.c
++++ b/net/openvswitch/vport.c
+@@ -503,7 +503,7 @@ int ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
+
+ OVS_CB(skb)->input_vport = vport;
+ OVS_CB(skb)->mru = 0;
+- OVS_CB(skb)->cutlen = 0;
++ OVS_CB(skb)->cutlen = U32_MAX;
+ if (unlikely(dev_net(skb->dev) != ovs_dp_get_net(vport->dp))) {
+ u32 mark;
+
+--
+2.53.0
+
drm-amdgpu-fix-division-by-zero-with-invalid-uvd-dimensions.patch
drm-amdgpu-invoke-pm_genpd_remove-before-freeing-genpd.patch
drm-amdgpu-fix-aperture-mapping-leak.patch
+i40e-remove-read-access-to-debugfs-files.patch
+ipv6-ndisc-fix-null-deref-in-accept_untracked_na.patch
+net-qrtr-ns-raise-node-count-limit-to-512.patch
+ksmbd-validate-num_subauth-when-copying-ace-in-set_n.patch
+ksmbd-restore-dacl-size-on-check_add_overflow-to-avo.patch
+ksmbd-bound-dacl-dedup-walk-to-copied-aces.patch
+ksmbd-validate-ace-size-against-sid-sub-authorities.patch
+openvswitch-fix-gso-userspace-truncation-underflow.patch
+fscrypt-avoid-dynamic-allocation-in-fscrypt_get_devi.patch
+exfat-validate-cluster-allocation-bits-of-the-alloca.patch
+drm-amd-display-fix-dcn32-dtb-dto-update-breaking-li.patch
+io_uring-rw-fix-missing-erestartsys-conversion-in-re.patch
+net-pcs-xpcs-fix-sgmii-state-reading.patch
+bpf-drop-bpf_lsm_getselfattr-from-hook-list.patch
--- /dev/null
+From 6dc84a3cb5f0d80831ad4343995f798c043f66ef Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 23:33:40 -0700
+Subject: drm/amd/display: Fix DTB DTO updates breaking live pixel rate sources
+
+From: Harry Wentland <harry.wentland@amd.com>
+
+commit 76a2db58e95e328007043f54ac3c7336ccbee440 upstream.
+
+dcn32_update_clocks_update_dtb_dto() and its dcn35 counterpart reprogram
+the DTB DTO of every timing generator in the context whenever the DTBCLK
+reference changes, passing a zeroed pixel rate and never setting
+is_hdmi. Both dccg set_dtbclk_dto() implementations treat a zero pixel
+rate as a disable request. On dcn32 that branch drives PIPE_DTO_SRC_SEL
+to the DP DTO source, so a timing generator actively scanning out an
+HDMI stream has its pixel rate source re-muxed out from under the live
+raster and the OTG stops on the spot. On dcn35 it clears
+DTBCLK_DTO_ENABLE and restores DTBCLK_Pn clock gating, which does the
+same to a live 128b/132b stream.
+
+Two displays where only one runs a 128b/132b link hit this reliably.
+is_dtbclk_required() holds the DTBCLK reference high while both are
+active, and the moment the 128b/132b stream is torn down (compositor
+switch, display disable, hot-unplug) the next safe_to_lower pass drops
+the reference to the lowest DPM level and the DTO walk freezes the
+surviving screen. On Navi31 the DAL mailbox then goes deaf on the
+DISPCLK hard-min that follows the walk in dcn32_update_clocks(),
+stranding both SMU mailboxes until reboot.
+
+Set is_hdmi for HDMI and DVI signals so the disable path leaves the
+pixel rate source selection on the HDMI path, and pass the real pixel
+rate for 128b/132b streams so a reference change rescales their DTO
+instead of disabling it.
+
+Fixes: 128c1ca0303f ("drm/amd/display: Update DTBCLK for DCN32")
+Fixes: 8774029f76b9 ("drm/amd/display: Add DCN35 CLK_MGR")
+Signed-off-by: Harry Wentland <harry.wentland@amd.com>
+Reviewed-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
+Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+[ mschwartz: dcn32 and dcn35 clk_mgr hunks only. The rest is HDMI FRL
+ enablement, absent before 7.2, so the FRL conditions and the
+ req_audio_dtbclk_khz assignment they guard are dropped and the
+ FRL-centric changelog is rewritten. Added the pipe_ctx->stream check
+ the new dereferences need. ]
+Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c | 9 ++++++++-
+ .../gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 9 ++++++++-
+ 2 files changed, 16 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+index fda6cade30a8de..e2787c7084ec07 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+@@ -276,13 +276,20 @@ static void dcn32_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
+ struct dtbclk_dto_params dto_params = {0};
+
+ /* use mask to program DTO once per tg */
+- if (pipe_ctx->stream_res.tg &&
++ if (pipe_ctx->stream && pipe_ctx->stream_res.tg &&
+ !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) {
+ tg_mask |= (1 << pipe_ctx->stream_res.tg->inst);
+
+ dto_params.otg_inst = pipe_ctx->stream_res.tg->inst;
+ dto_params.ref_dtbclk_khz = ref_dtbclk_khz;
+
++ if (dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))
++ dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
++
++ if (dc_is_hdmi_signal(pipe_ctx->stream->signal) ||
++ dc_is_dvi_signal(pipe_ctx->stream->signal))
++ dto_params.is_hdmi = true;
++
+ dccg->funcs->set_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ //dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
+index 3f58a1640d64e7..020d43c7fab855 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
+@@ -264,13 +264,20 @@ static void dcn35_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
+ struct dtbclk_dto_params dto_params = {0};
+
+ /* use mask to program DTO once per tg */
+- if (pipe_ctx->stream_res.tg &&
++ if (pipe_ctx->stream && pipe_ctx->stream_res.tg &&
+ !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) {
+ tg_mask |= (1 << pipe_ctx->stream_res.tg->inst);
+
+ dto_params.otg_inst = pipe_ctx->stream_res.tg->inst;
+ dto_params.ref_dtbclk_khz = ref_dtbclk_khz;
+
++ if (dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))
++ dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
++
++ if (dc_is_hdmi_signal(pipe_ctx->stream->signal) ||
++ dc_is_dvi_signal(pipe_ctx->stream->signal))
++ dto_params.is_hdmi = true;
++
+ dccg->funcs->set_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ //dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ }
+--
+2.53.0
+
--- /dev/null
+From 87374ccb3747b641fbbdd207b5167b97d9f04334 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:26 +0800
+Subject: ksmbd: bound DACL dedup walk to copied ACEs
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+commit 58d97fcd0bf1aee694e244cc28635b9df95b543b upstream.
+
+set_ntacl_dacl() can stop copying ACEs before consuming the full input
+DACL when size accounting overflows.
+
+When that happens, num_aces reflects only the ACEs that were actually
+copied into the output DACL, but set_posix_acl_entries_dacl() still
+receives nt_num_aces and uses it to walk the existing ACE array during
+dedup.
+
+That makes the dedup walk scan past the copied ACE array and inspect
+buffer tail that does not contain valid ACEs.
+
+Split the two meanings currently carried by the NT ACE count. Pass the
+number of copied NT ACEs to bound the dedup walk, and preserve the
+original "input DACL had NT ACEs" state separately for the
+Everyone/default ACL fallback.
+
+This keeps the dedup walk aligned with the ACEs that are actually
+present in the rebuilt DACL.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index 5621c50a805716..f8696399130889 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -595,7 +595,8 @@ static void parse_dacl(struct mnt_idmap *idmap,
+ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ struct smb_ace *pndace,
+ struct smb_fattr *fattr, u16 *num_aces,
+- u16 *size, u32 nt_aces_num)
++ u16 *size, u16 existing_nt_aces,
++ bool had_nt_aces)
+ {
+ struct posix_acl_entry *pace;
+ struct smb_sid *sid;
+@@ -627,14 +628,14 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+
+ gid = posix_acl_gid_translate(idmap, pace);
+ id_to_sid(gid, SIDUNIX_GROUP, sid);
+- } else if (pace->e_tag == ACL_OTHER && !nt_aces_num) {
++ } else if (pace->e_tag == ACL_OTHER && !had_nt_aces) {
+ smb_copy_sid(sid, &sid_everyone);
+ } else {
+ kfree(sid);
+ continue;
+ }
+ ntace = pndace;
+- for (j = 0; j < nt_aces_num; j++) {
++ for (j = 0; j < existing_nt_aces; j++) {
+ if (ntace->sid.sub_auth[ntace->sid.num_subauth - 1] ==
+ sid->sub_auth[sid->num_subauth - 1])
+ goto pass_same_sid;
+@@ -678,7 +679,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ kfree(sid);
+ }
+
+- if (nt_aces_num)
++ if (had_nt_aces)
+ return;
+
+ posix_default_acl:
+@@ -732,6 +733,7 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ {
+ struct smb_ace *ntace, *pndace;
+ u16 nt_num_aces = le16_to_cpu(nt_dacl->num_aces), num_aces = 0;
++ u16 copied_nt_aces;
+ unsigned short size = 0;
+ int i;
+
+@@ -765,8 +767,10 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ }
+ }
+
++ copied_nt_aces = num_aces;
+ set_posix_acl_entries_dacl(idmap, pndace, fattr,
+- &num_aces, &size, nt_num_aces);
++ &num_aces, &size, copied_nt_aces,
++ nt_num_aces != 0);
+ pndacl->num_aces = cpu_to_le16(num_aces);
+ pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
+ }
+@@ -784,7 +788,7 @@ static void set_mode_dacl(struct mnt_idmap *idmap,
+
+ if (fattr->cf_acls) {
+ set_posix_acl_entries_dacl(idmap, pndace, fattr,
+- &num_aces, &size, num_aces);
++ &num_aces, &size, num_aces, false);
+ goto out;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From e4e52ed15acfded51d3d9ca1324e1ea95f10697f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:24 +0800
+Subject: ksmbd: restore DACL size on check_add_overflow() to avoid malformed
+ ACL
+
+From: Wentao Guan <guanwentao@uniontech.com>
+
+commit bbf0a8e931204ecdab494a88d43b0a24a04285c5 upstream.
+
+check_add_overflow() unconditionally writes the truncated sum into *d
+even on overflow, per its contract in include/linux/overflow.h.
+The four check_add_overflow() guards in set_posix_acl_entries_dacl()
+and set_ntacl_dacl() break out of the ACE-building loops on overflow,
+but the truncated *size is then consumed downstream at the end of
+set_ntacl_dacl():
+
+ pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
+
+This produces an on-wire NT ACL whose pndacl->size under-reports the
+bytes actually written by the preceding fill_ace_for_sid()/memcpy()
+calls, yielding a malformed ACL that can trigger out-of-bounds reads
+when re-parsed by clients or ksmbd itself.
+
+Restore *size to its pre-addition value on each overflow branch (via
+`*size -= ace_sz` / `size -= nt_ace_size`) so that after the break,
+*size once again holds the cumulative size of the successfully-written
+ACEs. The committed ACL is then truncated-but-self-consistent rather
+than malformed.
+
+The ksmbd DACL builders are the only check_add_overflow() sites found
+where an overflow path breaks out of a loop and the destination value
+is consumed afterward. The other nearby break-style cases either
+return -EINVAL on overflow (transport_ipc.c) or break without
+consuming the overflowed destination value afterward (buildid.c).
+
+Fixes: 299f962c0b02 ("ksmbd: use check_add_overflow() to prevent u16 DACL size overflow")
+Assisted-by: atomcode:glm-5.2
+Assisted-by: Codex:gpt-5.5
+Cc: stable@vger.kernel.org
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index 9c59c8f73b6675..5621c50a805716 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -649,6 +649,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags,
+ pace->e_perm, 0777);
+ if (check_add_overflow(*size, ace_sz, size)) {
++ *size -= ace_sz;
+ kfree(sid);
+ break;
+ }
+@@ -663,6 +664,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED,
+ 0x03, pace->e_perm, 0777);
+ if (check_add_overflow(*size, ace_sz, size)) {
++ *size -= ace_sz;
+ kfree(sid);
+ break;
+ }
+@@ -708,6 +710,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b,
+ pace->e_perm, 0777);
+ if (check_add_overflow(*size, ace_sz, size)) {
++ *size -= ace_sz;
+ kfree(sid);
+ break;
+ }
+@@ -750,8 +753,10 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ goto next_ace;
+
+ memcpy((char *)pndace + size, ntace, nt_ace_size);
+- if (check_add_overflow(size, nt_ace_size, &size))
++ if (check_add_overflow(size, nt_ace_size, &size)) {
++ size -= nt_ace_size;
+ break;
++ }
+ num_aces++;
+
+ next_ace:
+--
+2.53.0
+
--- /dev/null
+From 96ba944f8cd220790a9d69dd1d485181b1bb9752 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:29 +0800
+Subject: ksmbd: validate ACE size against SID sub-authorities
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+commit 5152c6d49e3fd4e9f2e857c57527aead752f1f87 upstream.
+
+set_ntacl_dacl() validates sid.num_subauth before copying an ACE, but
+does not verify that the declared ACE size contains all sub-authorities
+described by that field. An undersized ACE can therefore be copied
+and later make the POSIX ACL deduplication walk inspect data beyond
+the copied ACE boundary.
+
+The existing initial bound check is also too small. It only ensures
+that the ACE size field is accessible before set_ntacl_dacl() reads
+sid.num_subauth farther into the input buffer.
+
+Require enough input for the fixed SID header before accessing
+num_subauth, reject ACEs smaller than that header, and skip ACEs
+whose declared size cannot contain the complete SID. This makes the
+validation consistent with the other ACE walk paths.
+
+Reported-by: LocalHost <localhost.detect@gmail.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index f8696399130889..0359cd10320269 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -743,15 +743,22 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ for (i = 0; i < nt_num_aces; i++) {
+ unsigned short nt_ace_size;
+
+- if (offsetof(struct smb_ace, access_req) > aces_size)
++ if (aces_size < offsetof(struct smb_ace, sid) +
++ CIFS_SID_BASE_SIZE)
+ break;
+
+ nt_ace_size = le16_to_cpu(ntace->size);
+- if (nt_ace_size > aces_size)
++ if (nt_ace_size > aces_size ||
++ nt_ace_size < offsetof(struct smb_ace, sid) +
++ CIFS_SID_BASE_SIZE)
+ break;
+
+ if (ntace->sid.num_subauth == 0 ||
+- ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES)
++ ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
++ nt_ace_size < offsetof(struct smb_ace, sid) +
++ CIFS_SID_BASE_SIZE +
++ sizeof(__le32) *
++ ntace->sid.num_subauth)
+ goto next_ace;
+
+ memcpy((char *)pndace + size, ntace, nt_ace_size);
+--
+2.53.0
+
--- /dev/null
+From 9f44461c807c77b13dc8adaa63034d2820f02048 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 03:00:22 +0800
+Subject: ksmbd: validate num_subauth when copying ACE in set_ntacl_dacl
+
+From: Haofeng Li <lihaofeng@kylinos.cn>
+
+commit 47f0b34f6bc98ed85bfdc293e8f3e432ec24958d upstream.
+
+set_ntacl_dacl() copies each ACE from the attacker-controlled stored
+security descriptor verbatim into the response DACL without checking
+sid.num_subauth. The ACE bytes (including an unchecked num_subauth)
+originate from an authenticated SMB2_SET_INFO(SecInfo=DACL) that is
+stored raw via ksmbd_vfs_set_sd_xattr(); parse_dacl() rejects a bad ACE
+with `break` rather than an error, so parse_sec_desc() still returns
+success and the malformed SD reaches the xattr intact.
+
+On a subsequent SMB2_QUERY_INFO(SecInfo=DACL) for an inode carrying a
+POSIX access ACL, build_sec_desc() -> set_ntacl_dacl() ->
+set_posix_acl_entries_dacl() walks the copied ACEs and reads
+
+ ntace->sid.sub_auth[ntace->sid.num_subauth - 1]
+
+with num_subauth taken straight from the stored SD. Since sub_auth[]
+is fixed at SID_MAX_SUB_AUTHORITIES (15), a crafted num_subauth (e.g.
+255) drives an out-of-bounds heap read of ~1 KB with an offset fully
+controlled by an authenticated client.
+
+The sibling functions already gate this field:
+ parse_dacl() -- num_subauth == 0 || > SID_MAX_SUB_AUTHORITIES
+ parse_sid() -- num_subauth > SID_MAX_SUB_AUTHORITIES
+ smb_copy_sid() -- min_t(u8, num_subauth, SID_MAX_SUB_AUTHORITIES)
+set_ntacl_dacl() is the lone inconsistent path that omits the check.
+
+Add the same num_subauth validation in set_ntacl_dacl() before copying
+the ACE, matching the gate already enforced by parse_dacl().
+
+Signed-off-by: Haofeng Li <lihaofeng@kylinos.cn>
+Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
+Suggested-by: Namjae Jeon <linkinjeon@kernel.org>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smbacl.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index fc9937cedb012b..9c59c8f73b6675 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -745,12 +745,18 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ if (nt_ace_size > aces_size)
+ break;
+
++ if (ntace->sid.num_subauth == 0 ||
++ ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES)
++ goto next_ace;
++
+ memcpy((char *)pndace + size, ntace, nt_ace_size);
+ if (check_add_overflow(size, nt_ace_size, &size))
+ break;
++ num_aces++;
++
++next_ace:
+ aces_size -= nt_ace_size;
+ ntace = (struct smb_ace *)((char *)ntace + nt_ace_size);
+- num_aces++;
+ }
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 58072da4f9a6f964a671680c1768ff51dea52f58 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jul 2026 20:04:46 +0200
+Subject: selftests: drv-net: add missing kconfig for psp.py
+
+From: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+
+[ Upstream commit c25dd7439f84cf607e13d6de8cc1c79cd51f56ff ]
+
+This psp.py selftest was failing on my side when only using the
+drivers/net config file on top of the default one -- the recommended way
+to execute selftest targets.
+
+It looks like some kernel config are needed to execute the new tc
+commands.
+
+Note that this was not visible on NIPA, because these tests are executed
+with the drivers/net/hw ones, combining the two config files, and the hw
+one contains the missing ones.
+
+Fixes: 3f74d5bb807e ("selftests/net: Add env for container based tests")
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Reviewed-by: Wei Wang <weibunny@fb.com>
+Link: https://patch.msgid.link/20260710-net-sft-fix-containers-v1-6-a2915c294ef5@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/drivers/net/config | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/tools/testing/selftests/drivers/net/config b/tools/testing/selftests/drivers/net/config
+index 2309109a94ecea..4df3f6eef2cbac 100644
+--- a/tools/testing/selftests/drivers/net/config
++++ b/tools/testing/selftests/drivers/net/config
+@@ -4,11 +4,14 @@ CONFIG_DEBUG_INFO_BTF_MODULES=n
+ CONFIG_INET_PSP=y
+ CONFIG_IPV6=y
+ CONFIG_MACSEC=m
++CONFIG_NET_CLS_ACT=y
++CONFIG_NET_CLS_BPF=y
+ CONFIG_NETCONSOLE=m
+ CONFIG_NETCONSOLE_DYNAMIC=y
+ CONFIG_NETCONSOLE_EXTENDED_LOG=y
+ CONFIG_NETDEVSIM=m
+ CONFIG_NET_SCH_ETF=m
+ CONFIG_NET_SCH_FQ=m
++CONFIG_NET_SCH_INGRESS=y
+ CONFIG_VLAN_8021Q=m
+ CONFIG_XDP_SOCKETS=y
+--
+2.53.0
+
drm-amdgpu-fix-aperture-mapping-leak.patch
drm-amd-pm-fix-smu13-power-limit-range-calculation.patch
drm-amdgpu-fix-check-in-amdgpu_hmm_invalidate_gfx.patch
+selftests-drv-net-add-missing-kconfig-for-psp.py.patch
+ksmbd-validate-num_subauth-when-copying-ace-in-set_n.patch
+ksmbd-restore-dacl-size-on-check_add_overflow-to-avo.patch
+ksmbd-bound-dacl-dedup-walk-to-copied-aces.patch
+ksmbd-validate-ace-size-against-sid-sub-authorities.patch
+drm-amd-display-fix-dtb-dto-updates-breaking-live-pi.patch