--- /dev/null
+From f2c2e2ba9edf6d4600348efceb6363facd712015 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 24 May 2026 23:38:46 -0400
+Subject: ARM: npcm: Fix OF node refcount leaks in SMP setup
+
+From: Yuho Choi <dbgh9129@gmail.com>
+
+[ Upstream commit 8eb052f48331474c2789d07b7f11165c323bd2f9 ]
+
+npcm7xx_smp_boot_secondary() and npcm7xx_smp_prepare_cpus() look up
+the GCR and SCU nodes with of_find_compatible_node(). The returned
+nodes are used for of_iomap(), but the node references are never
+released.
+
+of_iomap() does not consume the device node reference, and iounmap()
+only releases the MMIO mapping. Drop each node reference after the
+corresponding mapping attempt.
+
+Fixes: 7bffa14c9aed ("arm: npcm: add basic support for Nuvoton BMCs")
+Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
+Reviewed-by: Avi Fishman <avifishman70@gmail.com>
+Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/mach-npcm/platsmp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arm/mach-npcm/platsmp.c b/arch/arm/mach-npcm/platsmp.c
+index 21633c70fe7fe..fe63edc9886df 100644
+--- a/arch/arm/mach-npcm/platsmp.c
++++ b/arch/arm/mach-npcm/platsmp.c
+@@ -35,6 +35,7 @@ static int npcm7xx_smp_boot_secondary(unsigned int cpu,
+ goto out;
+ }
+ gcr_base = of_iomap(gcr_np, 0);
++ of_node_put(gcr_np);
+ if (!gcr_base) {
+ pr_err("could not iomap gcr");
+ ret = -ENOMEM;
+@@ -63,6 +64,7 @@ static void __init npcm7xx_smp_prepare_cpus(unsigned int max_cpus)
+ return;
+ }
+ scu_base = of_iomap(scu_np, 0);
++ of_node_put(scu_np);
+ if (!scu_base) {
+ pr_err("could not iomap scu");
+ return;
+--
+2.53.0
+
--- /dev/null
+From 6ee612a25f6ddeec742501e8f930df76e3e253b0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 14:06:28 +0800
+Subject: ata: pata_sl82c105: fix bridge revision use-after-free
+
+From: Hongyan Xu <getshell@seu.edu.cn>
+
+[ Upstream commit 7700a31039cdc6715cb6cce7e7a664ee4e945f67 ]
+
+pci_get_slot() returns a referenced PCI device. Commit 44c10138fd4b
+("PCI: Change all drivers to use pci_device->revision") replaced a
+configuration-space read with direct access to the cached revision field,
+but left that access after pci_dev_put(). The bridge may therefore be freed
+before its revision is read.
+
+Read the revision before dropping the reference.
+
+Fixes: 44c10138fd4b ("PCI: Change all drivers to use pci_device->revision")
+Signed-off-by: Hongyan Xu <getshell@seu.edu.cn>
+Reviewed-by: Niklas Cassel <cassel@kernel.org>
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ata/pata_sl82c105.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
+index ac7ddd87f188d..78275b2479df2 100644
+--- a/drivers/ata/pata_sl82c105.c
++++ b/drivers/ata/pata_sl82c105.c
+@@ -265,6 +265,7 @@ static struct ata_port_operations sl82c105_port_ops = {
+ static int sl82c105_bridge_revision(struct pci_dev *pdev)
+ {
+ struct pci_dev *bridge;
++ u8 revision;
+
+ /*
+ * The bridge should be part of the same device, but function 0.
+@@ -286,8 +287,9 @@ static int sl82c105_bridge_revision(struct pci_dev *pdev)
+ /*
+ * We need to find function 0's revision, not function 1
+ */
++ revision = bridge->revision;
+ pci_dev_put(bridge);
+- return bridge->revision;
++ return revision;
+ }
+
+ static void sl82c105_fixup(struct pci_dev *pdev)
+--
+2.53.0
+
--- /dev/null
+From ba032c60e7c1eacad914ed8a0ce52f88d837b5eb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:36 -0700
+Subject: bnxt_en: Disable EOP for TPA on all chips to prevent data corruption
+
+From: Michael Chan <michael.chan@broadcom.com>
+
+[ Upstream commit c3faf548a00f4c17100cc9204746975fa46a73b9 ]
+
+EOP (End of frame padding) on the AGG ring may cause overlapping of
+zero padding at the end of one segment with the next segment's data.
+If Relaxed Ordering (RO) is enabled, the zero padding may overwrite
+valid data in the next segment and corrupt the data. Older chips
+(P5 and older) do not automatically disable RO when EOP is enabled.
+On some ARM systems, data corruption was reported on 57508 (P5)
+chips with RO enabled.
+
+Always disable EOP on all chips on the AGG rings when TPA is enabled
+to fix the data corruption.
+
+Fixes: bfcd8d791ec1 ("bnxt_en: Add fast path logic for TPA on 57500 chips.")
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-5-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 07fe6e55f28a6..f36b2bae37999 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -3393,11 +3393,14 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr)
+ type = ((u32)BNXT_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
+ RX_BD_TYPE_RX_AGG_BD;
+
+- /* On P7, setting EOP will cause the chip to disable
+- * Relaxed Ordering (RO) for TPA data. Disable EOP for
+- * potentially higher performance with RO.
++ /* Disable EOP if TPA is enabled to prevent overlapping zero
++ * padding with the next segment's data. On P7_PLUS, EOP will
++ * automatically disable Relaxed Ordering (RO) to prevent
++ * potential data corruption (and may degrade performance). On
++ * older chips, RO will not be automatically disabled and may
++ * cause corruption.
+ */
+- if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
++ if (!(bp->flags & BNXT_FLAG_TPA))
+ type |= RX_BD_FLAGS_AGG_EOP;
+
+ bnxt_init_rxbd_pages(ring, type);
+--
+2.53.0
+
--- /dev/null
+From 88c9b3c4172d7cd56b19ea4e44a8a52f68cbc9e2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Nov 2025 13:56:46 -0800
+Subject: bnxt_en: Do not set EOP on RX AGG BDs on 5760X chips
+
+From: Michael Chan <michael.chan@broadcom.com>
+
+[ Upstream commit 30f253f8d9a01d532fdb7ec6c8a9d4c15fe29241 ]
+
+With End-of-Packet padding (EOP) set, the chip will disable Relaxed
+Ordering (RO) of TPA data packets. A TPA segment with EOP set will be
+padded to the next cache boundary and can potentially overwrite the
+beginning bytes of the next TPA segment when RO is enabled on 5760X.
+To prevent that, the chip disables RO for TPA when EOP is set.
+
+To take advantge of RO and higher performance, do not set EOP on
+5760X chips when TPA is enabled. Define a proper RX_BD_FLAGS_AGG_EOP
+constant to make it clear that we are setting EOP.
+
+Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
+Reviewed-by: Somnath Kotur <somnath.kotur@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20251126215648.1885936-6-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: c3faf548a00f ("bnxt_en: Disable EOP for TPA on all chips to prevent data corruption")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 ++++++++-
+ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
+ 2 files changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 6dd4104025297..07fe6e55f28a6 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -3391,7 +3391,14 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr)
+
+ if ((bp->flags & BNXT_FLAG_AGG_RINGS)) {
+ type = ((u32)BNXT_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
+- RX_BD_TYPE_RX_AGG_BD | RX_BD_FLAGS_SOP;
++ RX_BD_TYPE_RX_AGG_BD;
++
++ /* On P7, setting EOP will cause the chip to disable
++ * Relaxed Ordering (RO) for TPA data. Disable EOP for
++ * potentially higher performance with RO.
++ */
++ if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
++ type |= RX_BD_FLAGS_AGG_EOP;
+
+ bnxt_init_rxbd_pages(ring, type);
+ }
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+index c2122d5cda622..1a7ff21f8cdb8 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+@@ -99,6 +99,7 @@ struct rx_bd {
+ #define RX_BD_TYPE_48B_BD_SIZE (2 << 4)
+ #define RX_BD_TYPE_64B_BD_SIZE (3 << 4)
+ #define RX_BD_FLAGS_SOP (1 << 6)
++ #define RX_BD_FLAGS_AGG_EOP (1 << 6)
+ #define RX_BD_FLAGS_EOP (1 << 7)
+ #define RX_BD_FLAGS_BUFFERS (3 << 8)
+ #define RX_BD_FLAGS_1_BUFFER_PACKET (0 << 8)
+--
+2.53.0
+
--- /dev/null
+From f68d64c59c42a7e3a21a22e43ad690fb810b9a9a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 25 Jul 2026 23:39:30 +0000
+Subject: bonding: alb: re-check primary_is_promisc under RTNL in
+ bond_alb_monitor
+
+From: Xiang Mei (Microsoft) <xmei5@asu.edu>
+
+[ Upstream commit 683c6ba6e58e6ed1037831ea97dd58d9c0e76b8d ]
+
+bond_alb_monitor() reads primary_is_promisc under RCU, then drops RCU and
+takes RTNL via rtnl_trylock() before undoing the promiscuity it set on the
+active slave. In that window the active slave can change under RTNL
+(RTM_DELLINK -> __bond_release_one() -> bond_alb_handle_active_change()),
+which already drops the promiscuity and clears primary_is_promisc. The
+monitor still acts on the stale decision: if the slave was removed with no
+failover, curr_active_slave is now NULL and the deref faults; if it failed
+over, the stale dev_set_promiscuity(-1) underflows the new slave's
+promiscuity counter and pins it in IFF_PROMISC.
+
+ Oops: general protection fault, probably for non-canonical address ...
+ KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
+ Workqueue: b42 bond_alb_monitor
+ RIP: 0010:bond_alb_monitor (drivers/net/bonding/bond_alb.c:1600)
+ process_one_work (kernel/workqueue.c:3322)
+ worker_thread (kernel/workqueue.c:3486)
+ kthread (kernel/kthread.c:436)
+ ret_from_fork (arch/x86/kernel/process.c:158)
+ Kernel panic - not syncing: Fatal exception
+
+Re-check primary_is_promisc (and curr_active_slave) after taking RTNL so
+the monitor only undoes an increment it still owns. The other bonding
+monitors already re-read state under RTNL in their commit phase
+(bond_miimon_commit/bond_ab_arp_commit); bond_alb_monitor() was the only
+one acting on the pre-trylock decision.
+
+Fixes: d0e81b7e2246 ("bonding: Acquire correct locks in alb for promisc change")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
+Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
+Acked-by: Jay Vosburgh <jv@jvosburgh.net>
+Link: https://patch.msgid.link/20260725233930.2957317-1-xmei5@asu.edu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/bonding/bond_alb.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
+index 81a5e7622ea7d..dff22eddc885a 100644
+--- a/drivers/net/bonding/bond_alb.c
++++ b/drivers/net/bonding/bond_alb.c
+@@ -1528,8 +1528,8 @@ void bond_alb_monitor(struct work_struct *work)
+ struct bonding *bond = container_of(work, struct bonding,
+ alb_work.work);
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
++ struct slave *slave, *curr;
+ struct list_head *iter;
+- struct slave *slave;
+
+ if (!bond_has_slaves(bond)) {
+ atomic_set(&bond_info->tx_rebalance_counter, 0);
+@@ -1591,9 +1591,11 @@ void bond_alb_monitor(struct work_struct *work)
+ * because a slave was disabled then
+ * it can now leave promiscuous mode.
+ */
+- dev_set_promiscuity(rtnl_dereference(bond->curr_active_slave)->dev,
+- -1);
+- bond_info->primary_is_promisc = 0;
++ curr = rtnl_dereference(bond->curr_active_slave);
++ if (bond_info->primary_is_promisc && curr) {
++ dev_set_promiscuity(curr->dev, -1);
++ bond_info->primary_is_promisc = 0;
++ }
+
+ rtnl_unlock();
+ rcu_read_lock();
+--
+2.53.0
+
--- /dev/null
+From 196e3e2e72f167c87b14333fceb50c298ebd8915 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:18:28 +0000
+Subject: bpf: Preserve pointer state for commuted arithmetic
+
+From: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+
+[ Upstream commit a4c6f804b44c5c790269b25e0e61cf4e9f117c86 ]
+
+When scalar += pointer is handled in adjust_ptr_min_max_vals(), the
+destination register inherits the pointer state from the source pointer.
+Copying only selected fields is fragile because pointer provenance is
+tracked by several bpf_reg_state fields.
+
+Use the caller's temporary offset register to preserve the scalar operand
+while replacing the destination with the full pointer state. This preserves
+the frame number for PTR_TO_STACK registers and keeps parent identity
+fields consistent.
+
+Fixes: f4d7e40a5b71 ("bpf: introduce function calls (verification)")
+Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+Tested-by: Daniel Wade <danjwade95@gmail.com>
+Acked-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-2-8ee297e2346b@mails.tsinghua.edu.cn
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 058c05e7f144c..9866599171782 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -6301,11 +6301,12 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ break;
+ }
+
+- /* In case of 'scalar += pointer', dst_reg inherits pointer type and id.
+- * The id may be overwritten later if we create a new variable offset.
++ /* For 'scalar += pointer', dst_reg inherits the complete pointer
++ * register state. Individual fields may be adjusted later by pointer
++ * arithmetic. Callers guarantee that below does not overwrite off_reg.
+ */
+- dst_reg->type = ptr_reg->type;
+- dst_reg->id = ptr_reg->id;
++ if (dst_reg != ptr_reg)
++ *dst_reg = *ptr_reg;
+
+ if (!check_reg_sane_offset(env, off_reg, ptr_reg->type) ||
+ !check_reg_sane_offset(env, ptr_reg, ptr_reg->type))
+@@ -6373,7 +6374,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ }
+ break;
+ case BPF_SUB:
+- if (dst_reg == off_reg) {
++ if (dst_reg != ptr_reg) {
+ /* scalar -= pointer. Creates an unknown scalar */
+ verbose(env, "R%d tried to subtract pointer from scalar\n",
+ dst);
+@@ -7232,8 +7233,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
+ err = mark_chain_precision(env, insn->dst_reg);
+ if (err)
+ return err;
+- return adjust_ptr_min_max_vals(env, insn,
+- src_reg, dst_reg);
++ off_reg = *dst_reg;
++ return adjust_ptr_min_max_vals(env, insn, src_reg, &off_reg);
+ }
+ } else if (ptr_reg) {
+ /* pointer += scalar */
+--
+2.53.0
+
--- /dev/null
+From a1796ce78148ae9006bf059b322b037d68459f34 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jul 2026 04:29:10 +0000
+Subject: counter: microchip-tcb-capture: Fix DT channel validation
+
+From: Babanpreet Singh <bbnpreetsingh@gmail.com>
+
+[ Upstream commit f1a3a9946aab611dd2200c01ff122f64b033dad2 ]
+
+mchp_tc_probe() reads the devicetree "reg" cell - a u32, per the API
+contract of of_property_read_u32_index() - into a signed int, so the
+bounds check "channel > 2" fails to reject cell values at or above
+0x80000000: reinterpreted as a negative int, they compare below 2 and
+pass validation.
+
+A malformed devicetree can therefore drive a negative channel into the
+ATMEL_TC_REG() offset arithmetic, making the driver access syscon
+regmap offsets outside the TC block's register window, and into the
+"t%d_clk" clock-name formatting, where it truncates clk_name (sized
+for "t0_clk".."t2_clk").
+
+Declare channel as u32, matching the API contract; the unsigned
+comparison then rejects everything except channels 0..2. Adjust the
+format specifier to %u accordingly, which also resolves the W=1
+warning that exposed the gap:
+
+ microchip-tcb-capture.c:520:56: warning: '%d' directive output may
+ be truncated writing between 1 and 11 bytes into a region of size
+ 6 [-Wformat-truncation=]
+ note: directive argument in the range [-2147483648, 2]
+
+No behavior change for well-formed devicetrees: channels 0..2 take
+identical paths before and after.
+
+Fixes: 106b104137fd ("counter: Add microchip TCB capture counter")
+Assisted-by: Claude:claude-fable-5 [gcc W=1]
+Signed-off-by: Babanpreet Singh <bbnpreetsingh@gmail.com>
+Reviewed-by: Joshua Crofts <joshua.crofts1@gmail.com>
+Link: https://lore.kernel.org/r/20260714042910.7-1-bbnpreetsingh@gmail.com
+Signed-off-by: William Breathitt Gray <wbg@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/counter/microchip-tcb-capture.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/counter/microchip-tcb-capture.c b/drivers/counter/microchip-tcb-capture.c
+index 40d02df8acf75..822c072ffa20e 100644
+--- a/drivers/counter/microchip-tcb-capture.c
++++ b/drivers/counter/microchip-tcb-capture.c
+@@ -317,7 +317,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
+ char clk_name[7];
+ struct regmap *regmap;
+ struct clk *clk[3];
+- int channel;
++ u32 channel;
+ int ret, i;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+@@ -352,7 +352,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
+
+ priv->channel[i] = channel;
+
+- snprintf(clk_name, sizeof(clk_name), "t%d_clk", channel);
++ snprintf(clk_name, sizeof(clk_name), "t%u_clk", channel);
+
+ clk[i] = of_clk_get_by_name(np->parent, clk_name);
+ if (IS_ERR(clk[i])) {
+--
+2.53.0
+
--- /dev/null
+From 576a9fce7878612b4d771f82550c91a6be59a844 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 12:17:10 +0400
+Subject: net: hisilicon: hix5hd2_gmac: remove redundant NAPI delete
+
+From: Jiawen Liu <1298662399@qq.com>
+
+[ Upstream commit f307a7dc32097c11413178fca437a10d20890bc2 ]
+
+hix5hd2_dev_remove() calls netif_napi_del() before unregister_netdev().
+This is not needed because free_netdev() deletes all NAPI instances
+attached to the net_device.
+
+Remove the redundant call and let the networking core tear down the NAPI
+instance during unregister_netdev(). The probe error path still keeps its
+explicit netif_napi_del(), because the device has not been registered
+there.
+
+Fixes: 57c5bc9ad7d7 ("net: hisilicon: add hix5hd2 mac driver")
+Signed-off-by: Jiawen Liu <1298662399@qq.com>
+Link: https://patch.msgid.link/tencent_5FFD37A252B4FEA6A80AD25B17C8E904F005@qq.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hix5hd2_gmac.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+index 43f3146caf07e..18495d80e2e74 100644
+--- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
++++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+@@ -1291,7 +1291,6 @@ static int hix5hd2_dev_remove(struct platform_device *pdev)
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct hix5hd2_priv *priv = netdev_priv(ndev);
+
+- netif_napi_del(&priv->napi);
+ unregister_netdev(ndev);
+ mdiobus_unregister(priv->bus);
+ mdiobus_free(priv->bus);
+--
+2.53.0
+
--- /dev/null
+From f33a4801df1b07ac632666c632d3ea3dc182e5bb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 31 May 2021 17:32:46 +0300
+Subject: net: marvell: prestera: try to load previous fw version
+
+From: Vadym Kochan <vkochan@marvell.com>
+
+[ Upstream commit 47f26018a414ff640527be4ca814168e0b71eaf3 ]
+
+Lets try to load previous fw version in case the latest one is missing on
+existing system.
+
+Signed-off-by: Vadym Kochan <vkochan@marvell.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 8ae344eb540a ("net: prestera: validate firmware header length")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ethernet/marvell/prestera/prestera_pci.c | 83 ++++++++++++++-----
+ 1 file changed, 61 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/net/ethernet/marvell/prestera/prestera_pci.c b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+index be5677623455c..39cd3d5010147 100644
+--- a/drivers/net/ethernet/marvell/prestera/prestera_pci.c
++++ b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+@@ -16,6 +16,9 @@
+ #define PRESTERA_SUPP_FW_MAJ_VER 2
+ #define PRESTERA_SUPP_FW_MIN_VER 0
+
++#define PRESTERA_PREV_FW_MAJ_VER 2
++#define PRESTERA_PREV_FW_MIN_VER 0
++
+ #define PRESTERA_FW_PATH_FMT "mrvl/prestera/mvsw_prestera_fw-v%u.%u.img"
+
+ #define PRESTERA_FW_HDR_MAGIC 0x351D9D06
+@@ -166,6 +169,8 @@ struct prestera_fw_evtq {
+ };
+
+ struct prestera_fw {
++ struct prestera_fw_rev rev_supp;
++ const struct firmware *bin;
+ struct workqueue_struct *wq;
+ struct prestera_device dev;
+ u8 __iomem *ldr_regs;
+@@ -576,25 +581,24 @@ static void prestera_fw_rev_parse(const struct prestera_fw_header *hdr,
+ static int prestera_fw_rev_check(struct prestera_fw *fw)
+ {
+ struct prestera_fw_rev *rev = &fw->dev.fw_rev;
+- u16 maj_supp = PRESTERA_SUPP_FW_MAJ_VER;
+- u16 min_supp = PRESTERA_SUPP_FW_MIN_VER;
+
+- if (rev->maj == maj_supp && rev->min >= min_supp)
++ if (rev->maj == fw->rev_supp.maj && rev->min >= fw->rev_supp.min)
+ return 0;
+
+ dev_err(fw->dev.dev, "Driver supports FW version only '%u.%u.x'",
+- PRESTERA_SUPP_FW_MAJ_VER, PRESTERA_SUPP_FW_MIN_VER);
++ fw->rev_supp.maj, fw->rev_supp.min);
+
+ return -EINVAL;
+ }
+
+-static int prestera_fw_hdr_parse(struct prestera_fw *fw,
+- const struct firmware *img)
++static int prestera_fw_hdr_parse(struct prestera_fw *fw)
+ {
+- struct prestera_fw_header *hdr = (struct prestera_fw_header *)img->data;
+ struct prestera_fw_rev *rev = &fw->dev.fw_rev;
++ struct prestera_fw_header *hdr;
+ u32 magic;
+
++ hdr = (struct prestera_fw_header *)fw->bin->data;
++
+ magic = be32_to_cpu(hdr->magic_number);
+ if (magic != PRESTERA_FW_HDR_MAGIC) {
+ dev_err(fw->dev.dev, "FW img hdr magic is invalid");
+@@ -609,11 +613,52 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw,
+ return prestera_fw_rev_check(fw);
+ }
+
++static int prestera_fw_get(struct prestera_fw *fw)
++{
++ int ver_maj = PRESTERA_SUPP_FW_MAJ_VER;
++ int ver_min = PRESTERA_SUPP_FW_MIN_VER;
++ char fw_path[128];
++ int err;
++
++pick_fw_ver:
++ snprintf(fw_path, sizeof(fw_path), PRESTERA_FW_PATH_FMT,
++ ver_maj, ver_min);
++
++ err = request_firmware_direct(&fw->bin, fw_path, fw->dev.dev);
++ if (err) {
++ if (ver_maj == PRESTERA_SUPP_FW_MAJ_VER) {
++ ver_maj = PRESTERA_PREV_FW_MAJ_VER;
++ ver_min = PRESTERA_PREV_FW_MIN_VER;
++
++ dev_warn(fw->dev.dev,
++ "missing latest %s firmware, fall-back to previous %u.%u version\n",
++ fw_path, ver_maj, ver_min);
++
++ goto pick_fw_ver;
++ } else {
++ dev_err(fw->dev.dev, "failed to request previous firmware: %s\n",
++ fw_path);
++ return err;
++ }
++ }
++
++ dev_info(fw->dev.dev, "Loading %s ...", fw_path);
++
++ fw->rev_supp.maj = ver_maj;
++ fw->rev_supp.min = ver_min;
++ fw->rev_supp.sub = 0;
++
++ return 0;
++}
++
++static void prestera_fw_put(struct prestera_fw *fw)
++{
++ release_firmware(fw->bin);
++}
++
+ static int prestera_fw_load(struct prestera_fw *fw)
+ {
+ size_t hlen = sizeof(struct prestera_fw_header);
+- const struct firmware *f;
+- char fw_path[128];
+ int err;
+
+ err = prestera_ldr_wait_reg32(fw, PRESTERA_LDR_READY_REG,
+@@ -632,30 +677,24 @@ static int prestera_fw_load(struct prestera_fw *fw)
+
+ fw->ldr_wr_idx = 0;
+
+- snprintf(fw_path, sizeof(fw_path), PRESTERA_FW_PATH_FMT,
+- PRESTERA_SUPP_FW_MAJ_VER, PRESTERA_SUPP_FW_MIN_VER);
+-
+- err = request_firmware_direct(&f, fw_path, fw->dev.dev);
+- if (err) {
+- dev_err(fw->dev.dev, "failed to request firmware file\n");
++ err = prestera_fw_get(fw);
++ if (err)
+ return err;
+- }
+
+- err = prestera_fw_hdr_parse(fw, f);
++ err = prestera_fw_hdr_parse(fw);
+ if (err) {
+ dev_err(fw->dev.dev, "FW image header is invalid\n");
+ goto out_release;
+ }
+
+- prestera_ldr_write(fw, PRESTERA_LDR_IMG_SIZE_REG, f->size - hlen);
++ prestera_ldr_write(fw, PRESTERA_LDR_IMG_SIZE_REG, fw->bin->size - hlen);
+ prestera_ldr_write(fw, PRESTERA_LDR_CTL_REG, PRESTERA_LDR_CTL_DL_START);
+
+- dev_info(fw->dev.dev, "Loading %s ...", fw_path);
+-
+- err = prestera_ldr_fw_send(fw, f->data + hlen, f->size - hlen);
++ err = prestera_ldr_fw_send(fw, fw->bin->data + hlen,
++ fw->bin->size - hlen);
+
+ out_release:
+- release_firmware(f);
++ prestera_fw_put(fw);
+ return err;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 786bfed5342fe96166ede365ed85c472312a89bf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 11:04:02 +0300
+Subject: net/mlx5: fw_tracer, return NULL on create error
+
+From: Michael Guralnik <michaelgur@nvidia.com>
+
+[ Upstream commit af39eb111ce6b5eba9c08513b62c4868eb7e7fd5 ]
+
+Tracer creation can fail by returning either NULL or ERR_PTR.
+The return value is stored without a check on the device, and users
+treat ERR_PTR and NULL the same way.
+This also causes a crash in the core dump logic, which is missing the
+ERR_PTR check and ends up dereferencing it, as shown in the trace below.
+
+Switch tracer creation to return NULL on failure only, so callers only
+need a single NULL check.
+
+ Internal error: Oops: 0000000096000006 [#1] SMP
+ Modules linked in: mlx5_ib ib_uverbs ib_core ipv6 mlx5_core
+ CPU: 1 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted 6.19.7 #1 PREEMPT(none)
+ Workqueue: mlx5_health0001:01:00.0 mlx5_fw_reporter_err_work [mlx5_core]
+ pstate: a3400009 (NzCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
+ pc : mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core]
+ lr : mlx5_fw_tracer_trigger_core_dump_general+0x40/0xe0 [mlx5_core]
+ sp : ffff800081cf3c40
+ x29: ffff800081cf3c90 x28: 0000000000000000 x27: 0000000000000000
+ x26: ffff000080018828 x25: 0000000000000000 x24: ffff000080304a05
+ x23: ffff800081cf3d80 x22: ffff0000847e01a0 x21: 0000000000000000
+ x20: ffff0000847e01a0 x19: ffffffffffffffa1 x18: ffff80008310bbf0
+ x17: ffff800080119650 x16: ffff80008010df54 x15: ffff80008010d4ac
+ x14: ffff800079c202e4 x13: ffff80008002fe60 x12: ffff800080119650
+ x11: ffff80008010df54 x10: ffff80008010d4ac x9 : ffff800079c203d8
+ x8 : ffff800081cf3c88 x7 : 0000000000000000 x6 : 0000000000000000
+ x5 : 0000000000000000 x4 : 0000000000000008 x3 : 0000000000000030
+ x2 : 0000000000000008 x1 : 0000000000000000 x0 : 00000000c5c4000e
+ Call trace:
+ mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core] (P)
+ mlx5_fw_reporter_dump+0x30/0x2e0 [mlx5_core]
+ devlink_health_do_dump+0x9c/0x160
+ devlink_health_report+0x1c0/0x288
+ mlx5_fw_reporter_err_work+0xac/0xc0 [mlx5_core]
+ process_one_work+0x15c/0x3d8
+ worker_thread+0x18c/0x320
+ kthread+0x148/0x228
+ ret_from_fork+0x10/0x20
+ Code: b9400000 5ac00800 7a401800 540003ca (3940a260)
+ ---[ end trace 0000000000000000 ]---
+ Kernel panic - not syncing: Oops: Fatal exception
+ SMP: stopping secondary CPUs
+ Kernel Offset: disabled
+ CPU features: 0x000000,00078031,75fce5a1,35fffe67
+ Memory Limit: none
+ ---[ end Kernel panic - not syncing: Oops: Fatal exception ]---
+
+Fixes: fd1483fe1f9f ("net/mlx5: Add support for FW reporter dump")
+Signed-off-by: Michael Guralnik <michaelgur@nvidia.com>
+Reviewed-by: Shay Drori <shayd@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260729080402.2427184-1-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ethernet/mellanox/mlx5/core/diag/fw_tracer.c | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+index a83bfdfe51325..9817de5590b56 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+@@ -1036,13 +1036,11 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
+
+ tracer = kvzalloc(sizeof(*tracer), GFP_KERNEL);
+ if (!tracer)
+- return ERR_PTR(-ENOMEM);
++ return NULL;
+
+ tracer->work_queue = create_singlethread_workqueue("mlx5_fw_tracer");
+- if (!tracer->work_queue) {
+- err = -ENOMEM;
++ if (!tracer->work_queue)
+ goto free_tracer;
+- }
+
+ tracer->dev = dev;
+
+@@ -1082,7 +1080,7 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
+ destroy_workqueue(tracer->work_queue);
+ free_tracer:
+ kvfree(tracer);
+- return ERR_PTR(err);
++ return NULL;
+ }
+
+ static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data);
+@@ -1093,7 +1091,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
+ struct mlx5_core_dev *dev;
+ int err;
+
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return 0;
+
+ dev = tracer->dev;
+@@ -1136,7 +1134,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
+ /* Stop tracer + Cleanup HW resources */
+ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
+ {
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return;
+
+ mlx5_core_dbg(tracer->dev, "FWTracer: Cleanup, is owner ? (%d)\n",
+@@ -1155,7 +1153,7 @@ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
+ /* Free software resources (Buffers, etc ..) */
+ void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer)
+ {
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return;
+
+ mlx5_core_dbg(tracer->dev, "FWTracer: Destroy\n");
+@@ -1204,7 +1202,7 @@ int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer)
+ struct mlx5_core_dev *dev;
+ int err;
+
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return 0;
+
+ dev = tracer->dev;
+--
+2.53.0
+
--- /dev/null
+From 46ec1c475f4f261e39c26c7f9b2bdf540545b29b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Nov 2020 14:42:45 +0200
+Subject: net/mlx5: Remove second FW tracer check
+
+From: Leon Romanovsky <leonro@nvidia.com>
+
+[ Upstream commit 7e615b9978021a034124166d4fa3dc4fc0ea4b16 ]
+
+The FW tracer check is called twice, so delete one of them.
+
+Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
+Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
+Stable-dep-of: af39eb111ce6 ("net/mlx5: fw_tracer, return NULL on create error")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c | 2 +-
+ drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c | 7 +------
+ 2 files changed, 2 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+index f3985421e739e..a83bfdfe51325 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+@@ -1205,7 +1205,7 @@ int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer)
+ int err;
+
+ if (IS_ERR_OR_NULL(tracer))
+- return -EINVAL;
++ return 0;
+
+ dev = tracer->dev;
+ mlx5_fw_tracer_cleanup(tracer);
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
+index a2d9904e10492..d2bf20035e20d 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
+@@ -208,16 +208,11 @@ static void mlx5_fw_live_patch_event(struct work_struct *work)
+ struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset,
+ fw_live_patch_work);
+ struct mlx5_core_dev *dev = fw_reset->dev;
+- struct mlx5_fw_tracer *tracer;
+
+ mlx5_core_info(dev, "Live patch updated firmware version: %d.%d.%d\n", fw_rev_maj(dev),
+ fw_rev_min(dev), fw_rev_sub(dev));
+
+- tracer = dev->tracer;
+- if (IS_ERR_OR_NULL(tracer))
+- return;
+-
+- if (mlx5_fw_tracer_reload(tracer))
++ if (mlx5_fw_tracer_reload(dev->tracer))
+ mlx5_core_err(dev, "Failed to reload FW tracer\n");
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 8dcbc65e8f0df3058b7802377b217d59e8d7f226 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 12:36:18 +0800
+Subject: net/ncsi: fix heap OOB read in NCSI_CMD_SEND_CMD payload length
+
+From: Henry Martin <bsdhenrymartin@gmail.com>
+
+[ Upstream commit afa58b7384913c8773d837acdb07b035690ec5d2 ]
+
+ncsi_send_cmd_nl() takes the number of bytes to copy from the
+attacker-controlled ncsi_pkt_hdr.length field of the in-band packet
+header, while the source buffer is the NCSI_ATTR_DATA netlink
+attribute whose readable size is nla_len() - sizeof(ncsi_pkt_hdr).
+The two length sources are never cross-checked: only
+nla_len() >= sizeof(struct ncsi_pkt_hdr) is enforced.
+
+With hdr->length set larger than the attribute payload (up to 65535
+against at most 2032 readable bytes), ncsi_cmd_handler_oem() copies
+past the end of the netlink attribute buffer with unsafe_memcpy(),
+leaking up to ~64KB of kernel heap memory into the transmitted NCSI
+command packet. The destination skb is sized by the declared payload,
+so the write side does not overflow - this is a pure OOB read /
+information leak, reachable with CAP_NET_ADMIN on systems with a
+registered NCSI device (e.g. OpenBMC on Aspeed BMC SoCs, where
+NET_NCSI=y is standard).
+
+Reject commands whose declared payload extends past the end of the
+data attribute.
+
+The issue was found by the autokbug dynamic kernel fuzzer at Tencent
+Yunding Lab.
+
+Fixes: 9771b8ccdfa6 ("net/ncsi: Extend NC-SI Netlink interface to allow user space to send NC-SI command")
+Reported-by: Henry Martin <bsdhenrymartin@gmail.com>
+Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>
+Link: https://patch.msgid.link/20260803043618.3210301-1-bsdhenrymartin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ncsi/ncsi-netlink.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/net/ncsi/ncsi-netlink.c b/net/ncsi/ncsi-netlink.c
+index db350b8f5d88b..82b22368a540a 100644
+--- a/net/ncsi/ncsi-netlink.c
++++ b/net/ncsi/ncsi-netlink.c
+@@ -461,6 +461,10 @@ static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info)
+ nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN;
+ nca.info = info;
+ nca.payload = ntohs(hdr->length);
++ if (nca.payload > len - sizeof(*hdr)) {
++ ret = -EINVAL;
++ goto out_netlink;
++ }
+ nca.data = data + sizeof(*hdr);
+
+ ret = ncsi_xmit_cmd(&nca);
+--
+2.53.0
+
--- /dev/null
+From 87c478701db0006f128b41f14e8d306dba897f5f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 18:20:06 -0400
+Subject: net/openvswitch: check Ethernet header length in key_extract()
+
+From: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+
+[ Upstream commit cf6f8b29befb92173659bcef6a441d274947bfae ]
+
+When a packet arrives on an ARPHRD_NONE device (e.g. TUN),
+ovs_flow_key_extract() trusts the user-provided skb->protocol field: if
+it is ETH_P_TEB, the packet is classified as MAC_PROTO_ETHERNET and
+key_extract() is called without ensuring the skb has ETH_HLEN (14) bytes
+of linear data. key_extract() unconditionally pulls 2 * ETH_ALEN bytes
+for MAC addresses and parse_ethertype() pulls 2 more, either of which
+triggers a kernel BUG in __skb_pull() when the linear area is too small.
+
+ kernel BUG at include/linux/skbuff.h:2848!
+ RIP: 0010:key_extract+0xa7e/0xd90 net/openvswitch/flow.c:933
+ ovs_flow_key_extract+0x419/0xa70
+ ovs_vport_receive+0x222/0x390
+ netdev_frame_hook+0x3e0/0x630
+ tun_get_user+0x2d0c/0x38e0
+
+Fixed by calling check_header() in key_extract() before accessing the
+Ethernet header.
+
+Fixes: 217ac77a3c25 ("openvswitch: allow L3 netdev ports")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Reviewed-by: Eelco Chaudron <echaudro@redhat.com>
+Signed-off-by: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
+Link: https://patch.msgid.link/20260730222006.118652-1-blbllhy@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/flow.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
+index 862d376930d79..3f8a0d05161c5 100644
+--- a/net/openvswitch/flow.c
++++ b/net/openvswitch/flow.c
+@@ -748,8 +748,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ * Ethernet header
+ * @key: output flow key
+ *
+- * The caller must ensure that skb->len >= ETH_HLEN.
+- *
+ * Initializes @skb header fields as follows:
+ *
+ * - skb->mac_header: the L2 header.
+@@ -769,8 +767,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ */
+ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+ {
+- struct ethhdr *eth;
+-
+ /* Flags are always used as part of stats */
+ key->tp.flags = 0;
+
+@@ -785,6 +781,13 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+ skb_reset_network_header(skb);
+ key->eth.type = skb->protocol;
+ } else {
++ struct ethhdr *eth;
++ int err;
++
++ err = check_header(skb, ETH_HLEN);
++ if (unlikely(err))
++ return err;
++
+ eth = eth_hdr(skb);
+ ether_addr_copy(key->eth.src, eth->h_source);
+ ether_addr_copy(key->eth.dst, eth->h_dest);
+--
+2.53.0
+
--- /dev/null
+From a579366685aa265dc9bca61e60a3d95f3f99b16f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 8 Aug 2021 12:08:34 -0700
+Subject: net: openvswitch: fix kernel-doc warnings in flow.c
+
+From: Randy Dunlap <rdunlap@infradead.org>
+
+[ Upstream commit d6e712aa7e6a3d5a9633f4bcbe2237f3edc292bd ]
+
+Repair kernel-doc notation in a few places to make it conform to
+the expected format.
+
+Fixes the following kernel-doc warnings:
+
+flow.c:296: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst
+ * Parse vlan tag from vlan header.
+flow.c:296: warning: missing initial short description on line:
+ * Parse vlan tag from vlan header.
+flow.c:537: warning: No description found for return value of 'key_extract_l3l4'
+flow.c:769: warning: No description found for return value of 'key_extract'
+
+Signed-off-by: Randy Dunlap <rdunlap@infradead.org>
+Cc: Pravin B Shelar <pshelar@ovn.org>
+Cc: dev@openvswitch.org
+Link: https://lore.kernel.org/r/20210808190834.23362-1-rdunlap@infradead.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: cf6f8b29befb ("net/openvswitch: check Ethernet header length in key_extract()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/flow.c | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
+index beacb1b46706e..862d376930d79 100644
+--- a/net/openvswitch/flow.c
++++ b/net/openvswitch/flow.c
+@@ -293,14 +293,14 @@ static bool icmp6hdr_ok(struct sk_buff *skb)
+ }
+
+ /**
+- * Parse vlan tag from vlan header.
++ * parse_vlan_tag - Parse vlan tag from vlan header.
+ * @skb: skb containing frame to parse
+ * @key_vh: pointer to parsed vlan tag
+ * @untag_vlan: should the vlan header be removed from the frame
+ *
+- * Returns ERROR on memory error.
+- * Returns 0 if it encounters a non-vlan or incomplete packet.
+- * Returns 1 after successfully parsing vlan tag.
++ * Return: ERROR on memory error.
++ * %0 if it encounters a non-vlan or incomplete packet.
++ * %1 after successfully parsing vlan tag.
+ */
+ static int parse_vlan_tag(struct sk_buff *skb, struct vlan_head *key_vh,
+ bool untag_vlan)
+@@ -533,6 +533,7 @@ static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key)
+ * L3 header
+ * @key: output flow key
+ *
++ * Return: %0 if successful, otherwise a negative errno value.
+ */
+ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ {
+@@ -749,8 +750,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ *
+ * The caller must ensure that skb->len >= ETH_HLEN.
+ *
+- * Returns 0 if successful, otherwise a negative errno value.
+- *
+ * Initializes @skb header fields as follows:
+ *
+ * - skb->mac_header: the L2 header.
+@@ -765,6 +764,8 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ *
+ * - skb->protocol: the type of the data starting at skb->network_header.
+ * Equals to key->eth.type.
++ *
++ * Return: %0 if successful, otherwise a negative errno value.
+ */
+ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+ {
+--
+2.53.0
+
--- /dev/null
+From 10a238ee1e60b47a9419599f44c91a49203b8732 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 28 Oct 2020 01:48:49 +0100
+Subject: net: openvswitch: Fix kerneldoc warnings
+
+From: Andrew Lunn <andrew@lunn.ch>
+
+[ Upstream commit 210bba6790dc150c0dd65da2cbc4de39e5fa3a74 ]
+
+net/openvswitch/flow.c:303: warning: Function parameter or member 'key_vh' not described in 'parse_vlan_tag'
+net/openvswitch/flow.c:303: warning: Function parameter or member 'skb' not described in 'parse_vlan_tag'
+net/openvswitch/flow.c:303: warning: Function parameter or member 'untag_vlan' not described in 'parse_vlan_tag'
+net/openvswitch/vport.c:122: warning: Function parameter or member 'parms' not described in 'ovs_vport_alloc'
+
+Signed-off-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/20201028004849.930094-1-andrew@lunn.ch
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: cf6f8b29befb ("net/openvswitch: check Ethernet header length in key_extract()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/flow.c | 4 ++++
+ net/openvswitch/vport.c | 4 +++-
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
+index 94531289ed26a..beacb1b46706e 100644
+--- a/net/openvswitch/flow.c
++++ b/net/openvswitch/flow.c
+@@ -294,6 +294,10 @@ static bool icmp6hdr_ok(struct sk_buff *skb)
+
+ /**
+ * Parse vlan tag from vlan header.
++ * @skb: skb containing frame to parse
++ * @key_vh: pointer to parsed vlan tag
++ * @untag_vlan: should the vlan header be removed from the frame
++ *
+ * Returns ERROR on memory error.
+ * Returns 0 if it encounters a non-vlan or incomplete packet.
+ * Returns 1 after successfully parsing vlan tag.
+diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
+index ced707ff6dd97..2c876424864d2 100644
+--- a/net/openvswitch/vport.c
++++ b/net/openvswitch/vport.c
+@@ -111,10 +111,12 @@ struct vport *ovs_vport_locate(const struct net *net, const char *name)
+ *
+ * @priv_size: Size of private data area to allocate.
+ * @ops: vport device ops
++ * @parms: information about new vport.
+ *
+ * Allocate and initialize a new vport defined by @ops. The vport will contain
+ * a private data area of size @priv_size that can be accessed using
+- * vport_priv(). vports that are no longer needed should be released with
++ * vport_priv(). Some parameters of the vport will be initialized from @parms.
++ * @vports that are no longer needed should be released with
+ * vport_free().
+ */
+ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
+--
+2.53.0
+
--- /dev/null
+From 4e0de47af795cb2bfa63bc29418a4b3ebdfe48e0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 22:19:06 +0800
+Subject: net: prestera: validate firmware header length
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 8ae344eb540af3f457179b52bc6061416752485c ]
+
+prestera_fw_hdr_parse() reads the firmware header before checking
+that the firmware image contains that header.
+
+Reject images shorter than struct prestera_fw_header before decoding the
+magic and version fields.
+
+Fixes: 4c2703dfd7fabb ("net: marvell: prestera: Add PCI interface support")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Acked-by: Elad Nachman <enachman@marvell.com>
+Link: https://patch.msgid.link/20260731141500.1-prestera-v2-pengpeng@iscas.ac.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/marvell/prestera/prestera_pci.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/marvell/prestera/prestera_pci.c b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+index 39cd3d5010147..bdc57f4245930 100644
+--- a/drivers/net/ethernet/marvell/prestera/prestera_pci.c
++++ b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+@@ -597,6 +597,9 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw)
+ struct prestera_fw_header *hdr;
+ u32 magic;
+
++ if (fw->bin->size < sizeof(*hdr))
++ return -EINVAL;
++
+ hdr = (struct prestera_fw_header *)fw->bin->data;
+
+ magic = be32_to_cpu(hdr->magic_number);
+--
+2.53.0
+
--- /dev/null
+From fd7041340a21e9e91e976363eb3cd754a5b75d88 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 22:18:30 +0200
+Subject: net: qrtr: ns: Raise lookup limit to 128
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Łukasz Patron <priv.luk@gmail.com>
+
+[ Upstream commit 7fc1c937b6b37c77df4ba374c37435ab06a2e945 ]
+
+Current limit of 64 is not enough for Sony Xperia 10 VII (SM6475).
+
+After merging v6.6.142 into a downstream AOSP device, it's stuck on
+boot animation and following log spam can be observed in dmesg:
+
+E qrtr : ctrl_cmd_new_lookup(): QRTR client node exceeds max lookup limit!
+E qrtr : qrtr_ns_worker(): failed while handling packet from 1:16600
+
+No idea why it needs more than 64 client lookups, but it appears to
+work fine with 128 as it did when there were no limits.
+
+I don't really have a good way to investigate what it needs all
+these lookups for as most of the userspace is closed source.
+
+Fixes: 5640227d9a21 ("net: qrtr: ns: Limit the maximum number of lookups")
+Signed-off-by: Łukasz Patron <priv.luk@gmail.com>
+Link: https://patch.msgid.link/20260804201919.1148015-1-priv.luk@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/ns.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c
+index 3ebb5d39e153f..4246d21da5d14 100644
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -77,7 +77,7 @@ struct qrtr_node {
+ */
+ #define QRTR_NS_MAX_NODES 512
+ #define QRTR_NS_MAX_SERVERS 256
+-#define QRTR_NS_MAX_LOOKUPS 64
++#define QRTR_NS_MAX_LOOKUPS 128
+
+ static u16 node_count;
+
+--
+2.53.0
+
--- /dev/null
+From 497379f2999453c7f76dc44c6c135b83acede912 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 15:20:48 +0000
+Subject: net: remove WARN_ON_ONCE() from sk_mc_loop()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit b8a39a09ae4eaae04309e1e38ed6a1101d967496 ]
+
+sk_mc_loop() can be called for sockets that are neither AF_INET
+nor AF_INET6 (e.g. AF_PACKET sockets when sending packets via raw/packet
+socket over virtual devices such as VRF or ipvlan).
+
+In such cases, sk_family is not AF_INET/AF_INET6 and sk_mc_loop() falls
+through the switch statement and triggers WARN_ON_ONCE(1).
+
+Non-INET sockets do not support IP_MULTICAST_LOOP or IPV6_MULTICAST_LOOP
+options, so loopback should default to true without generating a warning.
+
+Fixes: f60e5990d9c1 ("ipv6: protect skb->sk accesses from recursive dereference inside the stack")
+Reported-by: syzbot+22c3218a6fa219e47321@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/6a72024c.13623e66.bdc14.0019.GAE@google.com/T/#u
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260804152048.2134341-1-edumazet@google.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/sock.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/net/core/sock.c b/net/core/sock.c
+index 963ea323362ad..b51a154ec5913 100644
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -699,7 +699,6 @@ bool sk_mc_loop(struct sock *sk)
+ return inet6_sk(sk)->mc_loop;
+ #endif
+ }
+- WARN_ON_ONCE(1);
+ return true;
+ }
+ EXPORT_SYMBOL(sk_mc_loop);
+--
+2.53.0
+
--- /dev/null
+From 8a29fa5617bd7cce0e7f88f186e2680b5c4d8ac9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 05:44:11 -0400
+Subject: net/sched: cls_route: fix fastmap use-after-free on filter
+
+From: Jamal Hadi Salim <jhs@mojatatu.com>
+
+[ Upstream commit 47d7f7051253bdc02b1d245d87e38f16d31a74df ]
+
+The route4 classifier maintains a 16-slot fastmap cache that stores raw
+struct route4_filter pointers indexed by (id, iif). The reader
+(route4_classify) populates this cache via route4_set_fastmap() for every
+classified packet that hits a filter. The writer (route4_delete,
+route4_change) clears the cache via route4_reset_fastmap() before
+RCU-deferred kfree of the filter.
+
+This creates a UAF race:
+ 1. Reader walks the RCU-protected bucket chain, finds filter f
+ 2. Writer unlinks f, calls route4_reset_fastmap(), then tcf_queue_work()
+ 3. Reader calls route4_set_fastmap() and writes f into the cache
+ *after* the writer's reset, caching a pointer about to be freed
+ 4. After the RCU grace period, kfree(f) executes
+ 5. Next classified packet on the same (id, iif) tuple hits the stale
+ fastmap entry and reads f->res from freed memory
+
+Reproduced with an mdelay(100) accelerator in route4_set_fastmap() and a
+concurrent add/delete stress test (provided by both zdi and Santosh).
+Both triggered KASAN slab-use-after-free reports in the route4 fastmap
+paths.
+
+Fix:
+Introduce a per-filter boolean dying flag to suppress stale fastmap
+republishing by in-flight readers.
+
+Fixes: 1109c00547fc ("net: sched: RCU cls_route")
+Reported-by: zdi-disclosures@trendmicro.com
+Reported-by: Santosh Kalluri <santosh.kalluri129@gmail.com>
+Suggested-by: Paolo Abeni <pabeni@redhat.com>
+Tested-by: Victor Nogueira <victor@mojatatu.com>
+Tested-by: Santosh Kalluri <santosh.kalluri129@gmail.com>
+Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260729094411.46257-1-jhs@mojatatu.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_route.c | 35 ++++++++++++++++++++++++++---------
+ 1 file changed, 26 insertions(+), 9 deletions(-)
+
+diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
+index 1ad4b3e60eb3b..695c91961e33b 100644
+--- a/net/sched/cls_route.c
++++ b/net/sched/cls_route.c
+@@ -51,6 +51,7 @@ struct route4_filter {
+ struct tcf_result res;
+ struct tcf_exts exts;
+ u32 handle;
++ bool dying;
+ struct route4_bucket *bkt;
+ struct tcf_proto *tp;
+ struct rcu_work rwork;
+@@ -65,9 +66,11 @@ static inline int route4_fastmap_hash(u32 id, int iif)
+
+ static DEFINE_SPINLOCK(fastmap_lock);
+ static void
+-route4_reset_fastmap(struct route4_head *head)
++route4_reset_fastmap(struct route4_head *head, struct route4_filter *f)
+ {
+ spin_lock_bh(&fastmap_lock);
++ if (f)
++ f->dying = true;
+ memset(head->fastmap, 0, sizeof(head->fastmap));
+ spin_unlock_bh(&fastmap_lock);
+ }
+@@ -80,9 +83,11 @@ route4_set_fastmap(struct route4_head *head, u32 id, int iif,
+
+ /* fastmap updates must look atomic to aling id, iff, filter */
+ spin_lock_bh(&fastmap_lock);
+- head->fastmap[h].id = id;
+- head->fastmap[h].iif = iif;
+- head->fastmap[h].filter = f;
++ if (f == ROUTE4_FAILURE || !f->dying) {
++ head->fastmap[h].id = id;
++ head->fastmap[h].iif = iif;
++ head->fastmap[h].filter = f;
++ }
+ spin_unlock_bh(&fastmap_lock);
+ }
+
+@@ -295,6 +300,13 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
+ next = rtnl_dereference(f->next);
+ RCU_INIT_POINTER(b->ht[h2], next);
+ tcf_unbind_filter(tp, &f->res);
++ /* Mark the filter dying under fastmap_lock so
++ * any in-flight reader that still holds it
++ * will skip the republish in route4_set_fastmap().
++ */
++ spin_lock_bh(&fastmap_lock);
++ f->dying = true;
++ spin_unlock_bh(&fastmap_lock);
+ if (tcf_exts_get_net(&f->exts))
+ route4_queue_work(f);
+ else
+@@ -305,6 +317,11 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
+ kfree_rcu(b, rcu);
+ }
+ }
++
++ /* All filters are unlinked and marked dying, so no in-flight
++ * reader can republish a stale entry after this reset.
++ */
++ route4_reset_fastmap(head, NULL);
+ kfree_rcu(head, rcu);
+ }
+
+@@ -332,11 +349,11 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,
+ /* unlink it */
+ RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
+
+- /* Remove any fastmap lookups that might ref filter
+- * notice we unlink'd the filter so we can't get it
+- * back in the fastmap.
++ /* Clear any fastmap entries that may ref this filter and
++ * mark it dying so in-flight readers can't republish it
++ * after the reset.
+ */
+- route4_reset_fastmap(head);
++ route4_reset_fastmap(head, f);
+
+ /* Delete it */
+ tcf_unbind_filter(tp, &f->res);
+@@ -551,7 +568,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
+ }
+ }
+
+- route4_reset_fastmap(head);
++ route4_reset_fastmap(head, fold);
+ *arg = f;
+ if (fold) {
+ tcf_unbind_filter(tp, &fold->res);
+--
+2.53.0
+
--- /dev/null
+From a1a97b7643c9e9fe3d5a13a31ea26d3d49139bf3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 21:14:16 +0200
+Subject: net/sched: sch_cake: drop WARN_ON(1) for malformed packets in ACK
+ filter
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Toke Høiland-Jørgensen <toke@toke.dk>
+
+[ Upstream commit 2a33516f9ef59ad11844d4fc152f889449b5daf3 ]
+
+The sch_cake ACK filter parses packets to find the TCP header and filter
+duplicated ACKs if the flow is backlogged. The parsing code contains a
+WARN_ON(1) which can be triggered by a malformed IP header in certain
+cases. Depending on the system configuration, this leads either to
+either spamming dmesg with warnings, or a panic if panic_on_warn is set.
+
+The code already correctly skips the offending packet in the branch that
+triggers the warning, so the WARN_ON itself doesn't really serve any
+purpose. So just drop it altogether to avoid the inconvenient side
+effects.
+
+Fixes: 8b7138814f29 ("sch_cake: Add optional ACK filter")
+Reported-by: Zhiling Zou <zhilinz@nebusec.ai>
+Reported-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
+Link: https://patch.msgid.link/20260729191417.45665-1-toke@toke.dk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_cake.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c
+index 45b175e53aac0..8e3010a183822 100644
+--- a/net/sched/sch_cake.c
++++ b/net/sched/sch_cake.c
+@@ -1281,7 +1281,6 @@ static struct sk_buff *cake_ack_filter(struct cake_sched_data *q,
+
+ seglen = ntohs(ipv6h_check->payload_len);
+ } else {
+- WARN_ON(1); /* shouldn't happen */
+ continue;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From ff1e83d829b7ef011656a38c67d0c57d8446a81b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:01:53 +0200
+Subject: net/smc: fix qentry overwrite for CONFIRM_LINK and ADD_LINK_CONT in
+ smc_llc_event_handler()
+
+From: Mahanta Jambigi <mjambigi@linux.ibm.com>
+
+[ Upstream commit 976245094925bab9bc39366b2e9ab44ffcde61d0 ]
+
+The SMC_LLC_CONFIRM_LINK / SMC_LLC_ADD_LINK_CONT branch in
+smc_llc_event_handler() stores an incoming qentry into the local LLC flow
+without first checking whether a qentry is already pending. If a malicious or
+buggy peer sends a second CONFIRM_LINK or ADD_LINK_CONT request while a flow is
+active and flow->qentry is already set, smc_llc_flow_qentry_set() overwrites the
+pointer without freeing the previous allocation, leaking one kmalloc-96 object
+per spurious message.
+
+The sibling SMC_LLC_DELETE_LINK branch already has the correct !flow->qentry
+guard. Apply the same guard to the CONFIRM_LINK/ADD_LINK_CONT branch so that a
+duplicate message when qentry is already occupied falls through to break and is
+freed by the kfree(qentry) at the out: label, rather than silently leaking the
+existing allocation.
+
+The response direction (smc_llc_rx_response()) is unaffected: it already guards
+with flow->qentry at the equivalent site and drops duplicate responses
+correctly.
+
+Fixes: 0fb0b02bd6fd ("net/smc: adapt SMC client code to use the LLC flow")
+Signed-off-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
+Reviewed-by: Hidayath Khan <hidayath@linux.ibm.com>
+Reviewed-by: Sidraya Jayagond <sidraya@linux.ibm.com>
+Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
+Link: https://patch.msgid.link/20260729130153.970800-1-mjambigi@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/smc_llc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c
+index d5ee961ca72d5..572d02bfd3eda 100644
+--- a/net/smc/smc_llc.c
++++ b/net/smc/smc_llc.c
+@@ -1582,7 +1582,8 @@ static void smc_llc_event_handler(struct smc_llc_qentry *qentry)
+ return;
+ case SMC_LLC_CONFIRM_LINK:
+ case SMC_LLC_ADD_LINK_CONT:
+- if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) {
++ if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE &&
++ !lgr->llc_flow_lcl.qentry) {
+ /* a flow is waiting for this message */
+ smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry);
+ wake_up(&lgr->llc_msg_waiter);
+--
+2.53.0
+
--- /dev/null
+From 976a83e5b6dc1430f134bd5ea8cab7049c145db8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 30 Jun 2026 14:31:00 -0400
+Subject: NFS: Pin the 'struct nfs_server' during a FREE_STATEID call
+
+From: Anna Schumaker <anna.schumaker@hammerspace.com>
+
+[ Upstream commit cf616096a0f3a2b60f7d68b6b39674a6867ded9c ]
+
+Dan Aloni reports that he was able to hit a use-after-free bug if a
+FREE_STATEID operation gets delayed for whatever reason. Fix this by
+bumping the refcount of the 'struct nfs_server' object for the duration
+of the FREE_STATEID so it doesn't get cleaned up from underneath us
+while operations are still in flight.
+
+Reported-by: Dan Aloni <dan.aloni@vastdata.com>
+Fixes: 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call")
+Tested-by: Dan Aloni <dan.aloni@vastdata.com>
+Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/nfs4proc.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index bd97e0b61e70d..c455f6a8f61ae 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -10138,6 +10138,7 @@ static void nfs41_free_stateid_release(void *calldata)
+ struct nfs_free_stateid_data *data = calldata;
+ struct nfs_client *clp = data->server->nfs_client;
+
++ nfs_sb_deactive(data->server->super);
+ nfs_put_client(clp);
+ kfree(calldata);
+ }
+@@ -10179,6 +10180,10 @@ static int nfs41_free_stateid(struct nfs_server *server,
+
+ if (!refcount_inc_not_zero(&clp->cl_count))
+ return -EIO;
++ if (!nfs_sb_active(server->super)) {
++ nfs_put_client(clp);
++ return -EIO;
++ }
+
+ nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
+ &task_setup.rpc_client, &msg);
+--
+2.53.0
+
--- /dev/null
+From 88b5017ecd162dfb0f270fbbf049a07a999ddc58 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 3 Nov 2021 06:24:40 -0400
+Subject: nfs4: take a reference on the nfs_client when running FREE_STATEID
+
+From: Scott Mayhew <smayhew@redhat.com>
+
+[ Upstream commit 576acc259146af848cec0940f573f7125a116b9f ]
+
+During umount, the session slot tables are freed. If there are
+outstanding FREE_STATEID tasks, a use-after-free and slab corruption can
+occur when rpc_exit_task calls rpc_call_done -> nfs41_sequence_done ->
+nfs4_sequence_process/nfs41_sequence_free_slot.
+
+Prevent that from happening by taking a reference on the nfs_client in
+nfs41_free_stateid and putting it in nfs41_free_stateid_release.
+
+Signed-off-by: Scott Mayhew <smayhew@redhat.com>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Stable-dep-of: cf616096a0f3 ("NFS: Pin the 'struct nfs_server' during a FREE_STATEID call")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/nfs4proc.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index 170e9eaf536af..bd97e0b61e70d 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -10135,6 +10135,10 @@ static void nfs41_free_stateid_done(struct rpc_task *task, void *calldata)
+
+ static void nfs41_free_stateid_release(void *calldata)
+ {
++ struct nfs_free_stateid_data *data = calldata;
++ struct nfs_client *clp = data->server->nfs_client;
++
++ nfs_put_client(clp);
+ kfree(calldata);
+ }
+
+@@ -10171,6 +10175,10 @@ static int nfs41_free_stateid(struct nfs_server *server,
+ };
+ struct nfs_free_stateid_data *data;
+ struct rpc_task *task;
++ struct nfs_client *clp = server->nfs_client;
++
++ if (!refcount_inc_not_zero(&clp->cl_count))
++ return -EIO;
+
+ nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
+ &task_setup.rpc_client, &msg);
+--
+2.53.0
+
--- /dev/null
+From 744a71847e17ae65e6191745b76f9f17cce84c54 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 11:18:40 -0400
+Subject: sctp: clear control chunk transport if it is being removed
+
+From: Xin Long <lucien.xin@gmail.com>
+
+[ Upstream commit c9158ceaf27780ef64534ad72f44ffde3f8ccc49 ]
+
+sctp_make_heartbeat_ack() caches the destination transport in
+chunk->transport without taking a reference. When src_out_of_asoc_ok is
+enabled, the HEARTBEAT ACK may remain queued on control_chunk_list instead
+of being transmitted immediately.
+
+If the peer transport is removed while the chunk is still queued,
+sctp_assoc_rm_peer() drops the transport and schedules it for RCU freeing,
+but only clears cached transport pointers in out_chunk_list. The queued
+control chunk therefore retains a dangling transport pointer.
+
+Once an ASCONF_ACK clears the suppression and the queued control chunk is
+transmitted, SCTP dereferences the stale transport pointer, leading to a
+use-after-free.
+
+Fix this by also clearing chunk->transport for queued control chunks in
+control_chunk_list when removing the transport.
+
+Fixes: 8a07eb0a50ae ("sctp: Add ASCONF operation on the single-homed host")
+Reported-by: Daniele Linguaglossa <danielelinguaglossa@gmail.com>
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/7e1168cb722132152a29d47e5eafaeac4a3bf6f3.1785943120.git.lucien.xin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/associola.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/net/sctp/associola.c b/net/sctp/associola.c
+index 86d86ec9d90aa..122f0a948430f 100644
+--- a/net/sctp/associola.c
++++ b/net/sctp/associola.c
+@@ -572,6 +572,10 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
+ if (ch->transport == peer)
+ ch->transport = NULL;
+
++ list_for_each_entry(ch, &asoc->outqueue.control_chunk_list, list)
++ if (ch->transport == peer)
++ ch->transport = NULL;
++
+ asoc->peer.transport_count--;
+
+ sctp_ulpevent_notify_peer_addr_change(peer, SCTP_ADDR_REMOVED, 0);
+--
+2.53.0
+
--- /dev/null
+From 418595e4e2b0326da7edc442ab1cc4135fa70ae2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 22 Jun 2021 14:04:59 -0400
+Subject: sctp: extract sctp_v4_err_handle function from sctp_v4_err
+
+From: Xin Long <lucien.xin@gmail.com>
+
+[ Upstream commit d83060759a652ccb64d7486fe38c8347b4a64048 ]
+
+This patch is to extract sctp_v4_err_handle() from sctp_v4_err() to
+only handle the icmp err after the sock lookup, and it also makes
+the code clearer.
+
+sctp_v4_err_handle() will be used in sctp over udp's err handling
+in the following patch.
+
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: af0e5cdd031f ("tls: don't abort the connection on signal-interrupted sends")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/input.c | 106 ++++++++++++++++++++++-------------------------
+ 1 file changed, 49 insertions(+), 57 deletions(-)
+
+diff --git a/net/sctp/input.c b/net/sctp/input.c
+index 3c7761199f200..731d12e8038c5 100644
+--- a/net/sctp/input.c
++++ b/net/sctp/input.c
+@@ -556,6 +556,49 @@ void sctp_err_finish(struct sock *sk, struct sctp_transport *t)
+ sctp_transport_put(t);
+ }
+
++static void sctp_v4_err_handle(struct sctp_transport *t, struct sk_buff *skb,
++ __u8 type, __u8 code, __u32 info)
++{
++ struct sctp_association *asoc = t->asoc;
++ struct sock *sk = asoc->base.sk;
++ int err = 0;
++
++ switch (type) {
++ case ICMP_PARAMETERPROB:
++ err = EPROTO;
++ break;
++ case ICMP_DEST_UNREACH:
++ if (code > NR_ICMP_UNREACH)
++ return;
++ if (code == ICMP_FRAG_NEEDED) {
++ sctp_icmp_frag_needed(sk, asoc, t, SCTP_TRUNC4(info));
++ return;
++ }
++ if (code == ICMP_PROT_UNREACH) {
++ sctp_icmp_proto_unreachable(sk, asoc, t);
++ return;
++ }
++ err = icmp_err_convert[code].errno;
++ break;
++ case ICMP_TIME_EXCEEDED:
++ if (code == ICMP_EXC_FRAGTIME)
++ return;
++
++ err = EHOSTUNREACH;
++ break;
++ case ICMP_REDIRECT:
++ sctp_icmp_redirect(sk, t, skb);
++ default:
++ return;
++ }
++ if (!sock_owned_by_user(sk) && inet_sk(sk)->recverr) {
++ sk->sk_err = err;
++ sk->sk_error_report(sk);
++ } else { /* Only an error on timeout */
++ sk->sk_err_soft = err;
++ }
++}
++
+ /*
+ * This routine is called by the ICMP module when it gets some
+ * sort of error condition. If err < 0 then the socket should
+@@ -574,22 +617,19 @@ void sctp_err_finish(struct sock *sk, struct sctp_transport *t)
+ int sctp_v4_err(struct sk_buff *skb, __u32 info)
+ {
+ const struct iphdr *iph = (const struct iphdr *)skb->data;
+- const int ihlen = iph->ihl * 4;
+ const int type = icmp_hdr(skb)->type;
+ const int code = icmp_hdr(skb)->code;
+- struct sock *sk;
+- struct sctp_association *asoc = NULL;
++ struct net *net = dev_net(skb->dev);
+ struct sctp_transport *transport;
+- struct inet_sock *inet;
++ struct sctp_association *asoc;
+ __u16 saveip, savesctp;
+- int err;
+- struct net *net = dev_net(skb->dev);
++ struct sock *sk;
+
+ /* Fix up skb to look at the embedded net header. */
+ saveip = skb->network_header;
+ savesctp = skb->transport_header;
+ skb_reset_network_header(skb);
+- skb_set_transport_header(skb, ihlen);
++ skb_set_transport_header(skb, iph->ihl * 4);
+ sk = sctp_err_lookup(net, AF_INET, skb, sctp_hdr(skb), &asoc, &transport);
+ /* Put back, the original values. */
+ skb->network_header = saveip;
+@@ -598,58 +638,10 @@ int sctp_v4_err(struct sk_buff *skb, __u32 info)
+ __ICMP_INC_STATS(net, ICMP_MIB_INERRORS);
+ return -ENOENT;
+ }
+- /* Warning: The sock lock is held. Remember to call
+- * sctp_err_finish!
+- */
+-
+- switch (type) {
+- case ICMP_PARAMETERPROB:
+- err = EPROTO;
+- break;
+- case ICMP_DEST_UNREACH:
+- if (code > NR_ICMP_UNREACH)
+- goto out_unlock;
+-
+- /* PMTU discovery (RFC1191) */
+- if (ICMP_FRAG_NEEDED == code) {
+- sctp_icmp_frag_needed(sk, asoc, transport,
+- SCTP_TRUNC4(info));
+- goto out_unlock;
+- } else {
+- if (ICMP_PROT_UNREACH == code) {
+- sctp_icmp_proto_unreachable(sk, asoc,
+- transport);
+- goto out_unlock;
+- }
+- }
+- err = icmp_err_convert[code].errno;
+- break;
+- case ICMP_TIME_EXCEEDED:
+- /* Ignore any time exceeded errors due to fragment reassembly
+- * timeouts.
+- */
+- if (ICMP_EXC_FRAGTIME == code)
+- goto out_unlock;
+-
+- err = EHOSTUNREACH;
+- break;
+- case ICMP_REDIRECT:
+- sctp_icmp_redirect(sk, transport, skb);
+- /* Fall through to out_unlock. */
+- default:
+- goto out_unlock;
+- }
+-
+- inet = inet_sk(sk);
+- if (!sock_owned_by_user(sk) && inet->recverr) {
+- sk->sk_err = err;
+- sk->sk_error_report(sk);
+- } else { /* Only an error on timeout */
+- sk->sk_err_soft = err;
+- }
+
+-out_unlock:
++ sctp_v4_err_handle(transport, skb, type, code, info);
+ sctp_err_finish(sk, transport);
++
+ return 0;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From bbff555a08dd2d2eb658a50fba549b2e89f7dd30 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 22 Jun 2021 14:04:58 -0400
+Subject: sctp: extract sctp_v6_err_handle function from sctp_v6_err
+
+From: Xin Long <lucien.xin@gmail.com>
+
+[ Upstream commit f6549bd37b927655c6fecad88428a731cd8a4a34 ]
+
+This patch is to extract sctp_v6_err_handle() from sctp_v6_err() to
+only handle the icmp err after the sock lookup, and it also makes
+the code clearer.
+
+sctp_v6_err_handle() will be used in sctp over udp's err handling
+in the following patch.
+
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: af0e5cdd031f ("tls: don't abort the connection on signal-interrupted sends")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/ipv6.c | 76 ++++++++++++++++++++++++++-----------------------
+ 1 file changed, 40 insertions(+), 36 deletions(-)
+
+diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
+index 984ec00ad6384..48bd3b52d56d0 100644
+--- a/net/sctp/ipv6.c
++++ b/net/sctp/ipv6.c
+@@ -121,50 +121,28 @@ static struct notifier_block sctp_inet6addr_notifier = {
+ .notifier_call = sctp_inet6addr_event,
+ };
+
+-/* ICMP error handler. */
+-static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+- u8 type, u8 code, int offset, __be32 info)
++static void sctp_v6_err_handle(struct sctp_transport *t, struct sk_buff *skb,
++ __u8 type, __u8 code, __u32 info)
+ {
+- struct sock *sk;
+- struct sctp_association *asoc;
+- struct sctp_transport *transport;
++ struct sctp_association *asoc = t->asoc;
++ struct sock *sk = asoc->base.sk;
+ struct ipv6_pinfo *np;
+- __u16 saveip, savesctp;
+- int err, ret = 0;
+- struct net *net = dev_net(skb->dev);
+-
+- /* Fix up skb to look at the embedded net header. */
+- saveip = skb->network_header;
+- savesctp = skb->transport_header;
+- skb_reset_network_header(skb);
+- skb_set_transport_header(skb, offset);
+- sk = sctp_err_lookup(net, AF_INET6, skb, sctp_hdr(skb), &asoc, &transport);
+- /* Put back, the original pointers. */
+- skb->network_header = saveip;
+- skb->transport_header = savesctp;
+- if (!sk) {
+- __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
+- return -ENOENT;
+- }
+-
+- /* Warning: The sock lock is held. Remember to call
+- * sctp_err_finish!
+- */
++ int err = 0;
+
+ switch (type) {
+ case ICMPV6_PKT_TOOBIG:
+ if (ip6_sk_accept_pmtu(sk))
+- sctp_icmp_frag_needed(sk, asoc, transport, ntohl(info));
+- goto out_unlock;
++ sctp_icmp_frag_needed(sk, asoc, t, info);
++ return;
+ case ICMPV6_PARAMPROB:
+ if (ICMPV6_UNK_NEXTHDR == code) {
+- sctp_icmp_proto_unreachable(sk, asoc, transport);
+- goto out_unlock;
++ sctp_icmp_proto_unreachable(sk, asoc, t);
++ return;
+ }
+ break;
+ case NDISC_REDIRECT:
+- sctp_icmp_redirect(sk, transport, skb);
+- goto out_unlock;
++ sctp_icmp_redirect(sk, t, skb);
++ return;
+ default:
+ break;
+ }
+@@ -174,13 +152,39 @@ static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ if (!sock_owned_by_user(sk) && np->recverr) {
+ sk->sk_err = err;
+ sk->sk_error_report(sk);
+- } else { /* Only an error on timeout */
++ } else {
+ sk->sk_err_soft = err;
+ }
++}
++
++/* ICMP error handler. */
++static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
++ u8 type, u8 code, int offset, __be32 info)
++{
++ struct net *net = dev_net(skb->dev);
++ struct sctp_transport *transport;
++ struct sctp_association *asoc;
++ __u16 saveip, savesctp;
++ struct sock *sk;
++
++ /* Fix up skb to look at the embedded net header. */
++ saveip = skb->network_header;
++ savesctp = skb->transport_header;
++ skb_reset_network_header(skb);
++ skb_set_transport_header(skb, offset);
++ sk = sctp_err_lookup(net, AF_INET6, skb, sctp_hdr(skb), &asoc, &transport);
++ /* Put back, the original pointers. */
++ skb->network_header = saveip;
++ skb->transport_header = savesctp;
++ if (!sk) {
++ __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
++ return -ENOENT;
++ }
+
+-out_unlock:
++ sctp_v6_err_handle(transport, skb, type, code, ntohl(info));
+ sctp_err_finish(sk, transport);
+- return ret;
++
++ return 0;
+ }
+
+ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
+--
+2.53.0
+
--- /dev/null
+From 333351595af73b55419d0fd5f7beb7fe46b84806 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 10:55:14 +0800
+Subject: sctp: fix addip_serial increment on ASCONF_ACK allocation failure
+
+From: Qing Luo <luoqing@kylinos.cn>
+
+[ Upstream commit aa2e13ae8d3cbe2c15ef4f7e971b2de0832794aa ]
+
+In sctp_process_asconf(), when sctp_make_asconf_ack() fails to allocate
+the ASCONF_ACK chunk due to memory pressure, the code jumps to the
+done label where asoc->peer.addip_serial is unconditionally incremented.
+
+This leaves the peer's ASCONF (serial N) unacknowledged while the local
+endpoint now expects serial N+1. When the peer retransmits serial N, it
+falls into the serial < addip_serial + 1 branch ,
+which attempts to look up a cached ACK for serial N. No cached ACK
+exists since the allocation failed, so the retransmission is silently
+discarded. The peer eventually times out and ABORTs the association.
+
+Move the addip_serial increment inside the if (asconf_ack) block so that
+the serial number is only advanced when the ASCONF_ACK is successfully
+created and cached. This way, on allocation failure, the serial number
+is unchanged and the peer's retransmitted ASCONF will be correctly
+re-processed.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Qing Luo <luoqing@kylinos.cn>
+Acked-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/20260804025514.241767-1-l1138897701@163.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/sm_make_chunk.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
+index 651fd41996ae1..06309c1869da0 100644
+--- a/net/sctp/sm_make_chunk.c
++++ b/net/sctp/sm_make_chunk.c
+@@ -3316,12 +3316,11 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
+ goto done;
+ }
+ done:
+- asoc->peer.addip_serial++;
+-
+ /* If we are sending a new ASCONF_ACK hold a reference to it in assoc
+ * after freeing the reference to old asconf ack if any.
+ */
+ if (asconf_ack) {
++ asoc->peer.addip_serial++;
+ sctp_chunk_hold(asconf_ack);
+ list_add_tail(&asconf_ack->transmitted_list,
+ &asoc->asconf_ack_list);
+--
+2.53.0
+
--- /dev/null
+From 7073a3ae46a9923c73357b7f4f9733a63506e2b8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 22 Jun 2021 14:04:57 -0400
+Subject: sctp: remove the unessessary hold for idev in sctp_v6_err
+
+From: Xin Long <lucien.xin@gmail.com>
+
+[ Upstream commit 237a6a2e318c1ed7429e72f2640054bdda91646f ]
+
+Same as in tcp_v6_err() and __udp6_lib_err(), there's no need to
+hold idev in sctp_v6_err(), so just call __in6_dev_get() instead.
+
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: af0e5cdd031f ("tls: don't abort the connection on signal-interrupted sends")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/ipv6.c | 12 ++----------
+ 1 file changed, 2 insertions(+), 10 deletions(-)
+
+diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
+index a9cfe4d62df83..984ec00ad6384 100644
+--- a/net/sctp/ipv6.c
++++ b/net/sctp/ipv6.c
+@@ -125,7 +125,6 @@ static struct notifier_block sctp_inet6addr_notifier = {
+ static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ u8 type, u8 code, int offset, __be32 info)
+ {
+- struct inet6_dev *idev;
+ struct sock *sk;
+ struct sctp_association *asoc;
+ struct sctp_transport *transport;
+@@ -134,8 +133,6 @@ static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ int err, ret = 0;
+ struct net *net = dev_net(skb->dev);
+
+- idev = in6_dev_get(skb->dev);
+-
+ /* Fix up skb to look at the embedded net header. */
+ saveip = skb->network_header;
+ savesctp = skb->transport_header;
+@@ -146,9 +143,8 @@ static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ skb->network_header = saveip;
+ skb->transport_header = savesctp;
+ if (!sk) {
+- __ICMP6_INC_STATS(net, idev, ICMP6_MIB_INERRORS);
+- ret = -ENOENT;
+- goto out;
++ __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
++ return -ENOENT;
+ }
+
+ /* Warning: The sock lock is held. Remember to call
+@@ -184,10 +180,6 @@ static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+
+ out_unlock:
+ sctp_err_finish(sk, transport);
+-out:
+- if (likely(idev != NULL))
+- in6_dev_put(idev);
+-
+ return ret;
+ }
+
+--
+2.53.0
+
gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch
mount-honour-sb_nouser-in-the-new-mount-api.patch
s390-zcrypt-fix-missing-mem-scrub-at-clear-key-impor.patch
+nfs4-take-a-reference-on-the-nfs_client-when-running.patch
+nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch
+arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch
+bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch
+bpf-preserve-pointer-state-for-commuted-arithmetic.patch
+net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch
+net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch
+net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch
+net-mlx5-remove-second-fw-tracer-check.patch
+net-mlx5-fw_tracer-return-null-on-create-error.patch
+counter-microchip-tcb-capture-fix-dt-channel-validat.patch
+udp-fix-potential-use-after-free-in-tunnel-segmentat.patch
+net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch
+net-openvswitch-fix-kerneldoc-warnings.patch
+net-openvswitch-fix-kernel-doc-warnings-in-flow.c.patch
+net-openvswitch-check-ethernet-header-length-in-key_.patch
+bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch
+bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch
+sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch
+net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch
+net-marvell-prestera-try-to-load-previous-fw-version.patch
+net-prestera-validate-firmware-header-length.patch
+net-remove-warn_on_once-from-sk_mc_loop.patch
+net-qrtr-ns-raise-lookup-limit-to-128.patch
+ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch
+sctp-clear-control-chunk-transport-if-it-is-being-re.patch
+sctp-remove-the-unessessary-hold-for-idev-in-sctp_v6.patch
+sctp-extract-sctp_v6_err_handle-function-from-sctp_v.patch
+sctp-extract-sctp_v4_err_handle-function-from-sctp_v.patch
+tls-don-t-abort-the-connection-on-signal-interrupted.patch
--- /dev/null
+From b91f0b707ce79341e882f8736962c4384a2c9299 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 08:22:48 +0200
+Subject: tls: don't abort the connection on signal-interrupted sends
+
+From: Maximilian Immanuel Brandtner <maxbr@linux.ibm.com>
+
+[ Upstream commit af0e5cdd031f4f4a8f6d4160bfbda4f36872b0ed ]
+
+When a signal interrupts a blocking send, tls_tx_records() treats the
+resulting -ERESTARTSYS as a transmission failure and marks the socket
+errored via tls_err_abort() with the raw error code. Later syscalls
+return the kernel-internal errno 512 (ERESTARTSYS) to userspace, as the
+signal it stems from is no longer pending during syscall exit and thus
+never translated.
+
+An interrupted send is not a connection error: the partially sent record
+stays queued and is resent later. Interrupt error codes are therefore
+excluded from the abort in the same way as -EAGAIN.
+
+Fixes: b341ca51d267 ("tls: Fix tls_sw_sendmsg error handling")
+Signed-off-by: Maximilian Immanuel Brandtner <maxbr@linux.ibm.com>
+Link: https://patch.msgid.link/20260805063109.1772314-1-maxbr@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tls/tls_sw.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
+index 29650fa546664..c2344a46dddda 100644
+--- a/net/tls/tls_sw.c
++++ b/net/tls/tls_sw.c
+@@ -430,7 +430,7 @@ int tls_tx_records(struct sock *sk, int flags)
+ }
+
+ tx_err:
+- if (rc < 0 && rc != -EAGAIN)
++ if (rc < 0 && rc != -EAGAIN && rc != -EINTR && rc != -ERESTARTSYS)
+ tls_err_abort(sk, rc);
+
+ return rc;
+--
+2.53.0
+
--- /dev/null
+From 3dbbf3bf859911909e0f84ed018a252ba1f5dcd8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 17:35:54 +0800
+Subject: udp: fix potential use-after-free in tunnel segmentation
+
+From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+
+[ Upstream commit d0f86fb36eb260abd10007b62c9dcc1028e03e61 ]
+
+__skb_udp_tunnel_segment() gets the UDP header before ensuring the
+tunnel header is in the skb head. If the pull reallocates skb->head,
+the saved UDP header pointer is no longer valid.
+
+Get the UDP header after the pull to avoid a potential use-after-free.
+
+Fixes: dbef491ebe7f ("udp: Use uh->len instead of skb->len to compute checksum in segmentation")
+Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+Reviewed-by: Antoine Tenart <atenart@kernel.org>
+Link: https://patch.msgid.link/20260730093554.68127-1-xuanqiang.luo@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/udp_offload.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
+index 5d4413fe41952..4285d25d9982d 100644
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -20,17 +20,19 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
+ int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
+ bool remcsum, need_csum, offload_csum, gso_partial;
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+- struct udphdr *uh = udp_hdr(skb);
+ u16 mac_offset = skb->mac_header;
+ __be16 protocol = skb->protocol;
+ u16 mac_len = skb->mac_len;
+ int udp_offset, outer_hlen;
++ struct udphdr *uh;
+ __wsum partial;
+ bool need_ipsec;
+
+ if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
+ goto out;
+
++ uh = udp_hdr(skb);
++
+ /* Adjust partial header checksum to negate old length.
+ * We cannot rely on the value contained in uh->len as it is
+ * possible that the actual value exceeds the boundaries of the
+--
+2.53.0
+
--- /dev/null
+From e8e17ba087e05b378b25acbac1d331ee7984a353 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 24 May 2026 23:38:46 -0400
+Subject: ARM: npcm: Fix OF node refcount leaks in SMP setup
+
+From: Yuho Choi <dbgh9129@gmail.com>
+
+[ Upstream commit 8eb052f48331474c2789d07b7f11165c323bd2f9 ]
+
+npcm7xx_smp_boot_secondary() and npcm7xx_smp_prepare_cpus() look up
+the GCR and SCU nodes with of_find_compatible_node(). The returned
+nodes are used for of_iomap(), but the node references are never
+released.
+
+of_iomap() does not consume the device node reference, and iounmap()
+only releases the MMIO mapping. Drop each node reference after the
+corresponding mapping attempt.
+
+Fixes: 7bffa14c9aed ("arm: npcm: add basic support for Nuvoton BMCs")
+Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
+Reviewed-by: Avi Fishman <avifishman70@gmail.com>
+Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/mach-npcm/platsmp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arm/mach-npcm/platsmp.c b/arch/arm/mach-npcm/platsmp.c
+index 21633c70fe7fe..fe63edc9886df 100644
+--- a/arch/arm/mach-npcm/platsmp.c
++++ b/arch/arm/mach-npcm/platsmp.c
+@@ -35,6 +35,7 @@ static int npcm7xx_smp_boot_secondary(unsigned int cpu,
+ goto out;
+ }
+ gcr_base = of_iomap(gcr_np, 0);
++ of_node_put(gcr_np);
+ if (!gcr_base) {
+ pr_err("could not iomap gcr");
+ ret = -ENOMEM;
+@@ -63,6 +64,7 @@ static void __init npcm7xx_smp_prepare_cpus(unsigned int max_cpus)
+ return;
+ }
+ scu_base = of_iomap(scu_np, 0);
++ of_node_put(scu_np);
+ if (!scu_base) {
+ pr_err("could not iomap scu");
+ return;
+--
+2.53.0
+
--- /dev/null
+From 1bb1751e7cec2b178425b82d2934839af616eb5c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 14:06:28 +0800
+Subject: ata: pata_sl82c105: fix bridge revision use-after-free
+
+From: Hongyan Xu <getshell@seu.edu.cn>
+
+[ Upstream commit 7700a31039cdc6715cb6cce7e7a664ee4e945f67 ]
+
+pci_get_slot() returns a referenced PCI device. Commit 44c10138fd4b
+("PCI: Change all drivers to use pci_device->revision") replaced a
+configuration-space read with direct access to the cached revision field,
+but left that access after pci_dev_put(). The bridge may therefore be freed
+before its revision is read.
+
+Read the revision before dropping the reference.
+
+Fixes: 44c10138fd4b ("PCI: Change all drivers to use pci_device->revision")
+Signed-off-by: Hongyan Xu <getshell@seu.edu.cn>
+Reviewed-by: Niklas Cassel <cassel@kernel.org>
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ata/pata_sl82c105.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
+index 8487470e2e01e..c32f3b490bb35 100644
+--- a/drivers/ata/pata_sl82c105.c
++++ b/drivers/ata/pata_sl82c105.c
+@@ -265,6 +265,7 @@ static struct ata_port_operations sl82c105_port_ops = {
+ static int sl82c105_bridge_revision(struct pci_dev *pdev)
+ {
+ struct pci_dev *bridge;
++ u8 revision;
+
+ /*
+ * The bridge should be part of the same device, but function 0.
+@@ -286,8 +287,9 @@ static int sl82c105_bridge_revision(struct pci_dev *pdev)
+ /*
+ * We need to find function 0's revision, not function 1
+ */
++ revision = bridge->revision;
+ pci_dev_put(bridge);
+- return bridge->revision;
++ return revision;
+ }
+
+ static void sl82c105_fixup(struct pci_dev *pdev)
+--
+2.53.0
+
--- /dev/null
+From 3f4f9b4edc9ae3bcfc8c9e6bcf6d8a615fa51b0c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:36 -0700
+Subject: bnxt_en: Disable EOP for TPA on all chips to prevent data corruption
+
+From: Michael Chan <michael.chan@broadcom.com>
+
+[ Upstream commit c3faf548a00f4c17100cc9204746975fa46a73b9 ]
+
+EOP (End of frame padding) on the AGG ring may cause overlapping of
+zero padding at the end of one segment with the next segment's data.
+If Relaxed Ordering (RO) is enabled, the zero padding may overwrite
+valid data in the next segment and corrupt the data. Older chips
+(P5 and older) do not automatically disable RO when EOP is enabled.
+On some ARM systems, data corruption was reported on 57508 (P5)
+chips with RO enabled.
+
+Always disable EOP on all chips on the AGG rings when TPA is enabled
+to fix the data corruption.
+
+Fixes: bfcd8d791ec1 ("bnxt_en: Add fast path logic for TPA on 57500 chips.")
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-5-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index b512a3513e324..0b435bd3db9dc 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -3602,11 +3602,14 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr)
+ type = ((u32)BNXT_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
+ RX_BD_TYPE_RX_AGG_BD;
+
+- /* On P7, setting EOP will cause the chip to disable
+- * Relaxed Ordering (RO) for TPA data. Disable EOP for
+- * potentially higher performance with RO.
++ /* Disable EOP if TPA is enabled to prevent overlapping zero
++ * padding with the next segment's data. On P7_PLUS, EOP will
++ * automatically disable Relaxed Ordering (RO) to prevent
++ * potential data corruption (and may degrade performance). On
++ * older chips, RO will not be automatically disabled and may
++ * cause corruption.
+ */
+- if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
++ if (!(bp->flags & BNXT_FLAG_TPA))
+ type |= RX_BD_FLAGS_AGG_EOP;
+
+ bnxt_init_rxbd_pages(ring, type);
+--
+2.53.0
+
--- /dev/null
+From 59a20e85238e63ef6ae4c80bfb27766e04cbbbce Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Nov 2025 13:56:46 -0800
+Subject: bnxt_en: Do not set EOP on RX AGG BDs on 5760X chips
+
+From: Michael Chan <michael.chan@broadcom.com>
+
+[ Upstream commit 30f253f8d9a01d532fdb7ec6c8a9d4c15fe29241 ]
+
+With End-of-Packet padding (EOP) set, the chip will disable Relaxed
+Ordering (RO) of TPA data packets. A TPA segment with EOP set will be
+padded to the next cache boundary and can potentially overwrite the
+beginning bytes of the next TPA segment when RO is enabled on 5760X.
+To prevent that, the chip disables RO for TPA when EOP is set.
+
+To take advantge of RO and higher performance, do not set EOP on
+5760X chips when TPA is enabled. Define a proper RX_BD_FLAGS_AGG_EOP
+constant to make it clear that we are setting EOP.
+
+Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
+Reviewed-by: Somnath Kotur <somnath.kotur@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20251126215648.1885936-6-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: c3faf548a00f ("bnxt_en: Disable EOP for TPA on all chips to prevent data corruption")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 ++++++++-
+ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
+ 2 files changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 79aa239fa7cc4..b512a3513e324 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -3600,7 +3600,14 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr)
+
+ if ((bp->flags & BNXT_FLAG_AGG_RINGS)) {
+ type = ((u32)BNXT_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
+- RX_BD_TYPE_RX_AGG_BD | RX_BD_FLAGS_SOP;
++ RX_BD_TYPE_RX_AGG_BD;
++
++ /* On P7, setting EOP will cause the chip to disable
++ * Relaxed Ordering (RO) for TPA data. Disable EOP for
++ * potentially higher performance with RO.
++ */
++ if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
++ type |= RX_BD_FLAGS_AGG_EOP;
+
+ bnxt_init_rxbd_pages(ring, type);
+ }
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+index 56aae0d654e8a..1f844798abc4e 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+@@ -103,6 +103,7 @@ struct rx_bd {
+ #define RX_BD_TYPE_48B_BD_SIZE (2 << 4)
+ #define RX_BD_TYPE_64B_BD_SIZE (3 << 4)
+ #define RX_BD_FLAGS_SOP (1 << 6)
++ #define RX_BD_FLAGS_AGG_EOP (1 << 6)
+ #define RX_BD_FLAGS_EOP (1 << 7)
+ #define RX_BD_FLAGS_BUFFERS (3 << 8)
+ #define RX_BD_FLAGS_1_BUFFER_PACKET (0 << 8)
+--
+2.53.0
+
--- /dev/null
+From 8b67a7d89f5d61d906942b11b2cc0049dda9febf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:37 -0700
+Subject: bnxt_en: Fix PTP PPS setting bug
+
+From: Keegan Freyhof <keegan.freyhof@broadcom.com>
+
+[ Upstream commit 80eaf88efec33ac77ed7726d066c4f2f932cc329 ]
+
+The existing driver logic is always turning on PTP_CLK_REQ_PPS
+regardless of the "on" parameter passed to bnxt_ptp_enable().
+During shutdown, PTP_CLK_REQ_PPS may be turned off and this
+bug will do the opposite and may trigger a PCIe PTM request TLP.
+On some systems this can trigger a PCIe AER.
+
+Fix it by properly configuring PTP_CLK_REQ_PPS based on the "on"
+parameter.
+
+Fixes: 9e518f25802c ("bnxt_en: 1PPS functions to configure TSIO pins")
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Keegan Freyhof <keegan.freyhof@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-6-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
+index 328ae267eba5c..e337e78c00365 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
+@@ -375,12 +375,15 @@ static int bnxt_ptp_enable(struct ptp_clock_info *ptp_info,
+ return rc;
+ case PTP_CLK_REQ_PPS:
+ /* Configure PHC PPS IN */
+- rc = bnxt_ptp_cfg_pin(bp, 0, BNXT_PPS_PIN_PPS_IN);
++ pin_id = 0;
++ if (!on)
++ break;
++ rc = bnxt_ptp_cfg_pin(bp, pin_id, BNXT_PPS_PIN_PPS_IN);
+ if (rc)
+ return rc;
+ rc = bnxt_ptp_cfg_event(bp, BNXT_PPS_EVENT_INTERNAL);
+ if (!rc)
+- ptp->pps_info.pins[0].event = BNXT_PPS_EVENT_INTERNAL;
++ ptp->pps_info.pins[pin_id].event = BNXT_PPS_EVENT_INTERNAL;
+ return rc;
+ default:
+ netdev_err(ptp->bp->dev, "Unrecognized PIN function\n");
+--
+2.53.0
+
--- /dev/null
+From f5d8cb48043bb756b1478664478d295606e17304 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 25 Jul 2026 23:39:30 +0000
+Subject: bonding: alb: re-check primary_is_promisc under RTNL in
+ bond_alb_monitor
+
+From: Xiang Mei (Microsoft) <xmei5@asu.edu>
+
+[ Upstream commit 683c6ba6e58e6ed1037831ea97dd58d9c0e76b8d ]
+
+bond_alb_monitor() reads primary_is_promisc under RCU, then drops RCU and
+takes RTNL via rtnl_trylock() before undoing the promiscuity it set on the
+active slave. In that window the active slave can change under RTNL
+(RTM_DELLINK -> __bond_release_one() -> bond_alb_handle_active_change()),
+which already drops the promiscuity and clears primary_is_promisc. The
+monitor still acts on the stale decision: if the slave was removed with no
+failover, curr_active_slave is now NULL and the deref faults; if it failed
+over, the stale dev_set_promiscuity(-1) underflows the new slave's
+promiscuity counter and pins it in IFF_PROMISC.
+
+ Oops: general protection fault, probably for non-canonical address ...
+ KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
+ Workqueue: b42 bond_alb_monitor
+ RIP: 0010:bond_alb_monitor (drivers/net/bonding/bond_alb.c:1600)
+ process_one_work (kernel/workqueue.c:3322)
+ worker_thread (kernel/workqueue.c:3486)
+ kthread (kernel/kthread.c:436)
+ ret_from_fork (arch/x86/kernel/process.c:158)
+ Kernel panic - not syncing: Fatal exception
+
+Re-check primary_is_promisc (and curr_active_slave) after taking RTNL so
+the monitor only undoes an increment it still owns. The other bonding
+monitors already re-read state under RTNL in their commit phase
+(bond_miimon_commit/bond_ab_arp_commit); bond_alb_monitor() was the only
+one acting on the pre-trylock decision.
+
+Fixes: d0e81b7e2246 ("bonding: Acquire correct locks in alb for promisc change")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
+Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
+Acked-by: Jay Vosburgh <jv@jvosburgh.net>
+Link: https://patch.msgid.link/20260725233930.2957317-1-xmei5@asu.edu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/bonding/bond_alb.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
+index 7091b018078b2..4be2afd98ce1d 100644
+--- a/drivers/net/bonding/bond_alb.c
++++ b/drivers/net/bonding/bond_alb.c
+@@ -1499,8 +1499,8 @@ void bond_alb_monitor(struct work_struct *work)
+ struct bonding *bond = container_of(work, struct bonding,
+ alb_work.work);
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
++ struct slave *slave, *curr;
+ struct list_head *iter;
+- struct slave *slave;
+
+ if (!bond_has_slaves(bond)) {
+ atomic_set(&bond_info->tx_rebalance_counter, 0);
+@@ -1562,9 +1562,11 @@ void bond_alb_monitor(struct work_struct *work)
+ * because a slave was disabled then
+ * it can now leave promiscuous mode.
+ */
+- dev_set_promiscuity(rtnl_dereference(bond->curr_active_slave)->dev,
+- -1);
+- bond_info->primary_is_promisc = 0;
++ curr = rtnl_dereference(bond->curr_active_slave);
++ if (bond_info->primary_is_promisc && curr) {
++ dev_set_promiscuity(curr->dev, -1);
++ bond_info->primary_is_promisc = 0;
++ }
+
+ rtnl_unlock();
+ rcu_read_lock();
+--
+2.53.0
+
--- /dev/null
+From e43831d5507e770c5edbbbd08e7175b131e97d2f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:18:28 +0000
+Subject: bpf: Preserve pointer state for commuted arithmetic
+
+From: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+
+[ Upstream commit a4c6f804b44c5c790269b25e0e61cf4e9f117c86 ]
+
+When scalar += pointer is handled in adjust_ptr_min_max_vals(), the
+destination register inherits the pointer state from the source pointer.
+Copying only selected fields is fragile because pointer provenance is
+tracked by several bpf_reg_state fields.
+
+Use the caller's temporary offset register to preserve the scalar operand
+while replacing the destination with the full pointer state. This preserves
+the frame number for PTR_TO_STACK registers and keeps parent identity
+fields consistent.
+
+Fixes: f4d7e40a5b71 ("bpf: introduce function calls (verification)")
+Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+Tested-by: Daniel Wade <danjwade95@gmail.com>
+Acked-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-2-8ee297e2346b@mails.tsinghua.edu.cn
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 5e71d58e4a300..a0163090309a4 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -7388,11 +7388,12 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ break;
+ }
+
+- /* In case of 'scalar += pointer', dst_reg inherits pointer type and id.
+- * The id may be overwritten later if we create a new variable offset.
++ /* For 'scalar += pointer', dst_reg inherits the complete pointer
++ * register state. Individual fields may be adjusted later by pointer
++ * arithmetic. Callers guarantee that below does not overwrite off_reg.
+ */
+- dst_reg->type = ptr_reg->type;
+- dst_reg->id = ptr_reg->id;
++ if (dst_reg != ptr_reg)
++ *dst_reg = *ptr_reg;
+
+ if (!check_reg_sane_offset(env, off_reg, ptr_reg->type) ||
+ !check_reg_sane_offset(env, ptr_reg, ptr_reg->type))
+@@ -7460,7 +7461,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ }
+ break;
+ case BPF_SUB:
+- if (dst_reg == off_reg) {
++ if (dst_reg != ptr_reg) {
+ /* scalar -= pointer. Creates an unknown scalar */
+ verbose(env, "R%d tried to subtract pointer from scalar\n",
+ dst);
+@@ -8319,8 +8320,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
+ err = mark_chain_precision(env, insn->dst_reg);
+ if (err)
+ return err;
+- return adjust_ptr_min_max_vals(env, insn,
+- src_reg, dst_reg);
++ off_reg = *dst_reg;
++ return adjust_ptr_min_max_vals(env, insn, src_reg, &off_reg);
+ }
+ } else if (ptr_reg) {
+ /* pointer += scalar */
+--
+2.53.0
+
--- /dev/null
+From 6f384d3ac7ab59dfab784a69cf0dba87e8614991 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jul 2026 04:29:10 +0000
+Subject: counter: microchip-tcb-capture: Fix DT channel validation
+
+From: Babanpreet Singh <bbnpreetsingh@gmail.com>
+
+[ Upstream commit f1a3a9946aab611dd2200c01ff122f64b033dad2 ]
+
+mchp_tc_probe() reads the devicetree "reg" cell - a u32, per the API
+contract of of_property_read_u32_index() - into a signed int, so the
+bounds check "channel > 2" fails to reject cell values at or above
+0x80000000: reinterpreted as a negative int, they compare below 2 and
+pass validation.
+
+A malformed devicetree can therefore drive a negative channel into the
+ATMEL_TC_REG() offset arithmetic, making the driver access syscon
+regmap offsets outside the TC block's register window, and into the
+"t%d_clk" clock-name formatting, where it truncates clk_name (sized
+for "t0_clk".."t2_clk").
+
+Declare channel as u32, matching the API contract; the unsigned
+comparison then rejects everything except channels 0..2. Adjust the
+format specifier to %u accordingly, which also resolves the W=1
+warning that exposed the gap:
+
+ microchip-tcb-capture.c:520:56: warning: '%d' directive output may
+ be truncated writing between 1 and 11 bytes into a region of size
+ 6 [-Wformat-truncation=]
+ note: directive argument in the range [-2147483648, 2]
+
+No behavior change for well-formed devicetrees: channels 0..2 take
+identical paths before and after.
+
+Fixes: 106b104137fd ("counter: Add microchip TCB capture counter")
+Assisted-by: Claude:claude-fable-5 [gcc W=1]
+Signed-off-by: Babanpreet Singh <bbnpreetsingh@gmail.com>
+Reviewed-by: Joshua Crofts <joshua.crofts1@gmail.com>
+Link: https://lore.kernel.org/r/20260714042910.7-1-bbnpreetsingh@gmail.com
+Signed-off-by: William Breathitt Gray <wbg@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/counter/microchip-tcb-capture.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/counter/microchip-tcb-capture.c b/drivers/counter/microchip-tcb-capture.c
+index 2625823152ead..1195fbcd639e3 100644
+--- a/drivers/counter/microchip-tcb-capture.c
++++ b/drivers/counter/microchip-tcb-capture.c
+@@ -310,7 +310,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
+ char clk_name[7];
+ struct regmap *regmap;
+ struct clk *clk[3];
+- int channel;
++ u32 channel;
+ int ret, i;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+@@ -345,7 +345,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
+
+ priv->channel[i] = channel;
+
+- snprintf(clk_name, sizeof(clk_name), "t%d_clk", channel);
++ snprintf(clk_name, sizeof(clk_name), "t%u_clk", channel);
+
+ clk[i] = of_clk_get_by_name(np->parent, clk_name);
+ if (IS_ERR(clk[i])) {
+--
+2.53.0
+
--- /dev/null
+From 6dbc5a8c76ec733dd687ef7ab1f3f30f4c8cb74c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 07:19:20 +0000
+Subject: hwmon: (corsair-psu) fix possible out-of-bounds access on missing
+ string termination
+
+From: Wilken Gottwalt <wilken.gottwalt@posteo.net>
+
+[ Upstream commit 36c4d73ce05d1d8896c2669eb0730d35a02a2ec1 ]
+
+In theory it could be possible that the REPLY_SIZE sized buffers for
+holding the vendor and product strings could be end up missing the null
+termination (for example by malicious hardware built on purpose)
+required by the seq_printf() call. That limits the debugfs printf calls
+to a maximum string length of REPLY_SIZE.
+
+Fixes: d115b51e0e567 ("hwmon: add Corsair PSU HID controller driver")
+Signed-off-by: Wilken Gottwalt <wilken.gottwalt@posteo.net>
+Link: https://lore.kernel.org/r/anLj9gPWRoRDbQBV@monster.localdomain
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/corsair-psu.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c
+index e9518221efc4c..f96de071e9094 100644
+--- a/drivers/hwmon/corsair-psu.c
++++ b/drivers/hwmon/corsair-psu.c
+@@ -644,7 +644,7 @@ static int vendor_show(struct seq_file *seqf, void *unused)
+ {
+ struct corsairpsu_data *priv = seqf->private;
+
+- seq_printf(seqf, "%s\n", priv->vendor);
++ seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->vendor);
+
+ return 0;
+ }
+@@ -654,7 +654,7 @@ static int product_show(struct seq_file *seqf, void *unused)
+ {
+ struct corsairpsu_data *priv = seqf->private;
+
+- seq_printf(seqf, "%s\n", priv->product);
++ seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->product);
+
+ return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From 02e4ccb81a608412e02140dbee90086260ccc479 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 12:17:10 +0400
+Subject: net: hisilicon: hix5hd2_gmac: remove redundant NAPI delete
+
+From: Jiawen Liu <1298662399@qq.com>
+
+[ Upstream commit f307a7dc32097c11413178fca437a10d20890bc2 ]
+
+hix5hd2_dev_remove() calls netif_napi_del() before unregister_netdev().
+This is not needed because free_netdev() deletes all NAPI instances
+attached to the net_device.
+
+Remove the redundant call and let the networking core tear down the NAPI
+instance during unregister_netdev(). The probe error path still keeps its
+explicit netif_napi_del(), because the device has not been registered
+there.
+
+Fixes: 57c5bc9ad7d7 ("net: hisilicon: add hix5hd2 mac driver")
+Signed-off-by: Jiawen Liu <1298662399@qq.com>
+Link: https://patch.msgid.link/tencent_5FFD37A252B4FEA6A80AD25B17C8E904F005@qq.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hix5hd2_gmac.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+index b981b6cbe6fff..7ecc3333c8df2 100644
+--- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
++++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+@@ -1288,7 +1288,6 @@ static int hix5hd2_dev_remove(struct platform_device *pdev)
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct hix5hd2_priv *priv = netdev_priv(ndev);
+
+- netif_napi_del(&priv->napi);
+ unregister_netdev(ndev);
+ mdiobus_unregister(priv->bus);
+ mdiobus_free(priv->bus);
+--
+2.53.0
+
--- /dev/null
+From e29ce88890705a04d4e2c39c8cd5d777de06eaac Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 11:04:02 +0300
+Subject: net/mlx5: fw_tracer, return NULL on create error
+
+From: Michael Guralnik <michaelgur@nvidia.com>
+
+[ Upstream commit af39eb111ce6b5eba9c08513b62c4868eb7e7fd5 ]
+
+Tracer creation can fail by returning either NULL or ERR_PTR.
+The return value is stored without a check on the device, and users
+treat ERR_PTR and NULL the same way.
+This also causes a crash in the core dump logic, which is missing the
+ERR_PTR check and ends up dereferencing it, as shown in the trace below.
+
+Switch tracer creation to return NULL on failure only, so callers only
+need a single NULL check.
+
+ Internal error: Oops: 0000000096000006 [#1] SMP
+ Modules linked in: mlx5_ib ib_uverbs ib_core ipv6 mlx5_core
+ CPU: 1 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted 6.19.7 #1 PREEMPT(none)
+ Workqueue: mlx5_health0001:01:00.0 mlx5_fw_reporter_err_work [mlx5_core]
+ pstate: a3400009 (NzCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
+ pc : mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core]
+ lr : mlx5_fw_tracer_trigger_core_dump_general+0x40/0xe0 [mlx5_core]
+ sp : ffff800081cf3c40
+ x29: ffff800081cf3c90 x28: 0000000000000000 x27: 0000000000000000
+ x26: ffff000080018828 x25: 0000000000000000 x24: ffff000080304a05
+ x23: ffff800081cf3d80 x22: ffff0000847e01a0 x21: 0000000000000000
+ x20: ffff0000847e01a0 x19: ffffffffffffffa1 x18: ffff80008310bbf0
+ x17: ffff800080119650 x16: ffff80008010df54 x15: ffff80008010d4ac
+ x14: ffff800079c202e4 x13: ffff80008002fe60 x12: ffff800080119650
+ x11: ffff80008010df54 x10: ffff80008010d4ac x9 : ffff800079c203d8
+ x8 : ffff800081cf3c88 x7 : 0000000000000000 x6 : 0000000000000000
+ x5 : 0000000000000000 x4 : 0000000000000008 x3 : 0000000000000030
+ x2 : 0000000000000008 x1 : 0000000000000000 x0 : 00000000c5c4000e
+ Call trace:
+ mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core] (P)
+ mlx5_fw_reporter_dump+0x30/0x2e0 [mlx5_core]
+ devlink_health_do_dump+0x9c/0x160
+ devlink_health_report+0x1c0/0x288
+ mlx5_fw_reporter_err_work+0xac/0xc0 [mlx5_core]
+ process_one_work+0x15c/0x3d8
+ worker_thread+0x18c/0x320
+ kthread+0x148/0x228
+ ret_from_fork+0x10/0x20
+ Code: b9400000 5ac00800 7a401800 540003ca (3940a260)
+ ---[ end trace 0000000000000000 ]---
+ Kernel panic - not syncing: Oops: Fatal exception
+ SMP: stopping secondary CPUs
+ Kernel Offset: disabled
+ CPU features: 0x000000,00078031,75fce5a1,35fffe67
+ Memory Limit: none
+ ---[ end Kernel panic - not syncing: Oops: Fatal exception ]---
+
+Fixes: fd1483fe1f9f ("net/mlx5: Add support for FW reporter dump")
+Signed-off-by: Michael Guralnik <michaelgur@nvidia.com>
+Reviewed-by: Shay Drori <shayd@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260729080402.2427184-1-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ethernet/mellanox/mlx5/core/diag/fw_tracer.c | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+index 1779ff98b5892..3c0e27eb01986 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+@@ -1036,13 +1036,11 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
+
+ tracer = kvzalloc(sizeof(*tracer), GFP_KERNEL);
+ if (!tracer)
+- return ERR_PTR(-ENOMEM);
++ return NULL;
+
+ tracer->work_queue = create_singlethread_workqueue("mlx5_fw_tracer");
+- if (!tracer->work_queue) {
+- err = -ENOMEM;
++ if (!tracer->work_queue)
+ goto free_tracer;
+- }
+
+ tracer->dev = dev;
+
+@@ -1082,7 +1080,7 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
+ destroy_workqueue(tracer->work_queue);
+ free_tracer:
+ kvfree(tracer);
+- return ERR_PTR(err);
++ return NULL;
+ }
+
+ static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data);
+@@ -1093,7 +1091,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
+ struct mlx5_core_dev *dev;
+ int err;
+
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return 0;
+
+ dev = tracer->dev;
+@@ -1136,7 +1134,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
+ /* Stop tracer + Cleanup HW resources */
+ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
+ {
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return;
+
+ mlx5_core_dbg(tracer->dev, "FWTracer: Cleanup, is owner ? (%d)\n",
+@@ -1155,7 +1153,7 @@ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
+ /* Free software resources (Buffers, etc ..) */
+ void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer)
+ {
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return;
+
+ mlx5_core_dbg(tracer->dev, "FWTracer: Destroy\n");
+@@ -1204,7 +1202,7 @@ int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer)
+ struct mlx5_core_dev *dev;
+ int err;
+
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return 0;
+
+ dev = tracer->dev;
+--
+2.53.0
+
--- /dev/null
+From b6c5958ee95b3aacc4c1ea89f0f249b80dcf62a8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 12:36:18 +0800
+Subject: net/ncsi: fix heap OOB read in NCSI_CMD_SEND_CMD payload length
+
+From: Henry Martin <bsdhenrymartin@gmail.com>
+
+[ Upstream commit afa58b7384913c8773d837acdb07b035690ec5d2 ]
+
+ncsi_send_cmd_nl() takes the number of bytes to copy from the
+attacker-controlled ncsi_pkt_hdr.length field of the in-band packet
+header, while the source buffer is the NCSI_ATTR_DATA netlink
+attribute whose readable size is nla_len() - sizeof(ncsi_pkt_hdr).
+The two length sources are never cross-checked: only
+nla_len() >= sizeof(struct ncsi_pkt_hdr) is enforced.
+
+With hdr->length set larger than the attribute payload (up to 65535
+against at most 2032 readable bytes), ncsi_cmd_handler_oem() copies
+past the end of the netlink attribute buffer with unsafe_memcpy(),
+leaking up to ~64KB of kernel heap memory into the transmitted NCSI
+command packet. The destination skb is sized by the declared payload,
+so the write side does not overflow - this is a pure OOB read /
+information leak, reachable with CAP_NET_ADMIN on systems with a
+registered NCSI device (e.g. OpenBMC on Aspeed BMC SoCs, where
+NET_NCSI=y is standard).
+
+Reject commands whose declared payload extends past the end of the
+data attribute.
+
+The issue was found by the autokbug dynamic kernel fuzzer at Tencent
+Yunding Lab.
+
+Fixes: 9771b8ccdfa6 ("net/ncsi: Extend NC-SI Netlink interface to allow user space to send NC-SI command")
+Reported-by: Henry Martin <bsdhenrymartin@gmail.com>
+Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>
+Link: https://patch.msgid.link/20260803043618.3210301-1-bsdhenrymartin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ncsi/ncsi-netlink.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/net/ncsi/ncsi-netlink.c b/net/ncsi/ncsi-netlink.c
+index db350b8f5d88b..82b22368a540a 100644
+--- a/net/ncsi/ncsi-netlink.c
++++ b/net/ncsi/ncsi-netlink.c
+@@ -461,6 +461,10 @@ static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info)
+ nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN;
+ nca.info = info;
+ nca.payload = ntohs(hdr->length);
++ if (nca.payload > len - sizeof(*hdr)) {
++ ret = -EINVAL;
++ goto out_netlink;
++ }
+ nca.data = data + sizeof(*hdr);
+
+ ret = ncsi_xmit_cmd(&nca);
+--
+2.53.0
+
--- /dev/null
+From 96a01c91d8bd20af07e77bf4e3e9f484d536abad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 18:20:06 -0400
+Subject: net/openvswitch: check Ethernet header length in key_extract()
+
+From: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+
+[ Upstream commit cf6f8b29befb92173659bcef6a441d274947bfae ]
+
+When a packet arrives on an ARPHRD_NONE device (e.g. TUN),
+ovs_flow_key_extract() trusts the user-provided skb->protocol field: if
+it is ETH_P_TEB, the packet is classified as MAC_PROTO_ETHERNET and
+key_extract() is called without ensuring the skb has ETH_HLEN (14) bytes
+of linear data. key_extract() unconditionally pulls 2 * ETH_ALEN bytes
+for MAC addresses and parse_ethertype() pulls 2 more, either of which
+triggers a kernel BUG in __skb_pull() when the linear area is too small.
+
+ kernel BUG at include/linux/skbuff.h:2848!
+ RIP: 0010:key_extract+0xa7e/0xd90 net/openvswitch/flow.c:933
+ ovs_flow_key_extract+0x419/0xa70
+ ovs_vport_receive+0x222/0x390
+ netdev_frame_hook+0x3e0/0x630
+ tun_get_user+0x2d0c/0x38e0
+
+Fixed by calling check_header() in key_extract() before accessing the
+Ethernet header.
+
+Fixes: 217ac77a3c25 ("openvswitch: allow L3 netdev ports")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Reviewed-by: Eelco Chaudron <echaudro@redhat.com>
+Signed-off-by: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
+Link: https://patch.msgid.link/20260730222006.118652-1-blbllhy@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/flow.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
+index 52ba0e7721cd6..635edddbd55ff 100644
+--- a/net/openvswitch/flow.c
++++ b/net/openvswitch/flow.c
+@@ -749,8 +749,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ * Ethernet header
+ * @key: output flow key
+ *
+- * The caller must ensure that skb->len >= ETH_HLEN.
+- *
+ * Initializes @skb header fields as follows:
+ *
+ * - skb->mac_header: the L2 header.
+@@ -770,8 +768,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ */
+ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+ {
+- struct ethhdr *eth;
+-
+ /* Flags are always used as part of stats */
+ key->tp.flags = 0;
+
+@@ -786,6 +782,13 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+ skb_reset_network_header(skb);
+ key->eth.type = skb->protocol;
+ } else {
++ struct ethhdr *eth;
++ int err;
++
++ err = check_header(skb, ETH_HLEN);
++ if (unlikely(err))
++ return err;
++
+ eth = eth_hdr(skb);
+ ether_addr_copy(key->eth.src, eth->h_source);
+ ether_addr_copy(key->eth.dst, eth->h_dest);
+--
+2.53.0
+
--- /dev/null
+From 41117a0598512f81b4103636d1225424080fbcc4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 22:19:06 +0800
+Subject: net: prestera: validate firmware header length
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 8ae344eb540af3f457179b52bc6061416752485c ]
+
+prestera_fw_hdr_parse() reads the firmware header before checking
+that the firmware image contains that header.
+
+Reject images shorter than struct prestera_fw_header before decoding the
+magic and version fields.
+
+Fixes: 4c2703dfd7fabb ("net: marvell: prestera: Add PCI interface support")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Acked-by: Elad Nachman <enachman@marvell.com>
+Link: https://patch.msgid.link/20260731141500.1-prestera-v2-pengpeng@iscas.ac.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/marvell/prestera/prestera_pci.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/marvell/prestera/prestera_pci.c b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+index 6bef633aa6330..94bcae9020eb7 100644
+--- a/drivers/net/ethernet/marvell/prestera/prestera_pci.c
++++ b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+@@ -616,6 +616,9 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw)
+ struct prestera_fw_header *hdr;
+ u32 magic;
+
++ if (fw->bin->size < sizeof(*hdr))
++ return -EINVAL;
++
+ hdr = (struct prestera_fw_header *)fw->bin->data;
+
+ magic = be32_to_cpu(hdr->magic_number);
+--
+2.53.0
+
--- /dev/null
+From 0b7d37122ec5a9f43341094c7550673688862ec0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 22:18:30 +0200
+Subject: net: qrtr: ns: Raise lookup limit to 128
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Łukasz Patron <priv.luk@gmail.com>
+
+[ Upstream commit 7fc1c937b6b37c77df4ba374c37435ab06a2e945 ]
+
+Current limit of 64 is not enough for Sony Xperia 10 VII (SM6475).
+
+After merging v6.6.142 into a downstream AOSP device, it's stuck on
+boot animation and following log spam can be observed in dmesg:
+
+E qrtr : ctrl_cmd_new_lookup(): QRTR client node exceeds max lookup limit!
+E qrtr : qrtr_ns_worker(): failed while handling packet from 1:16600
+
+No idea why it needs more than 64 client lookups, but it appears to
+work fine with 128 as it did when there were no limits.
+
+I don't really have a good way to investigate what it needs all
+these lookups for as most of the userspace is closed source.
+
+Fixes: 5640227d9a21 ("net: qrtr: ns: Limit the maximum number of lookups")
+Signed-off-by: Łukasz Patron <priv.luk@gmail.com>
+Link: https://patch.msgid.link/20260804201919.1148015-1-priv.luk@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/ns.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c
+index 5220529a4c62d..4df5f0a9b7419 100644
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -77,7 +77,7 @@ struct qrtr_node {
+ */
+ #define QRTR_NS_MAX_NODES 512
+ #define QRTR_NS_MAX_SERVERS 256
+-#define QRTR_NS_MAX_LOOKUPS 64
++#define QRTR_NS_MAX_LOOKUPS 128
+
+ static u16 node_count;
+
+--
+2.53.0
+
--- /dev/null
+From 58217cd42dc8597ff068d1ae68bc24dee1e76377 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 15:20:48 +0000
+Subject: net: remove WARN_ON_ONCE() from sk_mc_loop()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit b8a39a09ae4eaae04309e1e38ed6a1101d967496 ]
+
+sk_mc_loop() can be called for sockets that are neither AF_INET
+nor AF_INET6 (e.g. AF_PACKET sockets when sending packets via raw/packet
+socket over virtual devices such as VRF or ipvlan).
+
+In such cases, sk_family is not AF_INET/AF_INET6 and sk_mc_loop() falls
+through the switch statement and triggers WARN_ON_ONCE(1).
+
+Non-INET sockets do not support IP_MULTICAST_LOOP or IPV6_MULTICAST_LOOP
+options, so loopback should default to true without generating a warning.
+
+Fixes: f60e5990d9c1 ("ipv6: protect skb->sk accesses from recursive dereference inside the stack")
+Reported-by: syzbot+22c3218a6fa219e47321@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/6a72024c.13623e66.bdc14.0019.GAE@google.com/T/#u
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260804152048.2134341-1-edumazet@google.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/sock.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/net/core/sock.c b/net/core/sock.c
+index bf2bec10d5d6a..e5f8916aa85b8 100644
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -724,7 +724,6 @@ bool sk_mc_loop(struct sock *sk)
+ return inet6_sk(sk)->mc_loop;
+ #endif
+ }
+- WARN_ON_ONCE(1);
+ return true;
+ }
+ EXPORT_SYMBOL(sk_mc_loop);
+--
+2.53.0
+
--- /dev/null
+From 1c4e37d23627494abd0097d9037e1715d43caa52 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 05:44:11 -0400
+Subject: net/sched: cls_route: fix fastmap use-after-free on filter
+
+From: Jamal Hadi Salim <jhs@mojatatu.com>
+
+[ Upstream commit 47d7f7051253bdc02b1d245d87e38f16d31a74df ]
+
+The route4 classifier maintains a 16-slot fastmap cache that stores raw
+struct route4_filter pointers indexed by (id, iif). The reader
+(route4_classify) populates this cache via route4_set_fastmap() for every
+classified packet that hits a filter. The writer (route4_delete,
+route4_change) clears the cache via route4_reset_fastmap() before
+RCU-deferred kfree of the filter.
+
+This creates a UAF race:
+ 1. Reader walks the RCU-protected bucket chain, finds filter f
+ 2. Writer unlinks f, calls route4_reset_fastmap(), then tcf_queue_work()
+ 3. Reader calls route4_set_fastmap() and writes f into the cache
+ *after* the writer's reset, caching a pointer about to be freed
+ 4. After the RCU grace period, kfree(f) executes
+ 5. Next classified packet on the same (id, iif) tuple hits the stale
+ fastmap entry and reads f->res from freed memory
+
+Reproduced with an mdelay(100) accelerator in route4_set_fastmap() and a
+concurrent add/delete stress test (provided by both zdi and Santosh).
+Both triggered KASAN slab-use-after-free reports in the route4 fastmap
+paths.
+
+Fix:
+Introduce a per-filter boolean dying flag to suppress stale fastmap
+republishing by in-flight readers.
+
+Fixes: 1109c00547fc ("net: sched: RCU cls_route")
+Reported-by: zdi-disclosures@trendmicro.com
+Reported-by: Santosh Kalluri <santosh.kalluri129@gmail.com>
+Suggested-by: Paolo Abeni <pabeni@redhat.com>
+Tested-by: Victor Nogueira <victor@mojatatu.com>
+Tested-by: Santosh Kalluri <santosh.kalluri129@gmail.com>
+Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260729094411.46257-1-jhs@mojatatu.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_route.c | 35 ++++++++++++++++++++++++++---------
+ 1 file changed, 26 insertions(+), 9 deletions(-)
+
+diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
+index 194468d0355a1..1ce483fd30379 100644
+--- a/net/sched/cls_route.c
++++ b/net/sched/cls_route.c
+@@ -51,6 +51,7 @@ struct route4_filter {
+ struct tcf_result res;
+ struct tcf_exts exts;
+ u32 handle;
++ bool dying;
+ struct route4_bucket *bkt;
+ struct tcf_proto *tp;
+ struct rcu_work rwork;
+@@ -65,9 +66,11 @@ static inline int route4_fastmap_hash(u32 id, int iif)
+
+ static DEFINE_SPINLOCK(fastmap_lock);
+ static void
+-route4_reset_fastmap(struct route4_head *head)
++route4_reset_fastmap(struct route4_head *head, struct route4_filter *f)
+ {
+ spin_lock_bh(&fastmap_lock);
++ if (f)
++ f->dying = true;
+ memset(head->fastmap, 0, sizeof(head->fastmap));
+ spin_unlock_bh(&fastmap_lock);
+ }
+@@ -80,9 +83,11 @@ route4_set_fastmap(struct route4_head *head, u32 id, int iif,
+
+ /* fastmap updates must look atomic to aling id, iff, filter */
+ spin_lock_bh(&fastmap_lock);
+- head->fastmap[h].id = id;
+- head->fastmap[h].iif = iif;
+- head->fastmap[h].filter = f;
++ if (f == ROUTE4_FAILURE || !f->dying) {
++ head->fastmap[h].id = id;
++ head->fastmap[h].iif = iif;
++ head->fastmap[h].filter = f;
++ }
+ spin_unlock_bh(&fastmap_lock);
+ }
+
+@@ -295,6 +300,13 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
+ next = rtnl_dereference(f->next);
+ RCU_INIT_POINTER(b->ht[h2], next);
+ tcf_unbind_filter(tp, &f->res);
++ /* Mark the filter dying under fastmap_lock so
++ * any in-flight reader that still holds it
++ * will skip the republish in route4_set_fastmap().
++ */
++ spin_lock_bh(&fastmap_lock);
++ f->dying = true;
++ spin_unlock_bh(&fastmap_lock);
+ if (tcf_exts_get_net(&f->exts))
+ route4_queue_work(f);
+ else
+@@ -305,6 +317,11 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
+ kfree_rcu(b, rcu);
+ }
+ }
++
++ /* All filters are unlinked and marked dying, so no in-flight
++ * reader can republish a stale entry after this reset.
++ */
++ route4_reset_fastmap(head, NULL);
+ kfree_rcu(head, rcu);
+ }
+
+@@ -332,11 +349,11 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,
+ /* unlink it */
+ RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
+
+- /* Remove any fastmap lookups that might ref filter
+- * notice we unlink'd the filter so we can't get it
+- * back in the fastmap.
++ /* Clear any fastmap entries that may ref this filter and
++ * mark it dying so in-flight readers can't republish it
++ * after the reset.
+ */
+- route4_reset_fastmap(head);
++ route4_reset_fastmap(head, f);
+
+ /* Delete it */
+ tcf_unbind_filter(tp, &f->res);
+@@ -551,7 +568,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
+ }
+ }
+
+- route4_reset_fastmap(head);
++ route4_reset_fastmap(head, fold);
+ *arg = f;
+ if (fold) {
+ tcf_unbind_filter(tp, &fold->res);
+--
+2.53.0
+
--- /dev/null
+From 2354b1e970b4b66ae5de41e93edb093b20d1543b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 21:14:16 +0200
+Subject: net/sched: sch_cake: drop WARN_ON(1) for malformed packets in ACK
+ filter
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Toke Høiland-Jørgensen <toke@toke.dk>
+
+[ Upstream commit 2a33516f9ef59ad11844d4fc152f889449b5daf3 ]
+
+The sch_cake ACK filter parses packets to find the TCP header and filter
+duplicated ACKs if the flow is backlogged. The parsing code contains a
+WARN_ON(1) which can be triggered by a malformed IP header in certain
+cases. Depending on the system configuration, this leads either to
+either spamming dmesg with warnings, or a panic if panic_on_warn is set.
+
+The code already correctly skips the offending packet in the branch that
+triggers the warning, so the WARN_ON itself doesn't really serve any
+purpose. So just drop it altogether to avoid the inconvenient side
+effects.
+
+Fixes: 8b7138814f29 ("sch_cake: Add optional ACK filter")
+Reported-by: Zhiling Zou <zhilinz@nebusec.ai>
+Reported-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
+Link: https://patch.msgid.link/20260729191417.45665-1-toke@toke.dk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_cake.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c
+index ad2597deebab6..d94c9c11ac1e2 100644
+--- a/net/sched/sch_cake.c
++++ b/net/sched/sch_cake.c
+@@ -1281,7 +1281,6 @@ static struct sk_buff *cake_ack_filter(struct cake_sched_data *q,
+
+ seglen = ntohs(ipv6h_check->payload_len);
+ } else {
+- WARN_ON(1); /* shouldn't happen */
+ continue;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From f5243ee866d4472a989260b7cff7375b95cb22f7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:01:53 +0200
+Subject: net/smc: fix qentry overwrite for CONFIRM_LINK and ADD_LINK_CONT in
+ smc_llc_event_handler()
+
+From: Mahanta Jambigi <mjambigi@linux.ibm.com>
+
+[ Upstream commit 976245094925bab9bc39366b2e9ab44ffcde61d0 ]
+
+The SMC_LLC_CONFIRM_LINK / SMC_LLC_ADD_LINK_CONT branch in
+smc_llc_event_handler() stores an incoming qentry into the local LLC flow
+without first checking whether a qentry is already pending. If a malicious or
+buggy peer sends a second CONFIRM_LINK or ADD_LINK_CONT request while a flow is
+active and flow->qentry is already set, smc_llc_flow_qentry_set() overwrites the
+pointer without freeing the previous allocation, leaking one kmalloc-96 object
+per spurious message.
+
+The sibling SMC_LLC_DELETE_LINK branch already has the correct !flow->qentry
+guard. Apply the same guard to the CONFIRM_LINK/ADD_LINK_CONT branch so that a
+duplicate message when qentry is already occupied falls through to break and is
+freed by the kfree(qentry) at the out: label, rather than silently leaking the
+existing allocation.
+
+The response direction (smc_llc_rx_response()) is unaffected: it already guards
+with flow->qentry at the equivalent site and drops duplicate responses
+correctly.
+
+Fixes: 0fb0b02bd6fd ("net/smc: adapt SMC client code to use the LLC flow")
+Signed-off-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
+Reviewed-by: Hidayath Khan <hidayath@linux.ibm.com>
+Reviewed-by: Sidraya Jayagond <sidraya@linux.ibm.com>
+Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
+Link: https://patch.msgid.link/20260729130153.970800-1-mjambigi@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/smc_llc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c
+index d5ee961ca72d5..572d02bfd3eda 100644
+--- a/net/smc/smc_llc.c
++++ b/net/smc/smc_llc.c
+@@ -1582,7 +1582,8 @@ static void smc_llc_event_handler(struct smc_llc_qentry *qentry)
+ return;
+ case SMC_LLC_CONFIRM_LINK:
+ case SMC_LLC_ADD_LINK_CONT:
+- if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) {
++ if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE &&
++ !lgr->llc_flow_lcl.qentry) {
+ /* a flow is waiting for this message */
+ smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry);
+ wake_up(&lgr->llc_msg_waiter);
+--
+2.53.0
+
--- /dev/null
+From 5eaa1334fa42635a0bc8c0a73045deb321611132 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 09:07:01 +0200
+Subject: net/smc: fix TOCTOU race between smc_listen_out() and listener close
+
+From: Sidraya Jayagond <sidraya@linux.ibm.com>
+
+[ Upstream commit 185a4caeecabc150106deda1da170b09f2ad803f ]
+
+smc_listen_out() reads lsmc->sk.sk_state without the listener lock,
+then acquires lock_sock_nested() only after the check passes. This
+opens a window where smc_close_active() can transition the listener
+to SMC_CLOSED, call smc_close_cleanup_listen() to drain the accept
+queue, and release the lock, all between the lockless read and the
+delayed lock acquisition:
+
+ smc_listen_work (smc_hs_wq) smc_close_active()
+ ------------------------------- -------------------------
+ release_sock(child)
+ if (sk_state == SMC_LISTEN) TRUE
+ lock_sock(listener)
+ sk_state = SMC_CLOSED
+ smc_close_cleanup_listen()
+ release_sock(listener)
+ flush_work(tcp_listen_work)
+ lock_sock_nested(listener)
+ smc_accept_enqueue(listener, child) /* child enqueued on dead listener */
+
+smc_close_active() flushes only tcp_listen_work. Work items already
+dispatched onto smc_hs_wq for the CLC handshake continue running
+unguarded. smc_accept_enqueue() takes a sock_hold() on the child that
+is never released, so the child smc_sock, its clcsock, and the
+reference all leak. A remote peer that opens TCP connections while the
+server calls close() can exhaust kernel memory.
+
+Move lock_sock_nested() to before the sk_state check so that the test
+and the enqueue are atomic under the listener lock.
+
+Fixes: fd57770dd198 ("net/smc: wait for pending work before clcsock release_sock")
+Reviewed-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
+Signed-off-by: Sidraya Jayagond <sidraya@linux.ibm.com>
+Reviewed-by: Breno Leitao <leitao@debian.org>
+Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
+Link: https://patch.msgid.link/20260803070701.126339-1-sidraya@linux.ibm.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/af_smc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
+index 6b60a5dd240dd..7bbb59e170a6b 100644
+--- a/net/smc/af_smc.c
++++ b/net/smc/af_smc.c
+@@ -1574,11 +1574,12 @@ static void smc_listen_out(struct smc_sock *new_smc)
+ atomic_dec(&lsmc->queued_smc_hs);
+
+ release_sock(newsmcsk); /* lock in smc_listen_work() */
++ lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
+ if (lsmc->sk.sk_state == SMC_LISTEN) {
+- lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
+ smc_accept_enqueue(&lsmc->sk, newsmcsk);
+ release_sock(&lsmc->sk);
+ } else { /* no longer listening */
++ release_sock(&lsmc->sk);
+ smc_close_non_accepted(newsmcsk);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From b7fe909c6522bf50a0895cddaeb069ddc7c4f03a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 14:38:50 +0000
+Subject: net: thunderbolt: Tear down DMA paths before stopping the rings
+
+From: Fan XinRan <shinjiangjiang@gmail.com>
+
+[ Upstream commit 68bf02b6b4ad3f748c6db71fd77b6c0402d252f4 ]
+
+tbnet_tear_down() stops both rings and frees their frame buffers before
+calling tb_xdomain_disable_paths(). tb_ring_stop() zeroes the ring's
+descriptor base and tbnet_free_buffers() unmaps and frees the pages the
+frames sit in, so by the time __tb_path_deactivate_hop() polls the hop's
+'pending' bit, anything still in flight has nowhere to drain to.
+
+The teardown sequence has been in this order since the driver was added.
+The setup path has not: commit ff7cd07f3064 ("net: thunderbolt: Enable
+DMA paths only after rings are enabled") moved the path enable to the end
+of tbnet_connected_work() and documented why:
+
+ /* Both logins successful so enable the rings, high-speed DMA
+ * paths and start the network device queue.
+ *
+ * Note we enable the DMA paths last to make sure we have primed
+ * the Rx ring before any incoming packets are allowed to
+ * arrive.
+ */
+
+Teardown was never updated to match, so the rings and the paths now come
+down in the same order they go up instead of in reverse.
+
+On an ASMedia ASM4242 host router the 'pending' bit then never clears:
+every teardown burns the full 500 ms timeout and
+__tb_path_deactivate_hop() returns -ETIMEDOUT. Raising the timeout to
+5 s does not help, so the hop is not slow to drain, it never drains
+at all.
+
+The failure is invisible above the thunderbolt core.
+__tb_path_deactivate_hops() is void and only calls tb_port_warn();
+tb_path_deactivate(), tb_tunnel_deactivate() and
+__tb_disconnect_xdomain_paths() are void as well, and
+tb_disconnect_xdomain_paths() ends in an unconditional "return 0". So
+tb_xdomain_disable_paths() reports success and the netdev_warn() below
+it never fires. Repeated teardowns eventually take the XDomain control
+channel down, after which the peer node is gone and only a power cycle
+brings the controller back.
+
+Deactivating the paths first fixes it. Measured with kretprobes on a
+stock v6.17 tree with no other patches applied, on a link that was up
+and had just carried traffic:
+
+ before: __tb_path_deactivate_hop() returns 0 for the first hop, then
+ -ETIMEDOUT for the second 500335 us later
+ after: 0 for both, 525 us apart
+
+Alternating the two orderings ABBA over three load levels, four
+teardowns per arm: every teardown failed before the change (21 of 21
+that ran), none failed after (0 of 24). The before arms ran short
+because the link died partway through. The same split shows up when
+the interface is enslaved to a bond instead of just brought down, which
+is how I ran into this in the first place. Throughput and latency after
+the change are unchanged.
+
+Hosts whose routers drain the hop despite the stale descriptor base see
+no functional difference, since the paths end up deactivated either way.
+
+Fixes: e69b6c02b4c3 ("net: Add support for networking over Thunderbolt cable")
+Signed-off-by: Fan XinRan <shinjiangjiang@gmail.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Link: https://patch.msgid.link/20260803-b4-tbnet-teardown-v2-1-27de6a13ca2d@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/thunderbolt.c | 20 +++++++++++++++-----
+ 1 file changed, 15 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/thunderbolt.c b/drivers/net/thunderbolt.c
+index ba9f7062f5a7d..53d56cc860cd2 100644
+--- a/drivers/net/thunderbolt.c
++++ b/drivers/net/thunderbolt.c
+@@ -373,11 +373,16 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)
+ break;
+ }
+
+- tb_ring_stop(net->rx_ring.ring);
+- tb_ring_stop(net->tx_ring.ring);
+- tbnet_free_buffers(&net->rx_ring);
+- tbnet_free_buffers(&net->tx_ring);
+-
++ /* Tear the paths down before stopping the rings. This mirrors
++ * tbnet_connected_work(), which enables the paths last so the
++ * Rx ring is primed before packets can arrive. Stopping a
++ * ring zeroes its descriptor base and tbnet_free_buffers()
++ * unmaps and frees the frame buffers, leaving anything still
++ * in flight with nowhere to drain to;
++ * __tb_path_deactivate_hop() then waits for the hop's
++ * 'pending' bit, which on some host routers never clears in
++ * that state.
++ */
+ ret = tb_xdomain_disable_paths(net->xd,
+ net->local_transmit_path,
+ net->tx_ring.ring->hop,
+@@ -386,6 +391,11 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)
+ if (ret)
+ netdev_warn(net->dev, "failed to disable DMA paths\n");
+
++ tb_ring_stop(net->rx_ring.ring);
++ tb_ring_stop(net->tx_ring.ring);
++ tbnet_free_buffers(&net->rx_ring);
++ tbnet_free_buffers(&net->tx_ring);
++
+ tb_xdomain_release_in_hopid(net->xd, net->remote_transmit_path);
+ net->remote_transmit_path = 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From efa14b8975e450782e29525d1bad8c72ba856f55 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 30 Jun 2026 14:31:00 -0400
+Subject: NFS: Pin the 'struct nfs_server' during a FREE_STATEID call
+
+From: Anna Schumaker <anna.schumaker@hammerspace.com>
+
+[ Upstream commit cf616096a0f3a2b60f7d68b6b39674a6867ded9c ]
+
+Dan Aloni reports that he was able to hit a use-after-free bug if a
+FREE_STATEID operation gets delayed for whatever reason. Fix this by
+bumping the refcount of the 'struct nfs_server' object for the duration
+of the FREE_STATEID so it doesn't get cleaned up from underneath us
+while operations are still in flight.
+
+Reported-by: Dan Aloni <dan.aloni@vastdata.com>
+Fixes: 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call")
+Tested-by: Dan Aloni <dan.aloni@vastdata.com>
+Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/nfs4proc.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index 41bbc9407680f..25aaae1d6345e 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -10297,6 +10297,7 @@ static void nfs41_free_stateid_release(void *calldata)
+ struct nfs_free_stateid_data *data = calldata;
+ struct nfs_client *clp = data->server->nfs_client;
+
++ nfs_sb_deactive(data->server->super);
+ nfs_put_client(clp);
+ kfree(calldata);
+ }
+@@ -10338,6 +10339,10 @@ static int nfs41_free_stateid(struct nfs_server *server,
+
+ if (!refcount_inc_not_zero(&clp->cl_count))
+ return -EIO;
++ if (!nfs_sb_active(server->super)) {
++ nfs_put_client(clp);
++ return -EIO;
++ }
+
+ nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
+ &task_setup.rpc_client, &msg);
+--
+2.53.0
+
--- /dev/null
+From 6ed2d86d2ae1c17adc72b46f8086d495bb3a1ce1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 3 Nov 2021 06:24:40 -0400
+Subject: nfs4: take a reference on the nfs_client when running FREE_STATEID
+
+From: Scott Mayhew <smayhew@redhat.com>
+
+[ Upstream commit 576acc259146af848cec0940f573f7125a116b9f ]
+
+During umount, the session slot tables are freed. If there are
+outstanding FREE_STATEID tasks, a use-after-free and slab corruption can
+occur when rpc_exit_task calls rpc_call_done -> nfs41_sequence_done ->
+nfs4_sequence_process/nfs41_sequence_free_slot.
+
+Prevent that from happening by taking a reference on the nfs_client in
+nfs41_free_stateid and putting it in nfs41_free_stateid_release.
+
+Signed-off-by: Scott Mayhew <smayhew@redhat.com>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Stable-dep-of: cf616096a0f3 ("NFS: Pin the 'struct nfs_server' during a FREE_STATEID call")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/nfs4proc.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index cd97312860ce6..41bbc9407680f 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -10294,6 +10294,10 @@ static void nfs41_free_stateid_done(struct rpc_task *task, void *calldata)
+
+ static void nfs41_free_stateid_release(void *calldata)
+ {
++ struct nfs_free_stateid_data *data = calldata;
++ struct nfs_client *clp = data->server->nfs_client;
++
++ nfs_put_client(clp);
+ kfree(calldata);
+ }
+
+@@ -10330,6 +10334,10 @@ static int nfs41_free_stateid(struct nfs_server *server,
+ };
+ struct nfs_free_stateid_data *data;
+ struct rpc_task *task;
++ struct nfs_client *clp = server->nfs_client;
++
++ if (!refcount_inc_not_zero(&clp->cl_count))
++ return -EIO;
+
+ nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
+ &task_setup.rpc_client, &msg);
+--
+2.53.0
+
--- /dev/null
+From 47087644103d60ae0a5837e7cf6f9d5bf2509258 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 11:18:40 -0400
+Subject: sctp: clear control chunk transport if it is being removed
+
+From: Xin Long <lucien.xin@gmail.com>
+
+[ Upstream commit c9158ceaf27780ef64534ad72f44ffde3f8ccc49 ]
+
+sctp_make_heartbeat_ack() caches the destination transport in
+chunk->transport without taking a reference. When src_out_of_asoc_ok is
+enabled, the HEARTBEAT ACK may remain queued on control_chunk_list instead
+of being transmitted immediately.
+
+If the peer transport is removed while the chunk is still queued,
+sctp_assoc_rm_peer() drops the transport and schedules it for RCU freeing,
+but only clears cached transport pointers in out_chunk_list. The queued
+control chunk therefore retains a dangling transport pointer.
+
+Once an ASCONF_ACK clears the suppression and the queued control chunk is
+transmitted, SCTP dereferences the stale transport pointer, leading to a
+use-after-free.
+
+Fix this by also clearing chunk->transport for queued control chunks in
+control_chunk_list when removing the transport.
+
+Fixes: 8a07eb0a50ae ("sctp: Add ASCONF operation on the single-homed host")
+Reported-by: Daniele Linguaglossa <danielelinguaglossa@gmail.com>
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/7e1168cb722132152a29d47e5eafaeac4a3bf6f3.1785943120.git.lucien.xin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/associola.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/net/sctp/associola.c b/net/sctp/associola.c
+index 4dd36c8375507..4a79e855c85cd 100644
+--- a/net/sctp/associola.c
++++ b/net/sctp/associola.c
+@@ -575,6 +575,10 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
+ if (ch->transport == peer)
+ ch->transport = NULL;
+
++ list_for_each_entry(ch, &asoc->outqueue.control_chunk_list, list)
++ if (ch->transport == peer)
++ ch->transport = NULL;
++
+ asoc->peer.transport_count--;
+
+ sctp_ulpevent_notify_peer_addr_change(peer, SCTP_ADDR_REMOVED, 0);
+--
+2.53.0
+
--- /dev/null
+From b08f944054f473e96eccc65cc045e6740c3ba46f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 10:55:14 +0800
+Subject: sctp: fix addip_serial increment on ASCONF_ACK allocation failure
+
+From: Qing Luo <luoqing@kylinos.cn>
+
+[ Upstream commit aa2e13ae8d3cbe2c15ef4f7e971b2de0832794aa ]
+
+In sctp_process_asconf(), when sctp_make_asconf_ack() fails to allocate
+the ASCONF_ACK chunk due to memory pressure, the code jumps to the
+done label where asoc->peer.addip_serial is unconditionally incremented.
+
+This leaves the peer's ASCONF (serial N) unacknowledged while the local
+endpoint now expects serial N+1. When the peer retransmits serial N, it
+falls into the serial < addip_serial + 1 branch ,
+which attempts to look up a cached ACK for serial N. No cached ACK
+exists since the allocation failed, so the retransmission is silently
+discarded. The peer eventually times out and ABORTs the association.
+
+Move the addip_serial increment inside the if (asconf_ack) block so that
+the serial number is only advanced when the ASCONF_ACK is successfully
+created and cached. This way, on allocation failure, the serial number
+is unchanged and the peer's retransmitted ASCONF will be correctly
+re-processed.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Qing Luo <luoqing@kylinos.cn>
+Acked-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/20260804025514.241767-1-l1138897701@163.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/sm_make_chunk.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
+index 837fb8280bfd5..6d738f95aff1d 100644
+--- a/net/sctp/sm_make_chunk.c
++++ b/net/sctp/sm_make_chunk.c
+@@ -3362,12 +3362,11 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
+ goto done;
+ }
+ done:
+- asoc->peer.addip_serial++;
+-
+ /* If we are sending a new ASCONF_ACK hold a reference to it in assoc
+ * after freeing the reference to old asconf ack if any.
+ */
+ if (asconf_ack) {
++ asoc->peer.addip_serial++;
+ sctp_chunk_hold(asconf_ack);
+ list_add_tail(&asconf_ack->transmitted_list,
+ &asoc->asconf_ack_list);
+--
+2.53.0
+
--- /dev/null
+From 1027ded263b9c11d589922e595e132057622ae0f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jun 2022 10:19:08 +0800
+Subject: selftests/ftrace: Add test case for GRP/ only input
+
+From: Linyu Yuan <quic_linyyuan@quicinc.com>
+
+[ Upstream commit 5db19792f0660ad1ece247829bddd24bb2f8db25 ]
+
+Add kprobe and eprobe event test for new GRP/ only format.
+
+Link: https://lore.kernel.org/all/1656296348-16111-5-git-send-email-quic_linyyuan@quicinc.com/
+
+Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Reviewed-by: Tom Zanussi <zanussi@kernel.org>
+Signed-off-by: Linyu Yuan <quic_linyyuan@quicinc.com>
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Stable-dep-of: 6e3abef2a27e ("selftests/ftrace: refactor eprobes test to fix argument checks")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ftrace/test.d/dynevent/add_remove_eprobe.tc | 9 ++++++++-
+ .../ftrace/test.d/dynevent/add_remove_kprobe.tc | 7 +++++++
+ 2 files changed, 15 insertions(+), 1 deletion(-)
+
+diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
+index 60c02b482be83..c300eb0202620 100644
+--- a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
++++ b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
+@@ -1,7 +1,7 @@
+ #!/bin/sh
+ # SPDX-License-Identifier: GPL-2.0
+ # description: Generic dynamic event - add/remove eprobe events
+-# requires: dynamic_events events/syscalls/sys_enter_openat "e[:[<group>/]<event>] <attached-group>.<attached-event> [<args>]":README
++# requires: dynamic_events events/syscalls/sys_enter_openat "<attached-group>.<attached-event> [<args>]":README
+
+ echo 0 > events/enable
+
+@@ -87,4 +87,11 @@ echo "-:eprobes/$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
+ ! grep -q "$EPROBE" dynamic_events
+ ! test -d events/eprobes/$EPROBE
+
++if grep -q "e\[:\[<group>/]\[<event>]]" README; then
++ echo "e:mygroup/ $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
++ test -d events/mygroup
++ echo "-:mygroup/" >> dynamic_events
++ ! test -d events/mygroup
++fi
++
+ clear_trace
+diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_kprobe.tc b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_kprobe.tc
+index b4da41d126d58..13d43f40a6fc6 100644
+--- a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_kprobe.tc
++++ b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_kprobe.tc
+@@ -23,4 +23,11 @@ grep -q myevent1 dynamic_events
+
+ echo > dynamic_events
+
++if grep -q "p\[:\[<group>/]\[<event>]]" README; then
++ echo "p:mygroup/ $PLACE" >> dynamic_events
++ test -d events/mygroup
++ echo "-:mygroup/" >> dynamic_events
++ ! test -d events/mygroup
++fi
++
+ clear_trace
+--
+2.53.0
+
--- /dev/null
+From 334fc362a7659923df346db5a29a0e21b2f13187 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 21:46:35 +0200
+Subject: selftests/ftrace: refactor eprobes test to fix argument checks
+
+From: Martin Kaiser <martin@kaiser.cx>
+
+[ Upstream commit 6e3abef2a27e7402a94111c9eff85d887e64a309 ]
+
+The add/remove eprobe test installs an eprobe for the openat syscall and
+runs ls. It checks the filenames that were opened by ls against a
+whitelist and a blacklist.
+
+Commit 206b25c09080 ("tracing: eprobe: read the complete FILTER_PTR_STRING
+pointer") fixed access to some string fields in eprobes. This triggers
+test failures as the blacklist does not allow relative paths for the
+openat parameters.
+
+What makes this test unstable is the fact that the openat calls vary a
+lot between different systems.
+
+Refactor the test to make it more robust. "cd <directory>" will issue a
+chdir syscall with the target directory as parameter. Set an eprobe on
+the sys_enter_chdir event and filter for the exact directory name. Allow
+(fault) as fallback.
+
+Link: https://lore.kernel.org/all/20260804194705.760893-1-martin@kaiser.cx/
+
+Fixes: 206b25c09080 ("tracing: eprobe: read the complete FILTER_PTR_STRING pointer")
+Reported-by: kernel test robot <oliver.sang@intel.com>
+Closes: https://lore.kernel.org/oe-lkp/202607151010.b68428e1-lkp@intel.com
+Signed-off-by: Martin Kaiser <martin@kaiser.cx>
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ftrace/test.d/dynevent/add_remove_eprobe.tc | 16 +++++-----------
+ 1 file changed, 5 insertions(+), 11 deletions(-)
+
+diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
+index c300eb0202620..e2322693d0c32 100644
+--- a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
++++ b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
+@@ -1,16 +1,16 @@
+ #!/bin/sh
+ # SPDX-License-Identifier: GPL-2.0
+ # description: Generic dynamic event - add/remove eprobe events
+-# requires: dynamic_events events/syscalls/sys_enter_openat "<attached-group>.<attached-event> [<args>]":README
++# requires: dynamic_events events/syscalls/sys_enter_chdir "<attached-group>.<attached-event> [<args>]":README
+
+ echo 0 > events/enable
+
+ clear_dynamic_events
+
+ SYSTEM="syscalls"
+-EVENT="sys_enter_openat"
++EVENT="sys_enter_chdir"
+ FIELD="filename"
+-EPROBE="eprobe_open"
++EPROBE="eprobe_chdir"
+ OPTIONS="file=+0(\$filename):ustring"
+ echo "e:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
+
+@@ -18,20 +18,14 @@ grep -q "$EPROBE" dynamic_events
+ test -d events/eprobes/$EPROBE
+
+ echo 1 > events/eprobes/$EPROBE/enable
+-ls
++cd /sys/kernel/tracing
+ echo 0 > events/eprobes/$EPROBE/enable
+
+-content=`grep '^ *ls-' trace | grep 'file='`
+-nocontent=`grep '^ *ls-' trace | grep 'file=' | grep -v -e '"/' -e '"."' -e '(fault)' ` || true
+-
++content=`grep -e 'file="/sys/kernel/tracing"\|(fault)' trace`
+ if [ -z "$content" ]; then
+ exit_fail
+ fi
+
+-if [ ! -z "$nocontent" ]; then
+- exit_fail
+-fi
+-
+ echo "-:$EPROBE" >> dynamic_events
+
+ ! grep -q "$EPROBE" dynamic_events
+--
+2.53.0
+
gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch
mount-honour-sb_nouser-in-the-new-mount-api.patch
s390-zcrypt-fix-missing-mem-scrub-at-clear-key-impor.patch
+nfs4-take-a-reference-on-the-nfs_client-when-running.patch
+nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch
+arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch
+bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch
+bpf-preserve-pointer-state-for-commuted-arithmetic.patch
+net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch
+net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch
+net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch
+net-mlx5-fw_tracer-return-null-on-create-error.patch
+counter-microchip-tcb-capture-fix-dt-channel-validat.patch
+vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch
+udp-fix-potential-use-after-free-in-tunnel-segmentat.patch
+net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch
+net-openvswitch-check-ethernet-header-length-in-key_.patch
+selftests-ftrace-add-test-case-for-grp-only-input.patch
+selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch
+bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch
+bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch
+bnxt_en-fix-ptp-pps-setting-bug.patch
+sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch
+tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch
+net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch
+net-prestera-validate-firmware-header-length.patch
+net-remove-warn_on_once-from-sk_mc_loop.patch
+net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch
+net-qrtr-ns-raise-lookup-limit-to-128.patch
+net-thunderbolt-tear-down-dma-paths-before-stopping-.patch
+ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch
+sctp-clear-control-chunk-transport-if-it-is-being-re.patch
+tls-don-t-abort-the-connection-on-signal-interrupted.patch
+hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch
--- /dev/null
+From b2b3a9f29049b94855df062394e9d7824c836153 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 14:17:38 +0800
+Subject: tcp: fix TFO max_qlen accounting across reuseport migration
+
+From: Jiayuan Chen <jiayuan.chen@linux.dev>
+
+[ Upstream commit a0ab2ba83e35159d81cec830a92e885ecf8139be ]
+
+A listener's TCP_FASTOPEN max_qlen stops being accurate and lets through
+far more pending Fast Open requests than it was configured for.
+
+This only shows up with SO_REUSEPORT listener migration, where closing a
+listener hands its still-pending TFO children over to a surviving one.
+
+fastopenq.qlen is charged in tcp_fastopen_create_child() when the child
+is created and uncharged in reqsk_fastopen_remove() when the handshake
+completes. The uncharge follows rsk_listener of the request the child
+points at, and inet_reqsk_clone() has repointed the child at a new
+request owned by the new listener, so the ++ and the -- land on two
+different sockets. The new listener's qlen drifts negative and its
+limit no longer binds.
+
+Charge the new listener during migration, like reqsk_queue_migrated()
+already does for queue->young and queue->qlen.
+
+Fixes: 54b92e841937 ("tcp: Migrate TCP_ESTABLISHED/TCP_SYN_RECV sockets in accept queues.")
+Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260803061739.134737-1-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/inet_connection_sock.c | 20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
+index d99fed07b024f..042982aaf9704 100644
+--- a/net/ipv4/inet_connection_sock.c
++++ b/net/ipv4/inet_connection_sock.c
+@@ -750,11 +750,23 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req,
+
+ nreq->rsk_listener = sk;
+
+- /* We need not acquire fastopenq->lock
+- * because the child socket is locked in inet_csk_listen_stop().
+- */
+- if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener)
++ if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener) {
++ struct fastopen_queue *fastopenq;
++
++ /* reqsk_fastopen_remove() will uncharge nreq->rsk_listener,
++ * that is @sk, so charge it here. Unlike the listener
++ * being closed, @sk is live and needs its lock.
++ */
++ fastopenq = &inet_csk(sk)->icsk_accept_queue.fastopenq;
++ spin_lock_bh(&fastopenq->lock);
++ fastopenq->qlen++;
++ spin_unlock_bh(&fastopenq->lock);
++
++ /* We need not acquire fastopenq->lock
++ * because the child socket is locked in inet_csk_listen_stop().
++ */
+ rcu_assign_pointer(tcp_sk(nreq->sk)->fastopen_rsk, nreq);
++ }
+
+ return nreq;
+ }
+--
+2.53.0
+
--- /dev/null
+From 5cec22ef9eab45369103a8c7a53aff760bd5abcf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 08:22:48 +0200
+Subject: tls: don't abort the connection on signal-interrupted sends
+
+From: Maximilian Immanuel Brandtner <maxbr@linux.ibm.com>
+
+[ Upstream commit af0e5cdd031f4f4a8f6d4160bfbda4f36872b0ed ]
+
+When a signal interrupts a blocking send, tls_tx_records() treats the
+resulting -ERESTARTSYS as a transmission failure and marks the socket
+errored via tls_err_abort() with the raw error code. Later syscalls
+return the kernel-internal errno 512 (ERESTARTSYS) to userspace, as the
+signal it stems from is no longer pending during syscall exit and thus
+never translated.
+
+An interrupted send is not a connection error: the partially sent record
+stays queued and is resent later. Interrupt error codes are therefore
+excluded from the abort in the same way as -EAGAIN.
+
+Fixes: b341ca51d267 ("tls: Fix tls_sw_sendmsg error handling")
+Signed-off-by: Maximilian Immanuel Brandtner <maxbr@linux.ibm.com>
+Link: https://patch.msgid.link/20260805063109.1772314-1-maxbr@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tls/tls_sw.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
+index 0cdc9131aff22..012ff6a496697 100644
+--- a/net/tls/tls_sw.c
++++ b/net/tls/tls_sw.c
+@@ -455,7 +455,7 @@ int tls_tx_records(struct sock *sk, int flags)
+ }
+
+ tx_err:
+- if (rc < 0 && rc != -EAGAIN)
++ if (rc < 0 && rc != -EAGAIN && rc != -EINTR && rc != -ERESTARTSYS)
+ tls_err_abort(sk, rc);
+
+ return rc;
+--
+2.53.0
+
--- /dev/null
+From 92a63ad90e252b5b91da77094278b14b572d2f0b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 17:35:54 +0800
+Subject: udp: fix potential use-after-free in tunnel segmentation
+
+From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+
+[ Upstream commit d0f86fb36eb260abd10007b62c9dcc1028e03e61 ]
+
+__skb_udp_tunnel_segment() gets the UDP header before ensuring the
+tunnel header is in the skb head. If the pull reallocates skb->head,
+the saved UDP header pointer is no longer valid.
+
+Get the UDP header after the pull to avoid a potential use-after-free.
+
+Fixes: dbef491ebe7f ("udp: Use uh->len instead of skb->len to compute checksum in segmentation")
+Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+Reviewed-by: Antoine Tenart <atenart@kernel.org>
+Link: https://patch.msgid.link/20260730093554.68127-1-xuanqiang.luo@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/udp_offload.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
+index 8f47d07c49fb7..e2c7d6d8986c3 100644
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -20,17 +20,19 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
+ int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
+ bool remcsum, need_csum, offload_csum, gso_partial;
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+- struct udphdr *uh = udp_hdr(skb);
+ u16 mac_offset = skb->mac_header;
+ __be16 protocol = skb->protocol;
+ u16 mac_len = skb->mac_len;
+ int udp_offset, outer_hlen;
++ struct udphdr *uh;
+ __wsum partial;
+ bool need_ipsec;
+
+ if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
+ goto out;
+
++ uh = udp_hdr(skb);
++
+ /* Adjust partial header checksum to negate old length.
+ * We cannot rely on the value contained in uh->len as it is
+ * possible that the actual value exceeds the boundaries of the
+--
+2.53.0
+
--- /dev/null
+From c4b54f0ea4f35790510c2a46681f91cabe973517 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Jun 2026 15:02:02 -0700
+Subject: vhost/vdpa: reject overflowing PA map page counts on 32-bit
+
+From: Yousef Alhouseen <alhouseenyousef@gmail.com>
+
+[ Upstream commit 0619aaa34c0c2a2dcb07f0e9c8a34e7efb8c4cdf ]
+
+vhost_vdpa_pa_map() adds the IOVA page offset to the user-controlled map
+size before computing the number of pages to pin. On 32-bit systems,
+where unsigned long is narrower than u64, that addition can overflow and
+the code can pin and map fewer pages than the requested IOTLB range.
+
+Reject sizes that overflow the unsigned long page-count calculation.
+
+Fixes: 22af48cf91aa ("vdpa: factor out vhost_vdpa_pa_map() and vhost_vdpa_pa_unmap()")
+Acked-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Message-ID: <CAMuQ4bX-iDvcUOPPY+NLz95tkRJYwWqvzAr=U48uNaub_HZLGw@mail.gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vhost/vdpa.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
+index 17907e61f8e0c..080413757eea3 100644
+--- a/drivers/vhost/vdpa.c
++++ b/drivers/vhost/vdpa.c
+@@ -717,6 +717,7 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
+ unsigned int gup_flags = FOLL_LONGTERM;
+ unsigned long npages, cur_base, map_pfn, last_pfn = 0;
+ unsigned long lock_limit, sz2pin, nchunks, i;
++ unsigned long page_offset;
+ u64 start = iova;
+ long pinned;
+ int ret = 0;
+@@ -729,7 +730,13 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
+ if (perm & VHOST_ACCESS_WO)
+ gup_flags |= FOLL_WRITE;
+
+- npages = PFN_UP(size + (iova & ~PAGE_MASK));
++ page_offset = iova & ~PAGE_MASK;
++ if (size > ULONG_MAX - page_offset) {
++ ret = -EINVAL;
++ goto free;
++ }
++
++ npages = PFN_UP(size + page_offset);
+ if (!npages) {
+ ret = -EINVAL;
+ goto free;
+--
+2.53.0
+
--- /dev/null
+From f0f491009a617fcc8cb2b81635d364c2e49d9a42 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 24 May 2026 23:38:46 -0400
+Subject: ARM: npcm: Fix OF node refcount leaks in SMP setup
+
+From: Yuho Choi <dbgh9129@gmail.com>
+
+[ Upstream commit 8eb052f48331474c2789d07b7f11165c323bd2f9 ]
+
+npcm7xx_smp_boot_secondary() and npcm7xx_smp_prepare_cpus() look up
+the GCR and SCU nodes with of_find_compatible_node(). The returned
+nodes are used for of_iomap(), but the node references are never
+released.
+
+of_iomap() does not consume the device node reference, and iounmap()
+only releases the MMIO mapping. Drop each node reference after the
+corresponding mapping attempt.
+
+Fixes: 7bffa14c9aed ("arm: npcm: add basic support for Nuvoton BMCs")
+Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
+Reviewed-by: Avi Fishman <avifishman70@gmail.com>
+Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/mach-npcm/platsmp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arm/mach-npcm/platsmp.c b/arch/arm/mach-npcm/platsmp.c
+index 21633c70fe7fe..fe63edc9886df 100644
+--- a/arch/arm/mach-npcm/platsmp.c
++++ b/arch/arm/mach-npcm/platsmp.c
+@@ -35,6 +35,7 @@ static int npcm7xx_smp_boot_secondary(unsigned int cpu,
+ goto out;
+ }
+ gcr_base = of_iomap(gcr_np, 0);
++ of_node_put(gcr_np);
+ if (!gcr_base) {
+ pr_err("could not iomap gcr");
+ ret = -ENOMEM;
+@@ -63,6 +64,7 @@ static void __init npcm7xx_smp_prepare_cpus(unsigned int max_cpus)
+ return;
+ }
+ scu_base = of_iomap(scu_np, 0);
++ of_node_put(scu_np);
+ if (!scu_base) {
+ pr_err("could not iomap scu");
+ return;
+--
+2.53.0
+
--- /dev/null
+From 44f559ea20bcc124135c8986e70c04eaf5fb6b81 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 14:06:28 +0800
+Subject: ata: pata_sl82c105: fix bridge revision use-after-free
+
+From: Hongyan Xu <getshell@seu.edu.cn>
+
+[ Upstream commit 7700a31039cdc6715cb6cce7e7a664ee4e945f67 ]
+
+pci_get_slot() returns a referenced PCI device. Commit 44c10138fd4b
+("PCI: Change all drivers to use pci_device->revision") replaced a
+configuration-space read with direct access to the cached revision field,
+but left that access after pci_dev_put(). The bridge may therefore be freed
+before its revision is read.
+
+Read the revision before dropping the reference.
+
+Fixes: 44c10138fd4b ("PCI: Change all drivers to use pci_device->revision")
+Signed-off-by: Hongyan Xu <getshell@seu.edu.cn>
+Reviewed-by: Niklas Cassel <cassel@kernel.org>
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ata/pata_sl82c105.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
+index 8487470e2e01e..c32f3b490bb35 100644
+--- a/drivers/ata/pata_sl82c105.c
++++ b/drivers/ata/pata_sl82c105.c
+@@ -265,6 +265,7 @@ static struct ata_port_operations sl82c105_port_ops = {
+ static int sl82c105_bridge_revision(struct pci_dev *pdev)
+ {
+ struct pci_dev *bridge;
++ u8 revision;
+
+ /*
+ * The bridge should be part of the same device, but function 0.
+@@ -286,8 +287,9 @@ static int sl82c105_bridge_revision(struct pci_dev *pdev)
+ /*
+ * We need to find function 0's revision, not function 1
+ */
++ revision = bridge->revision;
+ pci_dev_put(bridge);
+- return bridge->revision;
++ return revision;
+ }
+
+ static void sl82c105_fixup(struct pci_dev *pdev)
+--
+2.53.0
+
--- /dev/null
+From 02148f889fe85a08046145deeacff8581e5e3181 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:36 -0700
+Subject: bnxt_en: Disable EOP for TPA on all chips to prevent data corruption
+
+From: Michael Chan <michael.chan@broadcom.com>
+
+[ Upstream commit c3faf548a00f4c17100cc9204746975fa46a73b9 ]
+
+EOP (End of frame padding) on the AGG ring may cause overlapping of
+zero padding at the end of one segment with the next segment's data.
+If Relaxed Ordering (RO) is enabled, the zero padding may overwrite
+valid data in the next segment and corrupt the data. Older chips
+(P5 and older) do not automatically disable RO when EOP is enabled.
+On some ARM systems, data corruption was reported on 57508 (P5)
+chips with RO enabled.
+
+Always disable EOP on all chips on the AGG rings when TPA is enabled
+to fix the data corruption.
+
+Fixes: bfcd8d791ec1 ("bnxt_en: Add fast path logic for TPA on 57500 chips.")
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-5-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index f11ca14c5c4d3..f69ad1ffc0c9d 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -3766,11 +3766,14 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr)
+ type = ((u32)BNXT_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
+ RX_BD_TYPE_RX_AGG_BD;
+
+- /* On P7, setting EOP will cause the chip to disable
+- * Relaxed Ordering (RO) for TPA data. Disable EOP for
+- * potentially higher performance with RO.
++ /* Disable EOP if TPA is enabled to prevent overlapping zero
++ * padding with the next segment's data. On P7_PLUS, EOP will
++ * automatically disable Relaxed Ordering (RO) to prevent
++ * potential data corruption (and may degrade performance). On
++ * older chips, RO will not be automatically disabled and may
++ * cause corruption.
+ */
+- if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
++ if (!(bp->flags & BNXT_FLAG_TPA))
+ type |= RX_BD_FLAGS_AGG_EOP;
+
+ bnxt_init_rxbd_pages(ring, type);
+--
+2.53.0
+
--- /dev/null
+From 8c84e7921b8869be09f190d24338d604cdecfef9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Nov 2025 13:56:46 -0800
+Subject: bnxt_en: Do not set EOP on RX AGG BDs on 5760X chips
+
+From: Michael Chan <michael.chan@broadcom.com>
+
+[ Upstream commit 30f253f8d9a01d532fdb7ec6c8a9d4c15fe29241 ]
+
+With End-of-Packet padding (EOP) set, the chip will disable Relaxed
+Ordering (RO) of TPA data packets. A TPA segment with EOP set will be
+padded to the next cache boundary and can potentially overwrite the
+beginning bytes of the next TPA segment when RO is enabled on 5760X.
+To prevent that, the chip disables RO for TPA when EOP is set.
+
+To take advantge of RO and higher performance, do not set EOP on
+5760X chips when TPA is enabled. Define a proper RX_BD_FLAGS_AGG_EOP
+constant to make it clear that we are setting EOP.
+
+Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
+Reviewed-by: Somnath Kotur <somnath.kotur@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20251126215648.1885936-6-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: c3faf548a00f ("bnxt_en: Disable EOP for TPA on all chips to prevent data corruption")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 ++++++++-
+ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
+ 2 files changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index e9cc604834c51..f11ca14c5c4d3 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -3764,7 +3764,14 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr)
+
+ if ((bp->flags & BNXT_FLAG_AGG_RINGS)) {
+ type = ((u32)BNXT_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
+- RX_BD_TYPE_RX_AGG_BD | RX_BD_FLAGS_SOP;
++ RX_BD_TYPE_RX_AGG_BD;
++
++ /* On P7, setting EOP will cause the chip to disable
++ * Relaxed Ordering (RO) for TPA data. Disable EOP for
++ * potentially higher performance with RO.
++ */
++ if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
++ type |= RX_BD_FLAGS_AGG_EOP;
+
+ bnxt_init_rxbd_pages(ring, type);
+ }
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+index 2c12a5b34b11f..006987d3caa1a 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+@@ -103,6 +103,7 @@ struct rx_bd {
+ #define RX_BD_TYPE_48B_BD_SIZE (2 << 4)
+ #define RX_BD_TYPE_64B_BD_SIZE (3 << 4)
+ #define RX_BD_FLAGS_SOP (1 << 6)
++ #define RX_BD_FLAGS_AGG_EOP (1 << 6)
+ #define RX_BD_FLAGS_EOP (1 << 7)
+ #define RX_BD_FLAGS_BUFFERS (3 << 8)
+ #define RX_BD_FLAGS_1_BUFFER_PACKET (0 << 8)
+--
+2.53.0
+
--- /dev/null
+From 45f6016d5b4edd8cb0df04a4ea3fdfc112b25860 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:37 -0700
+Subject: bnxt_en: Fix PTP PPS setting bug
+
+From: Keegan Freyhof <keegan.freyhof@broadcom.com>
+
+[ Upstream commit 80eaf88efec33ac77ed7726d066c4f2f932cc329 ]
+
+The existing driver logic is always turning on PTP_CLK_REQ_PPS
+regardless of the "on" parameter passed to bnxt_ptp_enable().
+During shutdown, PTP_CLK_REQ_PPS may be turned off and this
+bug will do the opposite and may trigger a PCIe PTM request TLP.
+On some systems this can trigger a PCIe AER.
+
+Fix it by properly configuring PTP_CLK_REQ_PPS based on the "on"
+parameter.
+
+Fixes: 9e518f25802c ("bnxt_en: 1PPS functions to configure TSIO pins")
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Keegan Freyhof <keegan.freyhof@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-6-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
+index 1c888d6c3aee8..850e4c44044ac 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
+@@ -460,12 +460,15 @@ static int bnxt_ptp_enable(struct ptp_clock_info *ptp_info,
+ return rc;
+ case PTP_CLK_REQ_PPS:
+ /* Configure PHC PPS IN */
+- rc = bnxt_ptp_cfg_pin(bp, 0, BNXT_PPS_PIN_PPS_IN);
++ pin_id = 0;
++ if (!on)
++ break;
++ rc = bnxt_ptp_cfg_pin(bp, pin_id, BNXT_PPS_PIN_PPS_IN);
+ if (rc)
+ return rc;
+ rc = bnxt_ptp_cfg_event(bp, BNXT_PPS_EVENT_INTERNAL);
+ if (!rc)
+- ptp->pps_info.pins[0].event = BNXT_PPS_EVENT_INTERNAL;
++ ptp->pps_info.pins[pin_id].event = BNXT_PPS_EVENT_INTERNAL;
+ return rc;
+ default:
+ netdev_err(ptp->bp->dev, "Unrecognized PIN function\n");
+--
+2.53.0
+
--- /dev/null
+From 67849cf8c52004548aaddff6ea7fa23cc2cb7889 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 25 Jul 2026 23:39:30 +0000
+Subject: bonding: alb: re-check primary_is_promisc under RTNL in
+ bond_alb_monitor
+
+From: Xiang Mei (Microsoft) <xmei5@asu.edu>
+
+[ Upstream commit 683c6ba6e58e6ed1037831ea97dd58d9c0e76b8d ]
+
+bond_alb_monitor() reads primary_is_promisc under RCU, then drops RCU and
+takes RTNL via rtnl_trylock() before undoing the promiscuity it set on the
+active slave. In that window the active slave can change under RTNL
+(RTM_DELLINK -> __bond_release_one() -> bond_alb_handle_active_change()),
+which already drops the promiscuity and clears primary_is_promisc. The
+monitor still acts on the stale decision: if the slave was removed with no
+failover, curr_active_slave is now NULL and the deref faults; if it failed
+over, the stale dev_set_promiscuity(-1) underflows the new slave's
+promiscuity counter and pins it in IFF_PROMISC.
+
+ Oops: general protection fault, probably for non-canonical address ...
+ KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
+ Workqueue: b42 bond_alb_monitor
+ RIP: 0010:bond_alb_monitor (drivers/net/bonding/bond_alb.c:1600)
+ process_one_work (kernel/workqueue.c:3322)
+ worker_thread (kernel/workqueue.c:3486)
+ kthread (kernel/kthread.c:436)
+ ret_from_fork (arch/x86/kernel/process.c:158)
+ Kernel panic - not syncing: Fatal exception
+
+Re-check primary_is_promisc (and curr_active_slave) after taking RTNL so
+the monitor only undoes an increment it still owns. The other bonding
+monitors already re-read state under RTNL in their commit phase
+(bond_miimon_commit/bond_ab_arp_commit); bond_alb_monitor() was the only
+one acting on the pre-trylock decision.
+
+Fixes: d0e81b7e2246 ("bonding: Acquire correct locks in alb for promisc change")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
+Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
+Acked-by: Jay Vosburgh <jv@jvosburgh.net>
+Link: https://patch.msgid.link/20260725233930.2957317-1-xmei5@asu.edu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/bonding/bond_alb.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
+index 9c4c2c7d90ef5..c44a9358f8b27 100644
+--- a/drivers/net/bonding/bond_alb.c
++++ b/drivers/net/bonding/bond_alb.c
+@@ -1535,8 +1535,8 @@ void bond_alb_monitor(struct work_struct *work)
+ struct bonding *bond = container_of(work, struct bonding,
+ alb_work.work);
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
++ struct slave *slave, *curr;
+ struct list_head *iter;
+- struct slave *slave;
+
+ if (!bond_has_slaves(bond)) {
+ atomic_set(&bond_info->tx_rebalance_counter, 0);
+@@ -1598,9 +1598,11 @@ void bond_alb_monitor(struct work_struct *work)
+ * because a slave was disabled then
+ * it can now leave promiscuous mode.
+ */
+- dev_set_promiscuity(rtnl_dereference(bond->curr_active_slave)->dev,
+- -1);
+- bond_info->primary_is_promisc = 0;
++ curr = rtnl_dereference(bond->curr_active_slave);
++ if (bond_info->primary_is_promisc && curr) {
++ dev_set_promiscuity(curr->dev, -1);
++ bond_info->primary_is_promisc = 0;
++ }
+
+ rtnl_unlock();
+ rcu_read_lock();
+--
+2.53.0
+
--- /dev/null
+From 5906b8f9ad2b939d61abb276d5cb1eea1683ac50 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:18:28 +0000
+Subject: bpf: Preserve pointer state for commuted arithmetic
+
+From: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+
+[ Upstream commit a4c6f804b44c5c790269b25e0e61cf4e9f117c86 ]
+
+When scalar += pointer is handled in adjust_ptr_min_max_vals(), the
+destination register inherits the pointer state from the source pointer.
+Copying only selected fields is fragile because pointer provenance is
+tracked by several bpf_reg_state fields.
+
+Use the caller's temporary offset register to preserve the scalar operand
+while replacing the destination with the full pointer state. This preserves
+the frame number for PTR_TO_STACK registers and keeps parent identity
+fields consistent.
+
+Fixes: f4d7e40a5b71 ("bpf: introduce function calls (verification)")
+Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+Tested-by: Daniel Wade <danjwade95@gmail.com>
+Acked-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-2-8ee297e2346b@mails.tsinghua.edu.cn
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 4ff1d5007a23e..abb62b3e4f873 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -8491,11 +8491,12 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ break;
+ }
+
+- /* In case of 'scalar += pointer', dst_reg inherits pointer type and id.
+- * The id may be overwritten later if we create a new variable offset.
++ /* For 'scalar += pointer', dst_reg inherits the complete pointer
++ * register state. Individual fields may be adjusted later by pointer
++ * arithmetic. Callers guarantee that below does not overwrite off_reg.
+ */
+- dst_reg->type = ptr_reg->type;
+- dst_reg->id = ptr_reg->id;
++ if (dst_reg != ptr_reg)
++ *dst_reg = *ptr_reg;
+
+ if (!check_reg_sane_offset(env, off_reg, ptr_reg->type) ||
+ !check_reg_sane_offset(env, ptr_reg, ptr_reg->type))
+@@ -8563,7 +8564,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ }
+ break;
+ case BPF_SUB:
+- if (dst_reg == off_reg) {
++ if (dst_reg != ptr_reg) {
+ /* scalar -= pointer. Creates an unknown scalar */
+ verbose(env, "R%d tried to subtract pointer from scalar\n",
+ dst);
+@@ -9422,8 +9423,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
+ err = mark_chain_precision(env, insn->dst_reg);
+ if (err)
+ return err;
+- return adjust_ptr_min_max_vals(env, insn,
+- src_reg, dst_reg);
++ off_reg = *dst_reg;
++ return adjust_ptr_min_max_vals(env, insn, src_reg, &off_reg);
+ }
+ } else if (ptr_reg) {
+ /* pointer += scalar */
+--
+2.53.0
+
--- /dev/null
+From b816ecb15c6f02a446cc5cdecf61032140721a8e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Jul 2025 11:09:09 -0700
+Subject: bpf: tcp: Avoid socket skips and repeats during iteration
+
+From: Jordan Rife <jordan@jrife.io>
+
+[ Upstream commit f5080f612a1c587bf636bb23d2a2f4de276d60e4 ]
+
+Replace the offset-based approach for tracking progress through a bucket
+in the TCP table with one based on socket cookies. Remember the cookies
+of unprocessed sockets from the last batch and use this list to
+pick up where we left off or, in the case that the next socket
+disappears between reads, find the first socket after that point that
+still exists in the bucket and resume from there.
+
+This approach guarantees that all sockets that existed when iteration
+began and continue to exist throughout will be visited exactly once.
+Sockets that are added to the table during iteration may or may not be
+seen, but if they are they will be seen exactly once.
+
+Signed-off-by: Jordan Rife <jordan@jrife.io>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 147 ++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 115 insertions(+), 32 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index 9843e05343565..8fcf9c990318b 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -58,6 +58,7 @@
+ #include <linux/times.h>
+ #include <linux/slab.h>
+ #include <linux/sched.h>
++#include <linux/sock_diag.h>
+
+ #include <net/net_namespace.h>
+ #include <net/icmp.h>
+@@ -2727,6 +2728,7 @@ static int tcp4_seq_show(struct seq_file *seq, void *v)
+ #ifdef CONFIG_BPF_SYSCALL
+ union bpf_tcp_iter_batch_item {
+ struct sock *sk;
++ __u64 cookie;
+ };
+
+ struct bpf_tcp_iter_state {
+@@ -2757,10 +2759,19 @@ static int tcp_prog_seq_show(struct bpf_prog *prog, struct bpf_iter_meta *meta,
+
+ static void bpf_iter_tcp_put_batch(struct bpf_tcp_iter_state *iter)
+ {
++ union bpf_tcp_iter_batch_item *item;
+ unsigned int cur_sk = iter->cur_sk;
++ __u64 cookie;
+
+- while (cur_sk < iter->end_sk)
+- sock_gen_put(iter->batch[cur_sk++].sk);
++ /* Remember the cookies of the sockets we haven't seen yet, so we can
++ * pick up where we left off next time around.
++ */
++ while (cur_sk < iter->end_sk) {
++ item = &iter->batch[cur_sk++];
++ cookie = sock_gen_cookie(item->sk);
++ sock_gen_put(item->sk);
++ item->cookie = cookie;
++ }
+ }
+
+ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+@@ -2781,6 +2792,106 @@ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+ return 0;
+ }
+
++static struct sock *bpf_iter_tcp_resume_bucket(struct sock *first_sk,
++ union bpf_tcp_iter_batch_item *cookies,
++ int n_cookies)
++{
++ struct hlist_nulls_node *node;
++ struct sock *sk;
++ int i;
++
++ for (i = 0; i < n_cookies; i++) {
++ sk = first_sk;
++ sk_nulls_for_each_from(sk, node)
++ if (cookies[i].cookie == atomic64_read(&sk->sk_cookie))
++ return sk;
++ }
++
++ return NULL;
++}
++
++static struct sock *bpf_iter_tcp_resume_listening(struct seq_file *seq)
++{
++ struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
++ struct bpf_tcp_iter_state *iter = seq->private;
++ struct tcp_iter_state *st = &iter->state;
++ unsigned int find_cookie = iter->cur_sk;
++ unsigned int end_cookie = iter->end_sk;
++ int resume_bucket = st->bucket;
++ struct sock *sk;
++
++ if (end_cookie && find_cookie == end_cookie)
++ ++st->bucket;
++
++ sk = listening_get_first(seq);
++ iter->cur_sk = 0;
++ iter->end_sk = 0;
++
++ if (sk && st->bucket == resume_bucket && end_cookie) {
++ sk = bpf_iter_tcp_resume_bucket(sk, &iter->batch[find_cookie],
++ end_cookie - find_cookie);
++ if (!sk) {
++ spin_unlock(&hinfo->lhash2[st->bucket].lock);
++ ++st->bucket;
++ sk = listening_get_first(seq);
++ }
++ }
++
++ return sk;
++}
++
++static struct sock *bpf_iter_tcp_resume_established(struct seq_file *seq)
++{
++ struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
++ struct bpf_tcp_iter_state *iter = seq->private;
++ struct tcp_iter_state *st = &iter->state;
++ unsigned int find_cookie = iter->cur_sk;
++ unsigned int end_cookie = iter->end_sk;
++ int resume_bucket = st->bucket;
++ struct sock *sk;
++
++ if (end_cookie && find_cookie == end_cookie)
++ ++st->bucket;
++
++ sk = established_get_first(seq);
++ iter->cur_sk = 0;
++ iter->end_sk = 0;
++
++ if (sk && st->bucket == resume_bucket && end_cookie) {
++ sk = bpf_iter_tcp_resume_bucket(sk, &iter->batch[find_cookie],
++ end_cookie - find_cookie);
++ if (!sk) {
++ spin_unlock_bh(inet_ehash_lockp(hinfo, st->bucket));
++ ++st->bucket;
++ sk = established_get_first(seq);
++ }
++ }
++
++ return sk;
++}
++
++static struct sock *bpf_iter_tcp_resume(struct seq_file *seq)
++{
++ struct bpf_tcp_iter_state *iter = seq->private;
++ struct tcp_iter_state *st = &iter->state;
++ struct sock *sk = NULL;
++
++ switch (st->state) {
++ case TCP_SEQ_STATE_LISTENING:
++ sk = bpf_iter_tcp_resume_listening(seq);
++ if (sk)
++ break;
++ st->bucket = 0;
++ st->state = TCP_SEQ_STATE_ESTABLISHED;
++ fallthrough;
++ case TCP_SEQ_STATE_ESTABLISHED:
++ sk = bpf_iter_tcp_resume_established(seq);
++ break;
++ }
++
++ return sk;
++}
++
+ static unsigned int bpf_iter_tcp_listening_batch(struct seq_file *seq,
+ struct sock **start_sk)
+ {
+@@ -2865,32 +2976,12 @@ static void bpf_iter_tcp_unlock_bucket(struct seq_file *seq)
+
+ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ {
+- struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
+ struct bpf_tcp_iter_state *iter = seq->private;
+- struct tcp_iter_state *st = &iter->state;
+ unsigned int expected;
+ struct sock *sk;
+ int err;
+
+- /* The st->bucket is done. Directly advance to the next
+- * bucket instead of having the tcp_seek_last_pos() to skip
+- * one by one in the current bucket and eventually find out
+- * it has to advance to the next bucket.
+- */
+- if (iter->end_sk && iter->cur_sk == iter->end_sk) {
+- st->offset = 0;
+- st->bucket++;
+- if (st->state == TCP_SEQ_STATE_LISTENING &&
+- st->bucket > hinfo->lhash2_mask) {
+- st->state = TCP_SEQ_STATE_ESTABLISHED;
+- st->bucket = 0;
+- }
+- }
+-
+- iter->cur_sk = 0;
+- iter->end_sk = 0;
+-
+- sk = tcp_seek_last_pos(seq);
++ sk = bpf_iter_tcp_resume(seq);
+ if (!sk)
+ return NULL; /* Done */
+
+@@ -2906,10 +2997,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ if (err)
+ return ERR_PTR(err);
+
+- iter->cur_sk = 0;
+- iter->end_sk = 0;
+-
+- sk = tcp_seek_last_pos(seq);
++ sk = bpf_iter_tcp_resume(seq);
+ if (!sk)
+ return NULL; /* Done */
+
+@@ -2961,11 +3049,6 @@ static void *bpf_iter_tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+ * meta.seq_num is used instead.
+ */
+ st->num++;
+- /* Move st->offset to the next sk in the bucket such that
+- * the future start() will resume at st->offset in
+- * st->bucket. See tcp_seek_last_pos().
+- */
+- st->offset++;
+ sock_gen_put(iter->batch[iter->cur_sk++].sk);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From f00b8e518ee706106c203941d9b6a2c5c7aefe7d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 22:32:47 +0000
+Subject: bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()
+
+From: Jose Fernandez (Anthropic) <jose.fernandez@linux.dev>
+
+[ Upstream commit e5fd3f514e27db1f05fbd72ba615d74941e23c51 ]
+
+reqsk_queue_hash_req() publishes a TCP_NEW_SYN_RECV request_sock onto
+the ehash chain, drops the bucket lock, and only afterwards sets
+rsk_refcnt to 3.
+
+Lockless readers such as __inet_lookup_established() handle this with
+refcount_inc_not_zero(), but bpf_iter_tcp_established_batch() uses plain
+sock_hold() while holding the bucket lock, on the assumption that the
+lock guarantees sk_refcnt > 0. That assumption does not hold for
+request_sock:
+
+ CPU 0 CPU 1
+ ----- -----
+ tcp_conn_request()
+ reqsk_queue_hash_req()
+ inet_ehash_insert(req)
+ spin_lock(bucket)
+ __sk_nulls_add_node_rcu(req) // rsk_refcnt == 0
+ spin_unlock(bucket)
+ bpf_iter_tcp_established_batch()
+ spin_lock(bucket)
+ sock_hold(req) <-- addition on 0
+ spin_unlock(bucket)
+ refcount_set(&req->rsk_refcnt, 3) // clobbers saturated value
+
+which surfaces as:
+
+ refcount_t: addition on 0; use-after-free.
+ WARNING: lib/refcount.c:25 at refcount_warn_saturate+0x48/0x90, CPU#1
+ Call Trace:
+ bpf_iter_tcp_established_batch+0x14e/0x170
+ bpf_iter_tcp_batch+0x53/0x200
+ bpf_iter_tcp_seq_next+0x27/0x70
+ bpf_seq_read+0x107/0x410
+ vfs_read+0xb9/0x380
+
+The iterator's stolen reference is lost when the publishing CPU's
+refcount_set() overwrites the count, leaving the socket one reference
+short. When the last legitimate owner drops its reference the reqsk is
+freed while still reachable, leading to use-after-free.
+
+This reproduces in seconds with tcp_syncookies=0, a handful of threads
+doing connect()/close() to a local listener while others read an
+iter/tcp link in a tight loop.
+
+Use refcount_inc_not_zero() and skip the socket on failure. A skipped
+socket is still part of the bucket, so keep counting it in expected.
+The reallocations are sized from expected, and a request sock whose
+refcount gets published while the lock is held across the last realloc
+must already have room.
+
+A skipped socket is counted in expected but never batched, so end_sk
+can be short of expected on a batch that is actually complete. Decide
+completeness by whether the walk left any socket behind instead. The
+WARN after the locked realloc checks the same, replacing an
+end_sk == expected check that could not hold on that path since
+commit cdec67a489d4 ("bpf: tcp: Make sure iter->batch always
+contains a full bucket snapshot").
+
+If every matching socket in a bucket is mid-init (refcount 0), end_sk
+stays 0. Advance to the next bucket rather than returning a batch entry
+that was never filled this round.
+
+Fixes: 04c7820b776f ("bpf: tcp: Bpf iter batching and lock_sock")
+Assisted-by: Claude:unspecified
+Signed-off-by: Jose Fernandez (Anthropic) <jose.fernandez@linux.dev>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Link: https://lore.kernel.org/bpf/20260730-bpf-iter-tcp-refcnt-v3-1-754b9c8a6717@linux.dev
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 43 ++++++++++++++++++++++++-------------------
+ 1 file changed, 24 insertions(+), 19 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index 8fcf9c990318b..25673067a5cda 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -2926,24 +2926,24 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,
+ {
+ struct bpf_tcp_iter_state *iter = seq->private;
+ struct hlist_nulls_node *node;
+- unsigned int expected = 1;
+- struct sock *sk;
+-
+- sock_hold(*start_sk);
+- iter->batch[iter->end_sk++].sk = *start_sk;
++ struct sock *sk = *start_sk;
++ unsigned int expected = 0;
+
+- sk = sk_nulls_next(*start_sk);
+ *start_sk = NULL;
+ sk_nulls_for_each_from(sk, node) {
+- if (seq_sk_match(seq, sk)) {
+- if (iter->end_sk < iter->max_sk) {
+- sock_hold(sk);
+- iter->batch[iter->end_sk++].sk = sk;
+- } else if (!*start_sk) {
+- /* Remember where we left off. */
+- *start_sk = sk;
+- }
+- expected++;
++ if (!seq_sk_match(seq, sk))
++ continue;
++ expected++;
++ if (iter->end_sk < iter->max_sk) {
++ /* reqsk_queue_hash_req() inserts with sk_refcnt == 0
++ * and refcount_set()s it after the bucket lock drops.
++ */
++ if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
++ continue;
++ iter->batch[iter->end_sk++].sk = sk;
++ } else if (!*start_sk) {
++ /* Remember where we left off. */
++ *start_sk = sk;
+ }
+ }
+
+@@ -2981,12 +2981,13 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ struct sock *sk;
+ int err;
+
++again:
+ sk = bpf_iter_tcp_resume(seq);
+ if (!sk)
+ return NULL; /* Done */
+
+ expected = bpf_iter_fill_batch(seq, &sk);
+- if (likely(iter->end_sk == expected))
++ if (likely(!sk))
+ goto done;
+
+ /* Batch size was too small. */
+@@ -3002,7 +3003,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ return NULL; /* Done */
+
+ expected = bpf_iter_fill_batch(seq, &sk);
+- if (likely(iter->end_sk == expected))
++ if (likely(!sk))
+ goto done;
+
+ /* Batch size was still too small. Hold onto the lock while we try
+@@ -3015,10 +3016,14 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ return ERR_PTR(err);
+ }
+
+- expected = bpf_iter_fill_batch(seq, &sk);
+- WARN_ON_ONCE(iter->end_sk != expected);
++ bpf_iter_fill_batch(seq, &sk);
++ WARN_ON_ONCE(sk);
+ done:
+ bpf_iter_tcp_unlock_bucket(seq);
++ if (unlikely(!iter->end_sk)) {
++ ++iter->state.bucket;
++ goto again;
++ }
+ return iter->batch[0].sk;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 152c092fa6ea7f2459644d30af6d57ac6f6e301f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Jul 2025 11:09:07 -0700
+Subject: bpf: tcp: Get rid of st_bucket_done
+
+From: Jordan Rife <jordan@jrife.io>
+
+[ Upstream commit e25ab9b874a4bd8c6e3e5ce66cbe8a1dd4096e2e ]
+
+Get rid of the st_bucket_done field to simplify TCP iterator state and
+logic. Before, st_bucket_done could be false if bpf_iter_tcp_batch
+returned a partial batch; however, with the last patch ("bpf: tcp: Make
+sure iter->batch always contains a full bucket snapshot"),
+st_bucket_done == true is equivalent to iter->cur_sk == iter->end_sk.
+
+Signed-off-by: Jordan Rife <jordan@jrife.io>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 14 ++++++--------
+ 1 file changed, 6 insertions(+), 8 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index 70c15160d2491..fb975e8f55ae5 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -2731,7 +2731,6 @@ struct bpf_tcp_iter_state {
+ unsigned int end_sk;
+ unsigned int max_sk;
+ struct sock **batch;
+- bool st_bucket_done;
+ };
+
+ struct bpf_iter__tcp {
+@@ -2754,8 +2753,10 @@ static int tcp_prog_seq_show(struct bpf_prog *prog, struct bpf_iter_meta *meta,
+
+ static void bpf_iter_tcp_put_batch(struct bpf_tcp_iter_state *iter)
+ {
+- while (iter->cur_sk < iter->end_sk)
+- sock_gen_put(iter->batch[iter->cur_sk++]);
++ unsigned int cur_sk = iter->cur_sk;
++
++ while (cur_sk < iter->end_sk)
++ sock_gen_put(iter->batch[cur_sk++]);
+ }
+
+ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+@@ -2872,7 +2873,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ * one by one in the current bucket and eventually find out
+ * it has to advance to the next bucket.
+ */
+- if (iter->st_bucket_done) {
++ if (iter->end_sk && iter->cur_sk == iter->end_sk) {
+ st->offset = 0;
+ st->bucket++;
+ if (st->state == TCP_SEQ_STATE_LISTENING &&
+@@ -2884,7 +2885,6 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+
+ iter->cur_sk = 0;
+ iter->end_sk = 0;
+- iter->st_bucket_done = true;
+
+ sk = tcp_seek_last_pos(seq);
+ if (!sk)
+@@ -3032,10 +3032,8 @@ static void bpf_iter_tcp_seq_stop(struct seq_file *seq, void *v)
+ (void)tcp_prog_seq_show(prog, &meta, v, 0);
+ }
+
+- if (iter->cur_sk < iter->end_sk) {
++ if (iter->cur_sk < iter->end_sk)
+ bpf_iter_tcp_put_batch(iter);
+- iter->st_bucket_done = false;
+- }
+ }
+
+ static const struct seq_operations bpf_iter_tcp_seq_ops = {
+--
+2.53.0
+
--- /dev/null
+From e55f46d6888c865fcfb440c07388157d9cc9f00e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Jul 2025 11:09:05 -0700
+Subject: bpf: tcp: Make mem flags configurable through
+ bpf_iter_tcp_realloc_batch
+
+From: Jordan Rife <jordan@jrife.io>
+
+[ Upstream commit 8271bec9fc1cfe522b1a18cacbefd6712a3d41c2 ]
+
+Prepare for the next patch which needs to be able to choose either
+GFP_USER or GFP_NOWAIT for calls to bpf_iter_tcp_realloc_batch.
+
+Signed-off-by: Jordan Rife <jordan@jrife.io>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index 89200b4314018..7823e55bc9e73 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -2759,12 +2759,12 @@ static void bpf_iter_tcp_put_batch(struct bpf_tcp_iter_state *iter)
+ }
+
+ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+- unsigned int new_batch_sz)
++ unsigned int new_batch_sz, gfp_t flags)
+ {
+ struct sock **new_batch;
+
+ new_batch = kvmalloc(sizeof(*new_batch) * new_batch_sz,
+- GFP_USER | __GFP_NOWARN);
++ flags | __GFP_NOWARN);
+ if (!new_batch)
+ return -ENOMEM;
+
+@@ -2876,7 +2876,8 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ return sk;
+ }
+
+- if (!resized && !bpf_iter_tcp_realloc_batch(iter, expected * 3 / 2)) {
++ if (!resized && !bpf_iter_tcp_realloc_batch(iter, expected * 3 / 2,
++ GFP_USER)) {
+ resized = true;
+ goto again;
+ }
+@@ -3293,7 +3294,7 @@ static int bpf_iter_init_tcp(void *priv_data, struct bpf_iter_aux_info *aux)
+ if (err)
+ return err;
+
+- err = bpf_iter_tcp_realloc_batch(iter, INIT_BATCH_SZ);
++ err = bpf_iter_tcp_realloc_batch(iter, INIT_BATCH_SZ, GFP_USER);
+ if (err) {
+ bpf_iter_fini_seq_net(priv_data);
+ return err;
+--
+2.53.0
+
--- /dev/null
+From ee0fda8353af9fbcbb1f0d0daf786b19806e088d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Jul 2025 11:09:06 -0700
+Subject: bpf: tcp: Make sure iter->batch always contains a full bucket
+ snapshot
+
+From: Jordan Rife <jordan@jrife.io>
+
+[ Upstream commit cdec67a489d4fdae3e83e04fca0419136a83c4c2 ]
+
+Require that iter->batch always contains a full bucket snapshot. This
+invariant is important to avoid skipping or repeating sockets during
+iteration when combined with the next few patches. Before, there were
+two cases where a call to bpf_iter_tcp_batch may only capture part of a
+bucket:
+
+1. When bpf_iter_tcp_realloc_batch() returns -ENOMEM.
+2. When more sockets are added to the bucket while calling
+ bpf_iter_tcp_realloc_batch(), making the updated batch size
+ insufficient.
+
+In cases where the batch size only covers part of a bucket, it is
+possible to forget which sockets were already visited, especially if we
+have to process a bucket in more than two batches. This forces us to
+choose between repeating or skipping sockets, so don't allow this:
+
+1. Stop iteration and propagate -ENOMEM up to userspace if reallocation
+ fails instead of continuing with a partial batch.
+2. Try bpf_iter_tcp_realloc_batch() with GFP_USER just as before, but if
+ we still aren't able to capture the full bucket, call
+ bpf_iter_tcp_realloc_batch() again while holding the bucket lock to
+ guarantee the bucket does not change. On the second attempt use
+ GFP_NOWAIT since we hold onto the spin lock.
+
+I did some manual testing to exercise the code paths where GFP_NOWAIT is
+used and where ERR_PTR(err) is returned. I used the realloc test cases
+included later in this series to trigger a scenario where a realloc
+happens inside bpf_iter_tcp_batch and made a small code tweak to force
+the first realloc attempt to allocate a too-small batch, thus requiring
+another attempt with GFP_NOWAIT. Some printks showed both reallocs with
+the tests passing:
+
+Jun 27 00:00:53 crow kernel: again GFP_USER
+Jun 27 00:00:53 crow kernel: again GFP_NOWAIT
+Jun 27 00:00:53 crow kernel: again GFP_USER
+Jun 27 00:00:53 crow kernel: again GFP_NOWAIT
+
+With this setup, I also forced each of the bpf_iter_tcp_realloc_batch
+calls to return -ENOMEM to ensure that iteration ends and that the
+read() in userspace fails.
+
+Signed-off-by: Jordan Rife <jordan@jrife.io>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 109 +++++++++++++++++++++++++++++++-------------
+ 1 file changed, 77 insertions(+), 32 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index 7823e55bc9e73..70c15160d2491 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -2768,7 +2768,7 @@ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+ if (!new_batch)
+ return -ENOMEM;
+
+- bpf_iter_tcp_put_batch(iter);
++ memcpy(new_batch, iter->batch, sizeof(*iter->batch) * iter->end_sk);
+ kvfree(iter->batch);
+ iter->batch = new_batch;
+ iter->max_sk = new_batch_sz;
+@@ -2777,69 +2777,95 @@ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+ }
+
+ static unsigned int bpf_iter_tcp_listening_batch(struct seq_file *seq,
+- struct sock *start_sk)
++ struct sock **start_sk)
+ {
+- struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
+ struct bpf_tcp_iter_state *iter = seq->private;
+- struct tcp_iter_state *st = &iter->state;
+ struct hlist_nulls_node *node;
+ unsigned int expected = 1;
+ struct sock *sk;
+
+- sock_hold(start_sk);
+- iter->batch[iter->end_sk++] = start_sk;
++ sock_hold(*start_sk);
++ iter->batch[iter->end_sk++] = *start_sk;
+
+- sk = sk_nulls_next(start_sk);
++ sk = sk_nulls_next(*start_sk);
++ *start_sk = NULL;
+ sk_nulls_for_each_from(sk, node) {
+ if (seq_sk_match(seq, sk)) {
+ if (iter->end_sk < iter->max_sk) {
+ sock_hold(sk);
+ iter->batch[iter->end_sk++] = sk;
++ } else if (!*start_sk) {
++ /* Remember where we left off. */
++ *start_sk = sk;
+ }
+ expected++;
+ }
+ }
+- spin_unlock(&hinfo->lhash2[st->bucket].lock);
+
+ return expected;
+ }
+
+ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,
+- struct sock *start_sk)
++ struct sock **start_sk)
+ {
+- struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
+ struct bpf_tcp_iter_state *iter = seq->private;
+- struct tcp_iter_state *st = &iter->state;
+ struct hlist_nulls_node *node;
+ unsigned int expected = 1;
+ struct sock *sk;
+
+- sock_hold(start_sk);
+- iter->batch[iter->end_sk++] = start_sk;
++ sock_hold(*start_sk);
++ iter->batch[iter->end_sk++] = *start_sk;
+
+- sk = sk_nulls_next(start_sk);
++ sk = sk_nulls_next(*start_sk);
++ *start_sk = NULL;
+ sk_nulls_for_each_from(sk, node) {
+ if (seq_sk_match(seq, sk)) {
+ if (iter->end_sk < iter->max_sk) {
+ sock_hold(sk);
+ iter->batch[iter->end_sk++] = sk;
++ } else if (!*start_sk) {
++ /* Remember where we left off. */
++ *start_sk = sk;
+ }
+ expected++;
+ }
+ }
+- spin_unlock_bh(inet_ehash_lockp(hinfo, st->bucket));
+
+ return expected;
+ }
+
++static unsigned int bpf_iter_fill_batch(struct seq_file *seq,
++ struct sock **start_sk)
++{
++ struct bpf_tcp_iter_state *iter = seq->private;
++ struct tcp_iter_state *st = &iter->state;
++
++ if (st->state == TCP_SEQ_STATE_LISTENING)
++ return bpf_iter_tcp_listening_batch(seq, start_sk);
++ else
++ return bpf_iter_tcp_established_batch(seq, start_sk);
++}
++
++static void bpf_iter_tcp_unlock_bucket(struct seq_file *seq)
++{
++ struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
++ struct bpf_tcp_iter_state *iter = seq->private;
++ struct tcp_iter_state *st = &iter->state;
++
++ if (st->state == TCP_SEQ_STATE_LISTENING)
++ spin_unlock(&hinfo->lhash2[st->bucket].lock);
++ else
++ spin_unlock_bh(inet_ehash_lockp(hinfo, st->bucket));
++}
++
+ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ {
+ struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
+ struct bpf_tcp_iter_state *iter = seq->private;
+ struct tcp_iter_state *st = &iter->state;
+ unsigned int expected;
+- bool resized = false;
+ struct sock *sk;
++ int err;
+
+ /* The st->bucket is done. Directly advance to the next
+ * bucket instead of having the tcp_seek_last_pos() to skip
+@@ -2856,33 +2882,52 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ }
+ }
+
+-again:
+- /* Get a new batch */
+ iter->cur_sk = 0;
+ iter->end_sk = 0;
+- iter->st_bucket_done = false;
++ iter->st_bucket_done = true;
+
+ sk = tcp_seek_last_pos(seq);
+ if (!sk)
+ return NULL; /* Done */
+
+- if (st->state == TCP_SEQ_STATE_LISTENING)
+- expected = bpf_iter_tcp_listening_batch(seq, sk);
+- else
+- expected = bpf_iter_tcp_established_batch(seq, sk);
++ expected = bpf_iter_fill_batch(seq, &sk);
++ if (likely(iter->end_sk == expected))
++ goto done;
+
+- if (iter->end_sk == expected) {
+- iter->st_bucket_done = true;
+- return sk;
+- }
++ /* Batch size was too small. */
++ bpf_iter_tcp_unlock_bucket(seq);
++ bpf_iter_tcp_put_batch(iter);
++ err = bpf_iter_tcp_realloc_batch(iter, expected * 3 / 2,
++ GFP_USER);
++ if (err)
++ return ERR_PTR(err);
++
++ iter->cur_sk = 0;
++ iter->end_sk = 0;
++
++ sk = tcp_seek_last_pos(seq);
++ if (!sk)
++ return NULL; /* Done */
++
++ expected = bpf_iter_fill_batch(seq, &sk);
++ if (likely(iter->end_sk == expected))
++ goto done;
+
+- if (!resized && !bpf_iter_tcp_realloc_batch(iter, expected * 3 / 2,
+- GFP_USER)) {
+- resized = true;
+- goto again;
++ /* Batch size was still too small. Hold onto the lock while we try
++ * again with a larger batch to make sure the current bucket's size
++ * does not change in the meantime.
++ */
++ err = bpf_iter_tcp_realloc_batch(iter, expected, GFP_NOWAIT);
++ if (err) {
++ bpf_iter_tcp_unlock_bucket(seq);
++ return ERR_PTR(err);
+ }
+
+- return sk;
++ expected = bpf_iter_fill_batch(seq, &sk);
++ WARN_ON_ONCE(iter->end_sk != expected);
++done:
++ bpf_iter_tcp_unlock_bucket(seq);
++ return iter->batch[0];
+ }
+
+ static void *bpf_iter_tcp_seq_start(struct seq_file *seq, loff_t *pos)
+--
+2.53.0
+
--- /dev/null
+From 0dc2b0f88c1c5f6e8a4bfa9e598623b7a967f7ae Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Jul 2025 11:09:08 -0700
+Subject: bpf: tcp: Use bpf_tcp_iter_batch_item for bpf_tcp_iter_state batch
+ items
+
+From: Jordan Rife <jordan@jrife.io>
+
+[ Upstream commit efeb820951ebf3778830256496ff72d00d135310 ]
+
+Prepare for the next patch that tracks cookies between iterations by
+converting struct sock **batch to union bpf_tcp_iter_batch_item *batch
+inside struct bpf_tcp_iter_state.
+
+Signed-off-by: Jordan Rife <jordan@jrife.io>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 24 ++++++++++++++----------
+ 1 file changed, 14 insertions(+), 10 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index fb975e8f55ae5..9843e05343565 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -2725,12 +2725,16 @@ static int tcp4_seq_show(struct seq_file *seq, void *v)
+ }
+
+ #ifdef CONFIG_BPF_SYSCALL
++union bpf_tcp_iter_batch_item {
++ struct sock *sk;
++};
++
+ struct bpf_tcp_iter_state {
+ struct tcp_iter_state state;
+ unsigned int cur_sk;
+ unsigned int end_sk;
+ unsigned int max_sk;
+- struct sock **batch;
++ union bpf_tcp_iter_batch_item *batch;
+ };
+
+ struct bpf_iter__tcp {
+@@ -2756,13 +2760,13 @@ static void bpf_iter_tcp_put_batch(struct bpf_tcp_iter_state *iter)
+ unsigned int cur_sk = iter->cur_sk;
+
+ while (cur_sk < iter->end_sk)
+- sock_gen_put(iter->batch[cur_sk++]);
++ sock_gen_put(iter->batch[cur_sk++].sk);
+ }
+
+ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+ unsigned int new_batch_sz, gfp_t flags)
+ {
+- struct sock **new_batch;
++ union bpf_tcp_iter_batch_item *new_batch;
+
+ new_batch = kvmalloc(sizeof(*new_batch) * new_batch_sz,
+ flags | __GFP_NOWARN);
+@@ -2786,7 +2790,7 @@ static unsigned int bpf_iter_tcp_listening_batch(struct seq_file *seq,
+ struct sock *sk;
+
+ sock_hold(*start_sk);
+- iter->batch[iter->end_sk++] = *start_sk;
++ iter->batch[iter->end_sk++].sk = *start_sk;
+
+ sk = sk_nulls_next(*start_sk);
+ *start_sk = NULL;
+@@ -2794,7 +2798,7 @@ static unsigned int bpf_iter_tcp_listening_batch(struct seq_file *seq,
+ if (seq_sk_match(seq, sk)) {
+ if (iter->end_sk < iter->max_sk) {
+ sock_hold(sk);
+- iter->batch[iter->end_sk++] = sk;
++ iter->batch[iter->end_sk++].sk = sk;
+ } else if (!*start_sk) {
+ /* Remember where we left off. */
+ *start_sk = sk;
+@@ -2815,7 +2819,7 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,
+ struct sock *sk;
+
+ sock_hold(*start_sk);
+- iter->batch[iter->end_sk++] = *start_sk;
++ iter->batch[iter->end_sk++].sk = *start_sk;
+
+ sk = sk_nulls_next(*start_sk);
+ *start_sk = NULL;
+@@ -2823,7 +2827,7 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,
+ if (seq_sk_match(seq, sk)) {
+ if (iter->end_sk < iter->max_sk) {
+ sock_hold(sk);
+- iter->batch[iter->end_sk++] = sk;
++ iter->batch[iter->end_sk++].sk = sk;
+ } else if (!*start_sk) {
+ /* Remember where we left off. */
+ *start_sk = sk;
+@@ -2927,7 +2931,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ WARN_ON_ONCE(iter->end_sk != expected);
+ done:
+ bpf_iter_tcp_unlock_bucket(seq);
+- return iter->batch[0];
++ return iter->batch[0].sk;
+ }
+
+ static void *bpf_iter_tcp_seq_start(struct seq_file *seq, loff_t *pos)
+@@ -2962,11 +2966,11 @@ static void *bpf_iter_tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+ * st->bucket. See tcp_seek_last_pos().
+ */
+ st->offset++;
+- sock_gen_put(iter->batch[iter->cur_sk++]);
++ sock_gen_put(iter->batch[iter->cur_sk++].sk);
+ }
+
+ if (iter->cur_sk < iter->end_sk)
+- sk = iter->batch[iter->cur_sk];
++ sk = iter->batch[iter->cur_sk].sk;
+ else
+ sk = bpf_iter_tcp_batch(seq);
+
+--
+2.53.0
+
--- /dev/null
+From d777275b37f35293379d4d7c61d934a191182100 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 14:53:52 +0300
+Subject: btrfs: fix memory leak in btrfs_do_encoded_write()
+
+From: Dmitry Antipov <dmantipov@yandex.ru>
+
+[ Upstream commit d2a4e4e626b2f4670b69b430c357f03f53eb6632 ]
+
+Local fuzzing of 6.12.94 has found the following memory leak:
+
+Unreferenced object 0xffff888018050a80 (size 64):
+ comm "syz.0.17", pid 10297, jiffies 4294953601
+ hex dump (first 32 bytes):
+ 00 10 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................
+ 10 0a 05 18 80 88 ff ff 10 0a 05 18 80 88 ff ff ................
+ backtrace (crc a8a6fc29):
+ kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
+ slab_post_alloc_hook mm/slub.c:4152 [inline]
+ slab_alloc_node mm/slub.c:4197 [inline]
+ __kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358
+ kmalloc_noprof include/linux/slab.h:878 [inline]
+ extent_changeset_alloc fs/btrfs/extent_io.h:207 [inline]
+ qgroup_reserve_data+0x1c5/0x7d0 fs/btrfs/qgroup.c:4305
+ btrfs_qgroup_reserve_data+0x2e/0xb0 fs/btrfs/qgroup.c:4355
+ btrfs_do_encoded_write+0x92e/0x1040 fs/btrfs/inode.c:9746
+ btrfs_encoded_write fs/btrfs/file.c:1482 [inline]
+ btrfs_do_write_iter+0x280/0x610 fs/btrfs/file.c:1507
+ btrfs_ioctl_encoded_write+0x3d6/0x490 fs/btrfs/ioctl.c:4738
+ btrfs_ioctl+0x6f9/0xc90 fs/btrfs/ioctl.c:-1
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:906 [inline]
+ __se_sys_ioctl+0xf9/0x170 fs/ioctl.c:892
+ do_syscall_x64 arch/x86/entry/common.c:47 [inline]
+ do_syscall_64+0xbe/0x1a0 arch/x86/entry/common.c:78
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Unreferenced object 0xffff888018050a00 (size 64):
+ comm "syz.0.17", pid 10297, jiffies 4294953601
+ hex dump (first 32 bytes):
+ 00 00 00 00 00 00 00 00 ff 0f 00 00 00 00 00 00 ................
+ 90 0a 05 18 80 88 ff ff 90 0a 05 18 80 88 ff ff ................
+ backtrace (crc cb5c9580):
+ kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
+ slab_post_alloc_hook mm/slub.c:4152 [inline]
+ slab_alloc_node mm/slub.c:4197 [inline]
+ __kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358
+ kmalloc_noprof include/linux/slab.h:878 [inline]
+ kzalloc_noprof include/linux/slab.h:1014 [inline]
+ ulist_prealloc+0x9c/0x110 fs/btrfs/ulist.c:114
+ extent_changeset_prealloc fs/btrfs/extent_io.h:217 [inline]
+ __set_extent_bit+0x16b/0x1a70 fs/btrfs/extent-io-tree.c:1086
+ set_record_extent_bits+0x50/0x90 fs/btrfs/extent-io-tree.c:1821
+ qgroup_reserve_data+0x274/0x7d0 fs/btrfs/qgroup.c:4312
+ btrfs_qgroup_reserve_data+0x2e/0xb0 fs/btrfs/qgroup.c:4355
+ btrfs_do_encoded_write+0x92e/0x1040 fs/btrfs/inode.c:9746
+ btrfs_encoded_write fs/btrfs/file.c:1482 [inline]
+ btrfs_do_write_iter+0x280/0x610 fs/btrfs/file.c:1507
+ btrfs_ioctl_encoded_write+0x3d6/0x490 fs/btrfs/ioctl.c:4738
+ btrfs_ioctl+0x6f9/0xc90 fs/btrfs/ioctl.c:-1
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:906 [inline]
+ __se_sys_ioctl+0xf9/0x170 fs/ioctl.c:892
+ do_syscall_x64 arch/x86/entry/common.c:47 [inline]
+ do_syscall_64+0xbe/0x1a0 arch/x86/entry/common.c:78
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Fix this by freeing an extent changeset before returning from
+btrfs_do_encoded_write().
+
+Fixes: 7c0c7269f7b5 ("btrfs: add BTRFS_IOC_ENCODED_WRITE")
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/inode.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index 77b436bf1db76..b2a1d96a806a9 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -11181,6 +11181,7 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
+ }
+ kvfree(pages);
+ out:
++ extent_changeset_free(data_reserved);
+ if (ret >= 0)
+ iocb->ki_pos += encoded->len;
+ return ret;
+--
+2.53.0
+
--- /dev/null
+From da9005daa8f982289b2d8eb873fb5b6228f75e84 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jul 2026 04:29:10 +0000
+Subject: counter: microchip-tcb-capture: Fix DT channel validation
+
+From: Babanpreet Singh <bbnpreetsingh@gmail.com>
+
+[ Upstream commit f1a3a9946aab611dd2200c01ff122f64b033dad2 ]
+
+mchp_tc_probe() reads the devicetree "reg" cell - a u32, per the API
+contract of of_property_read_u32_index() - into a signed int, so the
+bounds check "channel > 2" fails to reject cell values at or above
+0x80000000: reinterpreted as a negative int, they compare below 2 and
+pass validation.
+
+A malformed devicetree can therefore drive a negative channel into the
+ATMEL_TC_REG() offset arithmetic, making the driver access syscon
+regmap offsets outside the TC block's register window, and into the
+"t%d_clk" clock-name formatting, where it truncates clk_name (sized
+for "t0_clk".."t2_clk").
+
+Declare channel as u32, matching the API contract; the unsigned
+comparison then rejects everything except channels 0..2. Adjust the
+format specifier to %u accordingly, which also resolves the W=1
+warning that exposed the gap:
+
+ microchip-tcb-capture.c:520:56: warning: '%d' directive output may
+ be truncated writing between 1 and 11 bytes into a region of size
+ 6 [-Wformat-truncation=]
+ note: directive argument in the range [-2147483648, 2]
+
+No behavior change for well-formed devicetrees: channels 0..2 take
+identical paths before and after.
+
+Fixes: 106b104137fd ("counter: Add microchip TCB capture counter")
+Assisted-by: Claude:claude-fable-5 [gcc W=1]
+Signed-off-by: Babanpreet Singh <bbnpreetsingh@gmail.com>
+Reviewed-by: Joshua Crofts <joshua.crofts1@gmail.com>
+Link: https://lore.kernel.org/r/20260714042910.7-1-bbnpreetsingh@gmail.com
+Signed-off-by: William Breathitt Gray <wbg@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/counter/microchip-tcb-capture.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/counter/microchip-tcb-capture.c b/drivers/counter/microchip-tcb-capture.c
+index 2f631729a870b..f2cd7b599e44e 100644
+--- a/drivers/counter/microchip-tcb-capture.c
++++ b/drivers/counter/microchip-tcb-capture.c
+@@ -310,7 +310,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
+ char clk_name[7];
+ struct regmap *regmap;
+ struct clk *clk[3];
+- int channel;
++ u32 channel;
+ int ret, i;
+
+ counter = devm_counter_alloc(&pdev->dev, sizeof(*priv));
+@@ -344,7 +344,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
+
+ priv->channel[i] = channel;
+
+- snprintf(clk_name, sizeof(clk_name), "t%d_clk", channel);
++ snprintf(clk_name, sizeof(clk_name), "t%u_clk", channel);
+
+ clk[i] = of_clk_get_by_name(np->parent, clk_name);
+ if (IS_ERR(clk[i])) {
+--
+2.53.0
+
--- /dev/null
+From c36c6d9465eae41f81a36337fd0c1f692196764b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:16:45 +0800
+Subject: hwmon: (ads7828) Fix external VREF regulator handling
+
+From: Qingshuang Fu <fuqingshuang@kylinos.cn>
+
+[ Upstream commit fddb5ceaf901b050ed2a1a7deeecbf97e003435a ]
+
+The driver currently has two issues with the external VREF regulator
+handling in ads7828_probe():
+
+1. All errors from devm_regulator_get_optional() are ignored, causing the
+ driver to incorrectly fall back to internal VREF even for transient
+ errors like -EPROBE_DEFER or genuine failures like -ENOMEM.
+
+2. The external regulator is never enabled. The driver calls
+ regulator_get_voltage() without first calling regulator_enable(),
+ so the VREF pin may remain unpowered if the regulator is not
+ configured as always-on.
+
+Fix both issues by switching to devm_regulator_get_enable_read_voltage(),
+which handles regulator get, enable, and voltage read in one call.
+Only -ENODEV (no regulator specified in device tree) should trigger the
+fallback to internal VREF. All other errors are propagated to the caller.
+
+Fixes: a8ddfea09566 ("hwmon: (ads7828) Accept optional parameters from device tree")
+Signed-off-by: Qingshuang Fu <fuqingshuang@kylinos.cn>
+Link: https://lore.kernel.org/r/20260805061645.1331652-1-fffsqian@163.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ads7828.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
+index 7246198f09013..efd60b52e29b9 100644
+--- a/drivers/hwmon/ads7828.c
++++ b/drivers/hwmon/ads7828.c
+@@ -108,12 +108,11 @@ static int ads7828_probe(struct i2c_client *client)
+ struct ads7828_data *data;
+ struct device *hwmon_dev;
+ unsigned int vref_mv = ADS7828_INT_VREF_MV;
+- unsigned int vref_uv;
++ int vref_uv;
+ bool diff_input = false;
+ bool ext_vref = false;
+ unsigned int regval;
+ enum ads7828_chips chip;
+- struct regulator *reg;
+
+ data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL);
+ if (!data)
+@@ -127,9 +126,11 @@ static int ads7828_probe(struct i2c_client *client)
+ } else if (dev->of_node) {
+ diff_input = of_property_read_bool(dev->of_node,
+ "ti,differential-input");
+- reg = devm_regulator_get_optional(dev, "vref");
+- if (!IS_ERR(reg)) {
+- vref_uv = regulator_get_voltage(reg);
++ vref_uv = devm_regulator_get_enable_read_voltage(dev, "vref");
++ if (vref_uv < 0) {
++ if (vref_uv != -ENODEV)
++ return vref_uv;
++ } else {
+ vref_mv = DIV_ROUND_CLOSEST(vref_uv, 1000);
+ if (vref_mv < ADS7828_EXT_VREF_MV_MIN ||
+ vref_mv > ADS7828_EXT_VREF_MV_MAX)
+--
+2.53.0
+
--- /dev/null
+From 703d024563555b8974dc7f1be605e2ac58525ca9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 07:19:20 +0000
+Subject: hwmon: (corsair-psu) fix possible out-of-bounds access on missing
+ string termination
+
+From: Wilken Gottwalt <wilken.gottwalt@posteo.net>
+
+[ Upstream commit 36c4d73ce05d1d8896c2669eb0730d35a02a2ec1 ]
+
+In theory it could be possible that the REPLY_SIZE sized buffers for
+holding the vendor and product strings could be end up missing the null
+termination (for example by malicious hardware built on purpose)
+required by the seq_printf() call. That limits the debugfs printf calls
+to a maximum string length of REPLY_SIZE.
+
+Fixes: d115b51e0e567 ("hwmon: add Corsair PSU HID controller driver")
+Signed-off-by: Wilken Gottwalt <wilken.gottwalt@posteo.net>
+Link: https://lore.kernel.org/r/anLj9gPWRoRDbQBV@monster.localdomain
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/corsair-psu.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c
+index 2f2cbc067634a..8392a18758d21 100644
+--- a/drivers/hwmon/corsair-psu.c
++++ b/drivers/hwmon/corsair-psu.c
+@@ -647,7 +647,7 @@ static int vendor_show(struct seq_file *seqf, void *unused)
+ {
+ struct corsairpsu_data *priv = seqf->private;
+
+- seq_printf(seqf, "%s\n", priv->vendor);
++ seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->vendor);
+
+ return 0;
+ }
+@@ -657,7 +657,7 @@ static int product_show(struct seq_file *seqf, void *unused)
+ {
+ struct corsairpsu_data *priv = seqf->private;
+
+- seq_printf(seqf, "%s\n", priv->product);
++ seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->product);
+
+ return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From fcd629107158eced94836794797bebd4e1ca0315 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Nov 2023 14:57:02 -0600
+Subject: hwmon: (lm25066) Use i2c_get_match_data()
+
+From: Rob Herring <robh@kernel.org>
+
+[ Upstream commit ac0c26bae662138eac9b49215e505b402f7e80e3 ]
+
+Use preferred i2c_get_match_data() instead of of_match_device() and
+i2c_match_id() to get the driver match data. With this, adjust the
+includes to explicitly include the correct headers.
+
+Adjust the 'chips' enum to not use 0, so that no match data can be
+distinguished from a valid enum value.
+
+Signed-off-by: Rob Herring <robh@kernel.org>
+Link: https://lore.kernel.org/r/20231115205703.3730448-3-robh@kernel.org
+[groeck: Use double cast for enum chips assignment to make compiler happy]
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Stable-dep-of: 0dabe8a56f77 ("hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/pmbus/lm25066.c | 14 +++-----------
+ 1 file changed, 3 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c
+index 09792cd03d9fd..a99f073c2d0b9 100644
+--- a/drivers/hwmon/pmbus/lm25066.c
++++ b/drivers/hwmon/pmbus/lm25066.c
+@@ -14,10 +14,10 @@
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
+ #include <linux/log2.h>
+-#include <linux/of_device.h>
++#include <linux/of.h>
+ #include "pmbus.h"
+
+-enum chips { lm25056, lm25066, lm5064, lm5066, lm5066i };
++enum chips { lm25056 = 1, lm25066, lm5064, lm5066, lm5066i };
+
+ #define LM25066_READ_VAUX 0xd0
+ #define LM25066_MFR_READ_IIN 0xd1
+@@ -468,8 +468,6 @@ static int lm25066_probe(struct i2c_client *client)
+ struct lm25066_data *data;
+ struct pmbus_driver_info *info;
+ const struct __coeff *coeff;
+- const struct of_device_id *of_id;
+- const struct i2c_device_id *i2c_id;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA))
+@@ -484,14 +482,8 @@ static int lm25066_probe(struct i2c_client *client)
+ if (config < 0)
+ return config;
+
+- i2c_id = i2c_match_id(lm25066_id, client);
++ data->id = (enum chips)(unsigned long)i2c_get_match_data(client);
+
+- of_id = of_match_device(lm25066_of_match, &client->dev);
+- if (of_id && (unsigned long)of_id->data != i2c_id->driver_data)
+- dev_notice(&client->dev, "Device mismatch: %s in device tree, %s detected\n",
+- of_id->name, i2c_id->name);
+-
+- data->id = i2c_id->driver_data;
+ info = &data->info;
+
+ info->pages = 1;
+--
+2.53.0
+
--- /dev/null
+From 95713dd6d48c71f7a786121f5dfd07d24e6d3050 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 15:48:42 +0800
+Subject: hwmon: (nzxt-smart2) Check return value of init_device() in probe
+
+From: Qingshuang Fu <fuqingshuang@kylinos.cn>
+
+[ Upstream commit d533882ce1060866a590257f2c77ee23eabef5b8 ]
+
+The init_device() call in nzxt_smart2_hid_probe() can fail because it
+sends HID output reports to the hardware to detect fans and set the
+update interval. If the hardware is not responding or the HID reports
+fail, init_device() returns a negative error code.
+
+However, the return value was ignored, causing the probe to continue
+and register an hwmon device even though the device was never properly
+initialized. This leads to an inconsistent state where the driver
+reports stale data or blocks on wait queues that will never be woken.
+
+The same function's return value is already checked in the
+reset_resume() handler, confirming the author's intent that errors
+should be propagated.
+
+Note that this fix was not possible before commit 59d104b54b0b
+("hwmon: (nzxt-smart2) Stop device IO before calling hid_hw_stop")
+because the out_hw_close error path was missing hid_device_io_stop(),
+which would have opened a use-after-free risk window.
+
+Fixes: 53e68c20aeb1 ("hwmon: add driver for NZXT RGB&Fan Controller/Smart Device v2.")
+Signed-off-by: Qingshuang Fu <fuqingshuang@kylinos.cn>
+Link: https://lore.kernel.org/r/20260804074842.505923-1-fffsqian@163.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/nzxt-smart2.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/nzxt-smart2.c b/drivers/hwmon/nzxt-smart2.c
+index 90df6a7fc88d7..9f30ec0883fbc 100644
+--- a/drivers/hwmon/nzxt-smart2.c
++++ b/drivers/hwmon/nzxt-smart2.c
+@@ -754,7 +754,11 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev,
+
+ hid_device_io_start(hdev);
+
+- init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS);
++ ret = init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS);
++ if (ret) {
++ dev_err(&hdev->dev, "init_device failed: %d\n", ret);
++ goto out_hw_close;
++ }
+
+ drvdata->hwmon =
+ hwmon_device_register_with_info(&hdev->dev, "nzxtsmart2", drvdata,
+--
+2.53.0
+
--- /dev/null
+From 634f82a6d696eaad404d18bdf639a86bc982ced2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 14:12:31 -0700
+Subject: hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit 0dabe8a56f772f0ece46d2597799f412c277d874 ]
+
+In lm25066_probe(), the PMBus coefficients for current and power are
+scaled based on the shunt resistor value. The calculation evaluates the
+multiplication using 32-bit arithmetic because info->m is an int and
+shunt is a u32:
+
+static int lm25066_probe(struct i2c_client *client) {
+ ...
+ info->m[PSC_CURRENT_IN] = info->m[PSC_CURRENT_IN] * shunt / 1000;
+ info->m[PSC_POWER] = info->m[PSC_POWER] * shunt / 1000;
+ ...
+}
+
+For large coefficients like 26882 (LM25056) or 15076 (LM5066i), a device
+tree shunt-resistor-micro-ohms value exceeding approximately 159,000
+(159 mOhm, which is physically valid for low-current applications) causes
+the intermediate product to exceed UINT_MAX (4,294,967,295). This results
+in a silent wraparound before the division by 1000.
+
+Furthermore, if the wrapped value has the most significant bit set,
+converting it back to the signed int info->m results in negative
+coefficients. This logic error leads to drastically corrupted current and
+power readings, which can cause erratic thermal or power management
+behavior in the system.
+
+Fix the problem by using 64-bit operations for the multiply/divide
+operations. This can still overflow, but only for unreasonably large
+shunt resistor values.
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Fixes: 94ee5fcc240fe ("hwmon: (pmbus/lm25066) Support configurable sense resistor values")
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/pmbus/lm25066.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c
+index a99f073c2d0b9..8fef24a25d728 100644
+--- a/drivers/hwmon/pmbus/lm25066.c
++++ b/drivers/hwmon/pmbus/lm25066.c
+@@ -14,6 +14,7 @@
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
+ #include <linux/log2.h>
++#include <linux/math.h>
+ #include <linux/of.h>
+ #include "pmbus.h"
+
+@@ -540,8 +541,8 @@ static int lm25066_probe(struct i2c_client *client)
+ if (of_property_read_u32(client->dev.of_node, "shunt-resistor-micro-ohms", &shunt))
+ shunt = 1000;
+
+- info->m[PSC_CURRENT_IN] = info->m[PSC_CURRENT_IN] * shunt / 1000;
+- info->m[PSC_POWER] = info->m[PSC_POWER] * shunt / 1000;
++ info->m[PSC_CURRENT_IN] = DIV_ROUND_CLOSEST_ULL((u64)info->m[PSC_CURRENT_IN] * shunt, 1000);
++ info->m[PSC_POWER] = DIV_ROUND_CLOSEST_ULL((u64)info->m[PSC_POWER] * shunt, 1000);
+
+ #if IS_ENABLED(CONFIG_SENSORS_LM25066_REGULATOR)
+ /* LM25056 doesn't support OPERATION */
+--
+2.53.0
+
--- /dev/null
+From 94832c514362b1ae3be0df45a070205b6cd78671 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 21:35:05 +0300
+Subject: ipvs: avoid out-of-bounds write in ip_vs_nat_icmp
+
+From: Julian Anastasov <ja@ssi.bg>
+
+[ Upstream commit 646922a0379496154e8c8faca4f8e2fd9100cacc ]
+
+Sashiko warns that local attacker can modify the packet
+while it is processed by IPVS. Some places read the
+IP ihl field multiple times which can cause out-of-bounds
+access. One such place is ip_vs_nat_icmp where we
+can write after the validated area.
+
+Fix it by providing ciph argument just like it is done for
+IPv6 and use ciph->len as offset to the embedded transport
+header.
+
+Modify some IPv4 header checks by reading the ihl field
+only once.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Link: https://sashiko.dev/#/patchset/20260722101517.36313-1-ja%40ssi.bg
+Signed-off-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/ip_vs.h | 2 +-
+ net/netfilter/ipvs/ip_vs_core.c | 67 +++++++++++++++++----------------
+ net/netfilter/ipvs/ip_vs_xmit.c | 2 +-
+ 3 files changed, 36 insertions(+), 35 deletions(-)
+
+diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
+index 344f0082d3041..876852c2d37f5 100644
+--- a/include/net/ip_vs.h
++++ b/include/net/ip_vs.h
+@@ -1577,7 +1577,7 @@ static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp)
+
+ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct ip_vs_conn *cp, int dir, unsigned int toff,
+- bool has_ports);
++ bool has_ports, struct ip_vs_iphdr *ciph);
+
+ #ifdef CONFIG_IP_VS_IPV6
+ void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
+diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
+index 27c096b070774..7157ea5abaefa 100644
+--- a/net/netfilter/ipvs/ip_vs_core.c
++++ b/net/netfilter/ipvs/ip_vs_core.c
+@@ -747,28 +747,27 @@ static int ip_vs_route_me_harder(struct netns_ipvs *ipvs, int af,
+ */
+ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct ip_vs_conn *cp, int inout, unsigned int toff,
+- bool has_ports)
++ bool has_ports, struct ip_vs_iphdr *ciph)
+ {
+ struct iphdr *iph = ip_hdr(skb);
+ struct icmphdr *icmph = (struct icmphdr *)(skb->data + toff);
+- struct iphdr *ciph = (struct iphdr *)(icmph + 1);
+- unsigned int coff __maybe_unused = toff + sizeof(struct icmphdr);
++ struct iphdr *cih = (struct iphdr *)(icmph + 1);
+
+ if (inout) {
+ iph->saddr = cp->vaddr.ip;
+ ip_send_check(iph);
+- ciph->daddr = cp->vaddr.ip;
+- ip_send_check(ciph);
++ cih->daddr = cp->vaddr.ip;
++ ip_send_check(cih);
+ } else {
+ iph->daddr = cp->daddr.ip;
+ ip_send_check(iph);
+- ciph->saddr = cp->daddr.ip;
+- ip_send_check(ciph);
++ cih->saddr = cp->daddr.ip;
++ ip_send_check(cih);
+ }
+
+ /* the TCP/UDP/SCTP port */
+ if (has_ports) {
+- __be16 *ports = (void *)ciph + ciph->ihl*4;
++ __be16 *ports = (void *)(skb->data + ciph->len);
+
+ if (inout)
+ ports[1] = cp->vport;
+@@ -782,10 +781,10 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ if (inout)
+- IP_VS_DBG_PKT(11, AF_INET, pp, skb, coff,
++ IP_VS_DBG_PKT(11, AF_INET, pp, skb, ciph->off,
+ "Forwarding altered outgoing ICMP");
+ else
+- IP_VS_DBG_PKT(11, AF_INET, pp, skb, coff,
++ IP_VS_DBG_PKT(11, AF_INET, pp, skb, ciph->off,
+ "Forwarding altered incoming ICMP");
+ }
+
+@@ -878,7 +877,7 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
+ ip_vs_nat_icmp_v6(skb, pp, cp, 1, toff, has_ports, ciph);
+ else
+ #endif
+- ip_vs_nat_icmp(skb, pp, cp, 1, toff, has_ports);
++ ip_vs_nat_icmp(skb, pp, cp, 1, toff, has_ports, ciph);
+
+ if (ip_vs_route_me_harder(cp->ipvs, af, skb, hooknum))
+ goto out;
+@@ -914,7 +913,7 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ struct ip_vs_iphdr ciph;
+ struct ip_vs_conn *cp;
+ struct ip_vs_protocol *pp;
+- unsigned int offset, ihl;
++ unsigned int offset;
+ union nf_inet_addr snet;
+
+ *related = 1;
+@@ -927,7 +926,6 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ return NF_ACCEPT;
+ }
+
+- ihl = ipvsh->len;
+ offset = ipvsh->len;
+ ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
+ if (ic == NULL)
+@@ -953,11 +951,15 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+
+ /* Now find the contained IP header */
+ offset += sizeof(_icmph);
++ if (!ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, true, &ciph))
++ return NF_ACCEPT; /* The packet looks wrong, ignore */
++
+ cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+- if (!(cih && cih->version == 4 && cih->ihl >= 5))
++ if (!(cih && cih->version == 4 &&
++ ciph.len - ciph.off >= sizeof(struct iphdr)))
+ return NF_ACCEPT; /* The packet looks wrong, ignore */
+
+- pp = ip_vs_proto_get(cih->protocol);
++ pp = ip_vs_proto_get(ciph.protocol);
+ if (!pp)
+ return NF_ACCEPT;
+
+@@ -968,8 +970,6 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ IP_VS_DBG_PKT(11, AF_INET, pp, skb, offset,
+ "Checking outgoing ICMP for");
+
+- ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, true, &ciph);
+-
+ /* The embedded headers contain source and dest in reverse order */
+ cp = INDIRECT_CALL_1(pp->conn_out_get, ip_vs_conn_out_get_proto,
+ ipvs, AF_INET, skb, &ciph);
+@@ -977,8 +977,8 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ return NF_ACCEPT;
+
+ snet.ip = ipvsh->saddr.ip;
+- return handle_response_icmp(AF_INET, skb, &snet, cp, pp, &ciph, ihl,
+- hooknum);
++ return handle_response_icmp(AF_INET, skb, &snet, cp, pp, &ciph,
++ ipvsh->len, hooknum);
+ }
+
+ #ifdef CONFIG_IP_VS_IPV6
+@@ -1630,10 +1630,12 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ /* Now find the contained IP header */
+ offset += sizeof(_icmph);
+ cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+- if (!(cih && cih->version == 4 && cih->ihl >= 5))
++ if (!cih)
+ return NF_ACCEPT; /* The packet looks wrong, ignore */
+- raddr = (union nf_inet_addr *)&cih->daddr;
+ hlen_ipip = cih->ihl * 4;
++ if (!(cih->version == 4 && hlen_ipip >= sizeof(struct iphdr)))
++ return NF_ACCEPT; /* The packet looks wrong, ignore */
++ raddr = (union nf_inet_addr *)&cih->daddr;
+
+ /* Special case for errors for IPIP/UDP/GRE tunnel packets */
+ tunnel = false;
+@@ -1650,9 +1652,6 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ if (!dest || dest->tun_type != IP_VS_CONN_F_TUNNEL_TYPE_IPIP)
+ return NF_ACCEPT;
+ offset += hlen_ipip;
+- cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+- if (!(cih && cih->version == 4 && cih->ihl >= 5))
+- return NF_ACCEPT; /* The packet looks wrong, ignore */
+ tunnel = true;
+ } else if ((cih->protocol == IPPROTO_UDP || /* Can be UDP encap */
+ cih->protocol == IPPROTO_GRE) && /* Can be GRE encap */
+@@ -1677,21 +1676,25 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ /* Skip IP and UDP/GRE tunnel headers */
+ offset = offset2 + ulen;
+ /* Now we should be at the original IP header */
+- cih = skb_header_pointer(skb, offset, sizeof(_ciph),
+- &_ciph);
+- if (cih && cih->version == 4 && cih->ihl >= 5 &&
+- iproto == IPPROTO_IPIP)
++ if (iproto == IPPROTO_IPIP)
+ tunnel = true;
+ else
+ return NF_ACCEPT;
+ }
+ }
+
+- pd = ip_vs_proto_data_get(ipvs, cih->protocol);
++ if (!ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, !tunnel, &ciph))
++ return NF_ACCEPT;
++ pd = ip_vs_proto_data_get(ipvs, ciph.protocol);
+ if (!pd)
+ return NF_ACCEPT;
+ pp = pd->pp;
+
++ cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
++ if (!(cih && cih->version == 4 &&
++ ciph.len - ciph.off >= sizeof(struct iphdr)))
++ return NF_ACCEPT; /* The packet looks wrong, ignore */
++
+ /* Is the embedded protocol header present? */
+ if (unlikely(cih->frag_off & htons(IP_OFFSET) && !pp->dont_defrag))
+ return NF_ACCEPT;
+@@ -1699,9 +1702,6 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ IP_VS_DBG_PKT(11, AF_INET, pp, skb, offset,
+ "Checking incoming ICMP for");
+
+- offset2 = offset;
+- ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, !tunnel, &ciph);
+-
+ /* The embedded headers contain source and dest in reverse order.
+ * For IPIP/UDP/GRE tunnel this is error for request, not for reply.
+ */
+@@ -1731,11 +1731,12 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ }
+
+ if (tunnel) {
+- unsigned int hlen_orig = cih->ihl * 4;
++ unsigned int hlen_orig = ciph.len - ciph.off;
+ __be32 info = ic->un.gateway;
+ __u8 type = ic->type;
+ __u8 code = ic->code;
+
++ offset2 = offset;
+ /* Update the MTU */
+ if (ic->type == ICMP_DEST_UNREACH &&
+ ic->code == ICMP_FRAG_NEEDED) {
+diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
+index db2f090e2f8f9..63dd0a3d251f8 100644
+--- a/net/netfilter/ipvs/ip_vs_xmit.c
++++ b/net/netfilter/ipvs/ip_vs_xmit.c
+@@ -1591,7 +1591,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
+ if (skb_cow(skb, rt->dst.dev->hard_header_len))
+ goto tx_error;
+
+- ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports);
++ ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports, ciph);
+
+ /* Another hack: avoid icmp_send in ip_fragment */
+ skb->ignore_df = 1;
+--
+2.53.0
+
--- /dev/null
+From fac0aed665efce9a6b432cb8ee6e70d167de36ee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 21:35:06 +0300
+Subject: ipvs: return the csum validation for forward hook
+
+From: Julian Anastasov <ja@ssi.bg>
+
+[ Upstream commit 99609cb0aa789c8d071050ce8579989551882cc6 ]
+
+Sashiko notes that playing games with the skb dst and rt
+flags instead of providing hooknum is not a good idea
+when validating the checksums.
+
+Also, skipping checksum validation for FORWARD packets
+risk silent data corruption, even if the only user is
+the FTP-CMD packets coming from the real server.
+
+Sashiko also noticed that by using common checksum
+helper in the previous commit we actually fixed old bug
+where the TCP/UDP checksum for IPv6 on CHECKSUM_COMPLETE
+was not validated correctly.
+
+Fixes: e876b75b9020 ("ipvs: fix the checksum validations")
+Link: https://sashiko.dev/#/patchset/20260722211420.153933-1-pablo%40netfilter.org
+Link: https://sashiko.dev/#/patchset/20260727185024.67534-1-ja%40ssi.bg
+Link: https://sashiko.dev/#/patchset/20260728202520.59179-1-ja%40ssi.bg
+Signed-off-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/ip_vs.h | 19 +++++--------------
+ net/netfilter/ipvs/ip_vs_proto_sctp.c | 2 +-
+ 2 files changed, 6 insertions(+), 15 deletions(-)
+
+diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
+index 876852c2d37f5..6df46a7a4f976 100644
+--- a/include/net/ip_vs.h
++++ b/include/net/ip_vs.h
+@@ -24,9 +24,7 @@
+ #include <linux/netfilter.h> /* for union nf_inet_addr */
+ #include <linux/ip.h>
+ #include <linux/ipv6.h> /* for struct ipv6hdr */
+-#include <net/route.h>
+ #include <net/ipv6.h>
+-#include <net/ip6_fib.h>
+ #if IS_ENABLED(CONFIG_NF_CONNTRACK)
+ #include <net/netfilter/nf_conntrack.h>
+ #endif
+@@ -1610,30 +1608,23 @@ static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum)
+ return csum_partial(diff, sizeof(diff), oldsum);
+ }
+
+-static inline bool ip_vs_checksum_needed(struct sk_buff *skb, int af)
++static inline bool ip_vs_checksum_needed(struct sk_buff *skb)
+ {
+ /* Checksum unnecessary or already validated? */
+ if (skb_csum_unnecessary(skb))
+ return false;
+- /* LOCAL_OUT ? */
+- if (!skb->dev || skb->dev->flags & IFF_LOOPBACK)
++ /* Locally generated ? */
++ if (!skb->dev)
+ return false;
+- /* !LOCAL_IN (FORWARD) ? */
+- if (af == AF_INET6) {
+- if (!(dst_rt6_info(skb_dst(skb))->rt6i_flags & RTF_LOCAL))
+- return false;
+- } else {
+- if (!(skb_rtable(skb)->rt_flags & RTCF_LOCAL))
+- return false;
+- }
+ return true;
+ }
+
+ static inline bool ip_vs_checksum_common_check(struct sk_buff *skb,
+ int offset, int proto, int af)
+ {
+- if (!ip_vs_checksum_needed(skb, af))
++ if (!ip_vs_checksum_needed(skb))
+ return true;
++ /* Validate csum even for FORWARD */
+ return !nf_checksum(skb, NF_INET_LOCAL_IN, offset, proto, af);
+ }
+
+diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
+index 3dbd3096e1637..c80567c73469b 100644
+--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
++++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
+@@ -193,7 +193,7 @@ sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct sctphdr *sh;
+ __le32 cmp, val;
+
+- if (!ip_vs_checksum_needed(skb, af))
++ if (!ip_vs_checksum_needed(skb))
+ return 1;
+ sh = (struct sctphdr *)(skb->data + sctphoff);
+ cmp = sh->checksum;
+--
+2.53.0
+
--- /dev/null
+From 6163896209d085306952514d3a56cca333ea87af Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 13:15:08 +0000
+Subject: net/atm: fix slab-out-of-bounds read in vcc_setsockopt()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit d0c80dbb970439bd2eeb0e5effff8c16a5f4e1e3 ]
+
+vcc_setsockopt() contained an ineffective optlen check:
+ if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
+ return -EINVAL;
+
+If __SO_LEVEL_MATCH(optname, level) evaluated to false (e.g. if the caller
+passed a mismatched level), the length check optlen != __SO_SIZE(optname)
+was short-circuited and bypassed. Execution then fell through to switch(optname),
+calling copy_from_sockptr() assuming optval contained sufficient space.
+
+Furthermore, even if level matched, a cgroup BPF setsockopt filter could shrink
+optlen after entry. Because copy_from_sockptr() on kernel pointers uses memcpy(),
+this leads to a KASAN slab-out-of-bounds read when optlen is smaller than the
+expected structure size.
+
+Fix this by using copy_safe_from_sockptr(), which unconditionally validates
+that optlen is at least the expected size before copying. Also change the local
+'value' variable type from 'unsigned long' to 'int' so that SO_SETCLP matches
+its sizeof(int) ABI encoding on 64-bit systems.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: syzbot+53ecc09fb81df10ef4de@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=53ecc09fb81df10ef4de
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260805131508.3227331-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/atm/common.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/net/atm/common.c b/net/atm/common.c
+index 96f680a45e306..f3f68c231935a 100644
+--- a/net/atm/common.c
++++ b/net/atm/common.c
+@@ -760,7 +760,7 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
+ sockptr_t optval, unsigned int optlen)
+ {
+ struct atm_vcc *vcc;
+- unsigned long value;
++ int value;
+ int error;
+
+ if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
+@@ -772,8 +772,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
+ {
+ struct atm_qos qos;
+
+- if (copy_from_sockptr(&qos, optval, sizeof(qos)))
+- return -EFAULT;
++ error = copy_safe_from_sockptr(&qos, sizeof(qos), optval,
++ optlen);
++ if (error)
++ return error;
+ error = check_qos(&qos);
+ if (error)
+ return error;
+@@ -786,8 +788,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
+ return 0;
+ }
+ case SO_SETCLP:
+- if (copy_from_sockptr(&value, optval, sizeof(value)))
+- return -EFAULT;
++ error = copy_safe_from_sockptr(&value, sizeof(value), optval,
++ optlen);
++ if (error)
++ return error;
+ if (value)
+ vcc->atm_options |= ATM_ATMOPT_CLP;
+ else
+--
+2.53.0
+
--- /dev/null
+From 682dc10f686b8843f13984b0392ce72d4f2ecc37 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 12:17:10 +0400
+Subject: net: hisilicon: hix5hd2_gmac: remove redundant NAPI delete
+
+From: Jiawen Liu <1298662399@qq.com>
+
+[ Upstream commit f307a7dc32097c11413178fca437a10d20890bc2 ]
+
+hix5hd2_dev_remove() calls netif_napi_del() before unregister_netdev().
+This is not needed because free_netdev() deletes all NAPI instances
+attached to the net_device.
+
+Remove the redundant call and let the networking core tear down the NAPI
+instance during unregister_netdev(). The probe error path still keeps its
+explicit netif_napi_del(), because the device has not been registered
+there.
+
+Fixes: 57c5bc9ad7d7 ("net: hisilicon: add hix5hd2 mac driver")
+Signed-off-by: Jiawen Liu <1298662399@qq.com>
+Link: https://patch.msgid.link/tencent_5FFD37A252B4FEA6A80AD25B17C8E904F005@qq.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hix5hd2_gmac.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+index f867e95311173..4834cf1cd9b3e 100644
+--- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
++++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+@@ -1288,7 +1288,6 @@ static int hix5hd2_dev_remove(struct platform_device *pdev)
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct hix5hd2_priv *priv = netdev_priv(ndev);
+
+- netif_napi_del(&priv->napi);
+ unregister_netdev(ndev);
+ mdiobus_unregister(priv->bus);
+ mdiobus_free(priv->bus);
+--
+2.53.0
+
--- /dev/null
+From 516393aa3719ededb21082b34e837e6d3e9b76dc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 11:04:02 +0300
+Subject: net/mlx5: fw_tracer, return NULL on create error
+
+From: Michael Guralnik <michaelgur@nvidia.com>
+
+[ Upstream commit af39eb111ce6b5eba9c08513b62c4868eb7e7fd5 ]
+
+Tracer creation can fail by returning either NULL or ERR_PTR.
+The return value is stored without a check on the device, and users
+treat ERR_PTR and NULL the same way.
+This also causes a crash in the core dump logic, which is missing the
+ERR_PTR check and ends up dereferencing it, as shown in the trace below.
+
+Switch tracer creation to return NULL on failure only, so callers only
+need a single NULL check.
+
+ Internal error: Oops: 0000000096000006 [#1] SMP
+ Modules linked in: mlx5_ib ib_uverbs ib_core ipv6 mlx5_core
+ CPU: 1 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted 6.19.7 #1 PREEMPT(none)
+ Workqueue: mlx5_health0001:01:00.0 mlx5_fw_reporter_err_work [mlx5_core]
+ pstate: a3400009 (NzCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
+ pc : mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core]
+ lr : mlx5_fw_tracer_trigger_core_dump_general+0x40/0xe0 [mlx5_core]
+ sp : ffff800081cf3c40
+ x29: ffff800081cf3c90 x28: 0000000000000000 x27: 0000000000000000
+ x26: ffff000080018828 x25: 0000000000000000 x24: ffff000080304a05
+ x23: ffff800081cf3d80 x22: ffff0000847e01a0 x21: 0000000000000000
+ x20: ffff0000847e01a0 x19: ffffffffffffffa1 x18: ffff80008310bbf0
+ x17: ffff800080119650 x16: ffff80008010df54 x15: ffff80008010d4ac
+ x14: ffff800079c202e4 x13: ffff80008002fe60 x12: ffff800080119650
+ x11: ffff80008010df54 x10: ffff80008010d4ac x9 : ffff800079c203d8
+ x8 : ffff800081cf3c88 x7 : 0000000000000000 x6 : 0000000000000000
+ x5 : 0000000000000000 x4 : 0000000000000008 x3 : 0000000000000030
+ x2 : 0000000000000008 x1 : 0000000000000000 x0 : 00000000c5c4000e
+ Call trace:
+ mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core] (P)
+ mlx5_fw_reporter_dump+0x30/0x2e0 [mlx5_core]
+ devlink_health_do_dump+0x9c/0x160
+ devlink_health_report+0x1c0/0x288
+ mlx5_fw_reporter_err_work+0xac/0xc0 [mlx5_core]
+ process_one_work+0x15c/0x3d8
+ worker_thread+0x18c/0x320
+ kthread+0x148/0x228
+ ret_from_fork+0x10/0x20
+ Code: b9400000 5ac00800 7a401800 540003ca (3940a260)
+ ---[ end trace 0000000000000000 ]---
+ Kernel panic - not syncing: Oops: Fatal exception
+ SMP: stopping secondary CPUs
+ Kernel Offset: disabled
+ CPU features: 0x000000,00078031,75fce5a1,35fffe67
+ Memory Limit: none
+ ---[ end Kernel panic - not syncing: Oops: Fatal exception ]---
+
+Fixes: fd1483fe1f9f ("net/mlx5: Add support for FW reporter dump")
+Signed-off-by: Michael Guralnik <michaelgur@nvidia.com>
+Reviewed-by: Shay Drori <shayd@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260729080402.2427184-1-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ethernet/mellanox/mlx5/core/diag/fw_tracer.c | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+index c216634c8919e..de0bb2669e4ce 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+@@ -1036,13 +1036,11 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
+
+ tracer = kvzalloc(sizeof(*tracer), GFP_KERNEL);
+ if (!tracer)
+- return ERR_PTR(-ENOMEM);
++ return NULL;
+
+ tracer->work_queue = create_singlethread_workqueue("mlx5_fw_tracer");
+- if (!tracer->work_queue) {
+- err = -ENOMEM;
++ if (!tracer->work_queue)
+ goto free_tracer;
+- }
+
+ tracer->dev = dev;
+
+@@ -1082,7 +1080,7 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
+ destroy_workqueue(tracer->work_queue);
+ free_tracer:
+ kvfree(tracer);
+- return ERR_PTR(err);
++ return NULL;
+ }
+
+ static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data);
+@@ -1093,7 +1091,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
+ struct mlx5_core_dev *dev;
+ int err;
+
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return 0;
+
+ dev = tracer->dev;
+@@ -1136,7 +1134,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
+ /* Stop tracer + Cleanup HW resources */
+ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
+ {
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return;
+
+ mlx5_core_dbg(tracer->dev, "FWTracer: Cleanup, is owner ? (%d)\n",
+@@ -1155,7 +1153,7 @@ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
+ /* Free software resources (Buffers, etc ..) */
+ void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer)
+ {
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return;
+
+ mlx5_core_dbg(tracer->dev, "FWTracer: Destroy\n");
+@@ -1203,7 +1201,7 @@ int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer)
+ struct mlx5_core_dev *dev;
+ int err;
+
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return 0;
+
+ dev = tracer->dev;
+--
+2.53.0
+
--- /dev/null
+From b66009d5c7991c62e5c0131d9b6b8bc6e84c363c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 12:36:18 +0800
+Subject: net/ncsi: fix heap OOB read in NCSI_CMD_SEND_CMD payload length
+
+From: Henry Martin <bsdhenrymartin@gmail.com>
+
+[ Upstream commit afa58b7384913c8773d837acdb07b035690ec5d2 ]
+
+ncsi_send_cmd_nl() takes the number of bytes to copy from the
+attacker-controlled ncsi_pkt_hdr.length field of the in-band packet
+header, while the source buffer is the NCSI_ATTR_DATA netlink
+attribute whose readable size is nla_len() - sizeof(ncsi_pkt_hdr).
+The two length sources are never cross-checked: only
+nla_len() >= sizeof(struct ncsi_pkt_hdr) is enforced.
+
+With hdr->length set larger than the attribute payload (up to 65535
+against at most 2032 readable bytes), ncsi_cmd_handler_oem() copies
+past the end of the netlink attribute buffer with unsafe_memcpy(),
+leaking up to ~64KB of kernel heap memory into the transmitted NCSI
+command packet. The destination skb is sized by the declared payload,
+so the write side does not overflow - this is a pure OOB read /
+information leak, reachable with CAP_NET_ADMIN on systems with a
+registered NCSI device (e.g. OpenBMC on Aspeed BMC SoCs, where
+NET_NCSI=y is standard).
+
+Reject commands whose declared payload extends past the end of the
+data attribute.
+
+The issue was found by the autokbug dynamic kernel fuzzer at Tencent
+Yunding Lab.
+
+Fixes: 9771b8ccdfa6 ("net/ncsi: Extend NC-SI Netlink interface to allow user space to send NC-SI command")
+Reported-by: Henry Martin <bsdhenrymartin@gmail.com>
+Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>
+Link: https://patch.msgid.link/20260803043618.3210301-1-bsdhenrymartin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ncsi/ncsi-netlink.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/net/ncsi/ncsi-netlink.c b/net/ncsi/ncsi-netlink.c
+index fe681680b5d91..a4ba1f6c9d228 100644
+--- a/net/ncsi/ncsi-netlink.c
++++ b/net/ncsi/ncsi-netlink.c
+@@ -461,6 +461,10 @@ static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info)
+ nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN;
+ nca.info = info;
+ nca.payload = ntohs(hdr->length);
++ if (nca.payload > len - sizeof(*hdr)) {
++ ret = -EINVAL;
++ goto out_netlink;
++ }
+ nca.data = data + sizeof(*hdr);
+
+ ret = ncsi_xmit_cmd(&nca);
+--
+2.53.0
+
--- /dev/null
+From f661bc67ecd3eeafe360f154de70faed4599e9cb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 18:20:06 -0400
+Subject: net/openvswitch: check Ethernet header length in key_extract()
+
+From: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+
+[ Upstream commit cf6f8b29befb92173659bcef6a441d274947bfae ]
+
+When a packet arrives on an ARPHRD_NONE device (e.g. TUN),
+ovs_flow_key_extract() trusts the user-provided skb->protocol field: if
+it is ETH_P_TEB, the packet is classified as MAC_PROTO_ETHERNET and
+key_extract() is called without ensuring the skb has ETH_HLEN (14) bytes
+of linear data. key_extract() unconditionally pulls 2 * ETH_ALEN bytes
+for MAC addresses and parse_ethertype() pulls 2 more, either of which
+triggers a kernel BUG in __skb_pull() when the linear area is too small.
+
+ kernel BUG at include/linux/skbuff.h:2848!
+ RIP: 0010:key_extract+0xa7e/0xd90 net/openvswitch/flow.c:933
+ ovs_flow_key_extract+0x419/0xa70
+ ovs_vport_receive+0x222/0x390
+ netdev_frame_hook+0x3e0/0x630
+ tun_get_user+0x2d0c/0x38e0
+
+Fixed by calling check_header() in key_extract() before accessing the
+Ethernet header.
+
+Fixes: 217ac77a3c25 ("openvswitch: allow L3 netdev ports")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Reviewed-by: Eelco Chaudron <echaudro@redhat.com>
+Signed-off-by: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
+Link: https://patch.msgid.link/20260730222006.118652-1-blbllhy@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/flow.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
+index 60ebc42a20e7e..3111817293aa0 100644
+--- a/net/openvswitch/flow.c
++++ b/net/openvswitch/flow.c
+@@ -890,8 +890,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ * Ethernet header
+ * @key: output flow key
+ *
+- * The caller must ensure that skb->len >= ETH_HLEN.
+- *
+ * Initializes @skb header fields as follows:
+ *
+ * - skb->mac_header: the L2 header.
+@@ -911,8 +909,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ */
+ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+ {
+- struct ethhdr *eth;
+-
+ /* Flags are always used as part of stats */
+ key->tp.flags = 0;
+
+@@ -927,6 +923,13 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+ skb_reset_network_header(skb);
+ key->eth.type = skb->protocol;
+ } else {
++ struct ethhdr *eth;
++ int err;
++
++ err = check_header(skb, ETH_HLEN);
++ if (unlikely(err))
++ return err;
++
+ eth = eth_hdr(skb);
+ ether_addr_copy(key->eth.src, eth->h_source);
+ ether_addr_copy(key->eth.dst, eth->h_dest);
+--
+2.53.0
+
--- /dev/null
+From d29ad82db7a015f25b85c8b616e0ba9db3a007c6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 22:19:06 +0800
+Subject: net: prestera: validate firmware header length
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 8ae344eb540af3f457179b52bc6061416752485c ]
+
+prestera_fw_hdr_parse() reads the firmware header before checking
+that the firmware image contains that header.
+
+Reject images shorter than struct prestera_fw_header before decoding the
+magic and version fields.
+
+Fixes: 4c2703dfd7fabb ("net: marvell: prestera: Add PCI interface support")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Acked-by: Elad Nachman <enachman@marvell.com>
+Link: https://patch.msgid.link/20260731141500.1-prestera-v2-pengpeng@iscas.ac.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/marvell/prestera/prestera_pci.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/marvell/prestera/prestera_pci.c b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+index a37dbbda8de39..bc6af7b4909d9 100644
+--- a/drivers/net/ethernet/marvell/prestera/prestera_pci.c
++++ b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+@@ -673,6 +673,9 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw)
+ struct prestera_fw_header *hdr;
+ u32 magic;
+
++ if (fw->bin->size < sizeof(*hdr))
++ return -EINVAL;
++
+ hdr = (struct prestera_fw_header *)fw->bin->data;
+
+ magic = be32_to_cpu(hdr->magic_number);
+--
+2.53.0
+
--- /dev/null
+From 5a6fafeeaba1a57577cc0e4cc8dfeebbd936dbd5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 22:18:30 +0200
+Subject: net: qrtr: ns: Raise lookup limit to 128
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Łukasz Patron <priv.luk@gmail.com>
+
+[ Upstream commit 7fc1c937b6b37c77df4ba374c37435ab06a2e945 ]
+
+Current limit of 64 is not enough for Sony Xperia 10 VII (SM6475).
+
+After merging v6.6.142 into a downstream AOSP device, it's stuck on
+boot animation and following log spam can be observed in dmesg:
+
+E qrtr : ctrl_cmd_new_lookup(): QRTR client node exceeds max lookup limit!
+E qrtr : qrtr_ns_worker(): failed while handling packet from 1:16600
+
+No idea why it needs more than 64 client lookups, but it appears to
+work fine with 128 as it did when there were no limits.
+
+I don't really have a good way to investigate what it needs all
+these lookups for as most of the userspace is closed source.
+
+Fixes: 5640227d9a21 ("net: qrtr: ns: Limit the maximum number of lookups")
+Signed-off-by: Łukasz Patron <priv.luk@gmail.com>
+Link: https://patch.msgid.link/20260804201919.1148015-1-priv.luk@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/ns.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c
+index 5220529a4c62d..4df5f0a9b7419 100644
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -77,7 +77,7 @@ struct qrtr_node {
+ */
+ #define QRTR_NS_MAX_NODES 512
+ #define QRTR_NS_MAX_SERVERS 256
+-#define QRTR_NS_MAX_LOOKUPS 64
++#define QRTR_NS_MAX_LOOKUPS 128
+
+ static u16 node_count;
+
+--
+2.53.0
+
--- /dev/null
+From 5892613efbacc66ce4c0cfc3c20061a250920a47 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 15:20:48 +0000
+Subject: net: remove WARN_ON_ONCE() from sk_mc_loop()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit b8a39a09ae4eaae04309e1e38ed6a1101d967496 ]
+
+sk_mc_loop() can be called for sockets that are neither AF_INET
+nor AF_INET6 (e.g. AF_PACKET sockets when sending packets via raw/packet
+socket over virtual devices such as VRF or ipvlan).
+
+In such cases, sk_family is not AF_INET/AF_INET6 and sk_mc_loop() falls
+through the switch statement and triggers WARN_ON_ONCE(1).
+
+Non-INET sockets do not support IP_MULTICAST_LOOP or IPV6_MULTICAST_LOOP
+options, so loopback should default to true without generating a warning.
+
+Fixes: f60e5990d9c1 ("ipv6: protect skb->sk accesses from recursive dereference inside the stack")
+Reported-by: syzbot+22c3218a6fa219e47321@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/6a72024c.13623e66.bdc14.0019.GAE@google.com/T/#u
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260804152048.2134341-1-edumazet@google.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/sock.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/net/core/sock.c b/net/core/sock.c
+index 5f79f0b78321c..2a701e0b052b7 100644
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -772,7 +772,6 @@ bool sk_mc_loop(struct sock *sk)
+ return inet6_sk(sk)->mc_loop;
+ #endif
+ }
+- WARN_ON_ONCE(1);
+ return true;
+ }
+ EXPORT_SYMBOL(sk_mc_loop);
+--
+2.53.0
+
--- /dev/null
+From be9bc8cf78e82986787cd3d488a0e3ff2962688b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 05:44:11 -0400
+Subject: net/sched: cls_route: fix fastmap use-after-free on filter
+
+From: Jamal Hadi Salim <jhs@mojatatu.com>
+
+[ Upstream commit 47d7f7051253bdc02b1d245d87e38f16d31a74df ]
+
+The route4 classifier maintains a 16-slot fastmap cache that stores raw
+struct route4_filter pointers indexed by (id, iif). The reader
+(route4_classify) populates this cache via route4_set_fastmap() for every
+classified packet that hits a filter. The writer (route4_delete,
+route4_change) clears the cache via route4_reset_fastmap() before
+RCU-deferred kfree of the filter.
+
+This creates a UAF race:
+ 1. Reader walks the RCU-protected bucket chain, finds filter f
+ 2. Writer unlinks f, calls route4_reset_fastmap(), then tcf_queue_work()
+ 3. Reader calls route4_set_fastmap() and writes f into the cache
+ *after* the writer's reset, caching a pointer about to be freed
+ 4. After the RCU grace period, kfree(f) executes
+ 5. Next classified packet on the same (id, iif) tuple hits the stale
+ fastmap entry and reads f->res from freed memory
+
+Reproduced with an mdelay(100) accelerator in route4_set_fastmap() and a
+concurrent add/delete stress test (provided by both zdi and Santosh).
+Both triggered KASAN slab-use-after-free reports in the route4 fastmap
+paths.
+
+Fix:
+Introduce a per-filter boolean dying flag to suppress stale fastmap
+republishing by in-flight readers.
+
+Fixes: 1109c00547fc ("net: sched: RCU cls_route")
+Reported-by: zdi-disclosures@trendmicro.com
+Reported-by: Santosh Kalluri <santosh.kalluri129@gmail.com>
+Suggested-by: Paolo Abeni <pabeni@redhat.com>
+Tested-by: Victor Nogueira <victor@mojatatu.com>
+Tested-by: Santosh Kalluri <santosh.kalluri129@gmail.com>
+Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260729094411.46257-1-jhs@mojatatu.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_route.c | 35 ++++++++++++++++++++++++++---------
+ 1 file changed, 26 insertions(+), 9 deletions(-)
+
+diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
+index 306188bf2d1ff..6c205fcb65475 100644
+--- a/net/sched/cls_route.c
++++ b/net/sched/cls_route.c
+@@ -51,6 +51,7 @@ struct route4_filter {
+ struct tcf_result res;
+ struct tcf_exts exts;
+ u32 handle;
++ bool dying;
+ struct route4_bucket *bkt;
+ struct tcf_proto *tp;
+ struct rcu_work rwork;
+@@ -65,9 +66,11 @@ static inline int route4_fastmap_hash(u32 id, int iif)
+
+ static DEFINE_SPINLOCK(fastmap_lock);
+ static void
+-route4_reset_fastmap(struct route4_head *head)
++route4_reset_fastmap(struct route4_head *head, struct route4_filter *f)
+ {
+ spin_lock_bh(&fastmap_lock);
++ if (f)
++ f->dying = true;
+ memset(head->fastmap, 0, sizeof(head->fastmap));
+ spin_unlock_bh(&fastmap_lock);
+ }
+@@ -80,9 +83,11 @@ route4_set_fastmap(struct route4_head *head, u32 id, int iif,
+
+ /* fastmap updates must look atomic to aling id, iff, filter */
+ spin_lock_bh(&fastmap_lock);
+- head->fastmap[h].id = id;
+- head->fastmap[h].iif = iif;
+- head->fastmap[h].filter = f;
++ if (f == ROUTE4_FAILURE || !f->dying) {
++ head->fastmap[h].id = id;
++ head->fastmap[h].iif = iif;
++ head->fastmap[h].filter = f;
++ }
+ spin_unlock_bh(&fastmap_lock);
+ }
+
+@@ -295,6 +300,13 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
+ next = rtnl_dereference(f->next);
+ RCU_INIT_POINTER(b->ht[h2], next);
+ tcf_unbind_filter(tp, &f->res);
++ /* Mark the filter dying under fastmap_lock so
++ * any in-flight reader that still holds it
++ * will skip the republish in route4_set_fastmap().
++ */
++ spin_lock_bh(&fastmap_lock);
++ f->dying = true;
++ spin_unlock_bh(&fastmap_lock);
+ if (tcf_exts_get_net(&f->exts))
+ route4_queue_work(f);
+ else
+@@ -305,6 +317,11 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
+ kfree_rcu(b, rcu);
+ }
+ }
++
++ /* All filters are unlinked and marked dying, so no in-flight
++ * reader can republish a stale entry after this reset.
++ */
++ route4_reset_fastmap(head, NULL);
+ kfree_rcu(head, rcu);
+ }
+
+@@ -332,11 +349,11 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,
+ /* unlink it */
+ RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
+
+- /* Remove any fastmap lookups that might ref filter
+- * notice we unlink'd the filter so we can't get it
+- * back in the fastmap.
++ /* Clear any fastmap entries that may ref this filter and
++ * mark it dying so in-flight readers can't republish it
++ * after the reset.
+ */
+- route4_reset_fastmap(head);
++ route4_reset_fastmap(head, f);
+
+ /* Delete it */
+ tcf_unbind_filter(tp, &f->res);
+@@ -551,7 +568,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
+ }
+ }
+
+- route4_reset_fastmap(head);
++ route4_reset_fastmap(head, fold);
+ *arg = f;
+ if (fold) {
+ tcf_unbind_filter(tp, &fold->res);
+--
+2.53.0
+
--- /dev/null
+From 7968377f51e1c15ef1ef879abb10af5107cffa19 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 21:14:16 +0200
+Subject: net/sched: sch_cake: drop WARN_ON(1) for malformed packets in ACK
+ filter
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Toke Høiland-Jørgensen <toke@toke.dk>
+
+[ Upstream commit 2a33516f9ef59ad11844d4fc152f889449b5daf3 ]
+
+The sch_cake ACK filter parses packets to find the TCP header and filter
+duplicated ACKs if the flow is backlogged. The parsing code contains a
+WARN_ON(1) which can be triggered by a malformed IP header in certain
+cases. Depending on the system configuration, this leads either to
+either spamming dmesg with warnings, or a panic if panic_on_warn is set.
+
+The code already correctly skips the offending packet in the branch that
+triggers the warning, so the WARN_ON itself doesn't really serve any
+purpose. So just drop it altogether to avoid the inconvenient side
+effects.
+
+Fixes: 8b7138814f29 ("sch_cake: Add optional ACK filter")
+Reported-by: Zhiling Zou <zhilinz@nebusec.ai>
+Reported-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
+Link: https://patch.msgid.link/20260729191417.45665-1-toke@toke.dk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_cake.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c
+index e210a676dc340..1c6f2c623939f 100644
+--- a/net/sched/sch_cake.c
++++ b/net/sched/sch_cake.c
+@@ -1281,7 +1281,6 @@ static struct sk_buff *cake_ack_filter(struct cake_sched_data *q,
+
+ seglen = ntohs(ipv6h_check->payload_len);
+ } else {
+- WARN_ON(1); /* shouldn't happen */
+ continue;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 56572156102cd788fca51de6d955e3a01526b988 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:01:53 +0200
+Subject: net/smc: fix qentry overwrite for CONFIRM_LINK and ADD_LINK_CONT in
+ smc_llc_event_handler()
+
+From: Mahanta Jambigi <mjambigi@linux.ibm.com>
+
+[ Upstream commit 976245094925bab9bc39366b2e9ab44ffcde61d0 ]
+
+The SMC_LLC_CONFIRM_LINK / SMC_LLC_ADD_LINK_CONT branch in
+smc_llc_event_handler() stores an incoming qentry into the local LLC flow
+without first checking whether a qentry is already pending. If a malicious or
+buggy peer sends a second CONFIRM_LINK or ADD_LINK_CONT request while a flow is
+active and flow->qentry is already set, smc_llc_flow_qentry_set() overwrites the
+pointer without freeing the previous allocation, leaking one kmalloc-96 object
+per spurious message.
+
+The sibling SMC_LLC_DELETE_LINK branch already has the correct !flow->qentry
+guard. Apply the same guard to the CONFIRM_LINK/ADD_LINK_CONT branch so that a
+duplicate message when qentry is already occupied falls through to break and is
+freed by the kfree(qentry) at the out: label, rather than silently leaking the
+existing allocation.
+
+The response direction (smc_llc_rx_response()) is unaffected: it already guards
+with flow->qentry at the equivalent site and drops duplicate responses
+correctly.
+
+Fixes: 0fb0b02bd6fd ("net/smc: adapt SMC client code to use the LLC flow")
+Signed-off-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
+Reviewed-by: Hidayath Khan <hidayath@linux.ibm.com>
+Reviewed-by: Sidraya Jayagond <sidraya@linux.ibm.com>
+Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
+Link: https://patch.msgid.link/20260729130153.970800-1-mjambigi@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/smc_llc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c
+index fcb24a0ccf761..761515b590f20 100644
+--- a/net/smc/smc_llc.c
++++ b/net/smc/smc_llc.c
+@@ -1901,7 +1901,8 @@ static void smc_llc_event_handler(struct smc_llc_qentry *qentry)
+ return;
+ case SMC_LLC_CONFIRM_LINK:
+ case SMC_LLC_ADD_LINK_CONT:
+- if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) {
++ if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE &&
++ !lgr->llc_flow_lcl.qentry) {
+ /* a flow is waiting for this message */
+ smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry);
+ wake_up(&lgr->llc_msg_waiter);
+--
+2.53.0
+
--- /dev/null
+From 2684d3671434507c511aa4a421f18f8aafdb657b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 09:07:01 +0200
+Subject: net/smc: fix TOCTOU race between smc_listen_out() and listener close
+
+From: Sidraya Jayagond <sidraya@linux.ibm.com>
+
+[ Upstream commit 185a4caeecabc150106deda1da170b09f2ad803f ]
+
+smc_listen_out() reads lsmc->sk.sk_state without the listener lock,
+then acquires lock_sock_nested() only after the check passes. This
+opens a window where smc_close_active() can transition the listener
+to SMC_CLOSED, call smc_close_cleanup_listen() to drain the accept
+queue, and release the lock, all between the lockless read and the
+delayed lock acquisition:
+
+ smc_listen_work (smc_hs_wq) smc_close_active()
+ ------------------------------- -------------------------
+ release_sock(child)
+ if (sk_state == SMC_LISTEN) TRUE
+ lock_sock(listener)
+ sk_state = SMC_CLOSED
+ smc_close_cleanup_listen()
+ release_sock(listener)
+ flush_work(tcp_listen_work)
+ lock_sock_nested(listener)
+ smc_accept_enqueue(listener, child) /* child enqueued on dead listener */
+
+smc_close_active() flushes only tcp_listen_work. Work items already
+dispatched onto smc_hs_wq for the CLC handshake continue running
+unguarded. smc_accept_enqueue() takes a sock_hold() on the child that
+is never released, so the child smc_sock, its clcsock, and the
+reference all leak. A remote peer that opens TCP connections while the
+server calls close() can exhaust kernel memory.
+
+Move lock_sock_nested() to before the sk_state check so that the test
+and the enqueue are atomic under the listener lock.
+
+Fixes: fd57770dd198 ("net/smc: wait for pending work before clcsock release_sock")
+Reviewed-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
+Signed-off-by: Sidraya Jayagond <sidraya@linux.ibm.com>
+Reviewed-by: Breno Leitao <leitao@debian.org>
+Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
+Link: https://patch.msgid.link/20260803070701.126339-1-sidraya@linux.ibm.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/af_smc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
+index ae97f47f4fda0..d069e5b156e51 100644
+--- a/net/smc/af_smc.c
++++ b/net/smc/af_smc.c
+@@ -1874,11 +1874,12 @@ static void smc_listen_out(struct smc_sock *new_smc)
+ atomic_dec(&lsmc->queued_smc_hs);
+
+ release_sock(newsmcsk); /* lock in smc_listen_work() */
++ lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
+ if (lsmc->sk.sk_state == SMC_LISTEN) {
+- lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
+ smc_accept_enqueue(&lsmc->sk, newsmcsk);
+ release_sock(&lsmc->sk);
+ } else { /* no longer listening */
++ release_sock(&lsmc->sk);
+ smc_close_non_accepted(newsmcsk);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From fc31608ca42507671304f132c77a0d941e95556d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 14:38:50 +0000
+Subject: net: thunderbolt: Tear down DMA paths before stopping the rings
+
+From: Fan XinRan <shinjiangjiang@gmail.com>
+
+[ Upstream commit 68bf02b6b4ad3f748c6db71fd77b6c0402d252f4 ]
+
+tbnet_tear_down() stops both rings and frees their frame buffers before
+calling tb_xdomain_disable_paths(). tb_ring_stop() zeroes the ring's
+descriptor base and tbnet_free_buffers() unmaps and frees the pages the
+frames sit in, so by the time __tb_path_deactivate_hop() polls the hop's
+'pending' bit, anything still in flight has nowhere to drain to.
+
+The teardown sequence has been in this order since the driver was added.
+The setup path has not: commit ff7cd07f3064 ("net: thunderbolt: Enable
+DMA paths only after rings are enabled") moved the path enable to the end
+of tbnet_connected_work() and documented why:
+
+ /* Both logins successful so enable the rings, high-speed DMA
+ * paths and start the network device queue.
+ *
+ * Note we enable the DMA paths last to make sure we have primed
+ * the Rx ring before any incoming packets are allowed to
+ * arrive.
+ */
+
+Teardown was never updated to match, so the rings and the paths now come
+down in the same order they go up instead of in reverse.
+
+On an ASMedia ASM4242 host router the 'pending' bit then never clears:
+every teardown burns the full 500 ms timeout and
+__tb_path_deactivate_hop() returns -ETIMEDOUT. Raising the timeout to
+5 s does not help, so the hop is not slow to drain, it never drains
+at all.
+
+The failure is invisible above the thunderbolt core.
+__tb_path_deactivate_hops() is void and only calls tb_port_warn();
+tb_path_deactivate(), tb_tunnel_deactivate() and
+__tb_disconnect_xdomain_paths() are void as well, and
+tb_disconnect_xdomain_paths() ends in an unconditional "return 0". So
+tb_xdomain_disable_paths() reports success and the netdev_warn() below
+it never fires. Repeated teardowns eventually take the XDomain control
+channel down, after which the peer node is gone and only a power cycle
+brings the controller back.
+
+Deactivating the paths first fixes it. Measured with kretprobes on a
+stock v6.17 tree with no other patches applied, on a link that was up
+and had just carried traffic:
+
+ before: __tb_path_deactivate_hop() returns 0 for the first hop, then
+ -ETIMEDOUT for the second 500335 us later
+ after: 0 for both, 525 us apart
+
+Alternating the two orderings ABBA over three load levels, four
+teardowns per arm: every teardown failed before the change (21 of 21
+that ran), none failed after (0 of 24). The before arms ran short
+because the link died partway through. The same split shows up when
+the interface is enslaved to a bond instead of just brought down, which
+is how I ran into this in the first place. Throughput and latency after
+the change are unchanged.
+
+Hosts whose routers drain the hop despite the stale descriptor base see
+no functional difference, since the paths end up deactivated either way.
+
+Fixes: e69b6c02b4c3 ("net: Add support for networking over Thunderbolt cable")
+Signed-off-by: Fan XinRan <shinjiangjiang@gmail.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Link: https://patch.msgid.link/20260803-b4-tbnet-teardown-v2-1-27de6a13ca2d@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/thunderbolt.c | 20 +++++++++++++++-----
+ 1 file changed, 15 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/thunderbolt.c b/drivers/net/thunderbolt.c
+index 6f01089e6f47d..a14655b795cca 100644
+--- a/drivers/net/thunderbolt.c
++++ b/drivers/net/thunderbolt.c
+@@ -379,11 +379,16 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)
+ break;
+ }
+
+- tb_ring_stop(net->rx_ring.ring);
+- tb_ring_stop(net->tx_ring.ring);
+- tbnet_free_buffers(&net->rx_ring);
+- tbnet_free_buffers(&net->tx_ring);
+-
++ /* Tear the paths down before stopping the rings. This mirrors
++ * tbnet_connected_work(), which enables the paths last so the
++ * Rx ring is primed before packets can arrive. Stopping a
++ * ring zeroes its descriptor base and tbnet_free_buffers()
++ * unmaps and frees the frame buffers, leaving anything still
++ * in flight with nowhere to drain to;
++ * __tb_path_deactivate_hop() then waits for the hop's
++ * 'pending' bit, which on some host routers never clears in
++ * that state.
++ */
+ ret = tb_xdomain_disable_paths(net->xd,
+ net->local_transmit_path,
+ net->tx_ring.ring->hop,
+@@ -392,6 +397,11 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)
+ if (ret)
+ netdev_warn(net->dev, "failed to disable DMA paths\n");
+
++ tb_ring_stop(net->rx_ring.ring);
++ tb_ring_stop(net->tx_ring.ring);
++ tbnet_free_buffers(&net->rx_ring);
++ tbnet_free_buffers(&net->tx_ring);
++
+ tb_xdomain_release_in_hopid(net->xd, net->remote_transmit_path);
+ net->remote_transmit_path = 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From b2476013c836f66a0a3414150d4c9c6c6723724d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 20:38:50 +0200
+Subject: netfilter: ipset: switch ext_size to atomic64_t
+
+From: Jozsef Kadlecsik <kadlec@netfilter.org>
+
+[ Upstream commit 712a6f545c359b427daa9a5a782e30d2f8331e25 ]
+
+The hash types do not acquire set->lock, they use 'region locking' where
+only part of the hash table is locked. Parallel inserts and deletes are
+possible and CPUs can race on ->ext_size update. Switch to atomic64_t.
+
+This leaves another bug unresolved: there still can be a race on
+comment extension re-init. This will be handled in a later commit
+when converting to rhashtable backend.
+
+Fixes: f66ee0410b1c ("netfilter: ipset: Fix "INFO: rcu detected stall in hash_xxx" reports")
+Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/netfilter/ipset/ip_set.h | 2 +-
+ net/netfilter/ipset/ip_set_bitmap_gen.h | 4 ++--
+ net/netfilter/ipset/ip_set_core.c | 6 +++---
+ net/netfilter/ipset/ip_set_hash_gen.h | 2 +-
+ net/netfilter/ipset/ip_set_list_set.c | 4 ++--
+ 5 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
+index d82413e6098a7..b2ee80b4b0d39 100644
+--- a/include/linux/netfilter/ipset/ip_set.h
++++ b/include/linux/netfilter/ipset/ip_set.h
+@@ -273,7 +273,7 @@ struct ip_set {
+ /* Number of elements (vs timeout) */
+ u32 elements;
+ /* Size of the dynamic extensions (vs timeout) */
+- size_t ext_size;
++ atomic64_t ext_size;
+ /* Element data size */
+ size_t dsize;
+ /* Offsets to extensions in elements */
+diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h
+index 9523104a90da4..40f0383883f9d 100644
+--- a/net/netfilter/ipset/ip_set_bitmap_gen.h
++++ b/net/netfilter/ipset/ip_set_bitmap_gen.h
+@@ -75,7 +75,7 @@ mtype_flush(struct ip_set *set)
+ mtype_ext_cleanup(set);
+ bitmap_zero(map->members, map->elements);
+ set->elements = 0;
+- set->ext_size = 0;
++ atomic64_set(&set->ext_size, 0);
+ }
+
+ /* Calculate the actual memory size of the set data */
+@@ -91,7 +91,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
+ {
+ const struct mtype *map = set->data;
+ struct nlattr *nested;
+- size_t memsize = mtype_memsize(map, set->dsize) + set->ext_size;
++ size_t memsize = mtype_memsize(map, set->dsize) + atomic64_read(&set->ext_size);
+
+ nested = nla_nest_start(skb, IPSET_ATTR_DATA);
+ if (!nested)
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index 1d6579358f9ba..7601e4ca02775 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -350,7 +350,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
+ size_t len = ext->comment ? strlen(ext->comment) : 0;
+
+ if (unlikely(c)) {
+- set->ext_size -= sizeof(*c) + strlen(c->str) + 1;
++ atomic64_sub(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
+ rcu_assign_pointer(comment->c, NULL);
+ kfree_rcu(c, rcu);
+ }
+@@ -362,7 +362,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
+ if (unlikely(!c))
+ return;
+ strscpy(c->str, ext->comment, len + 1);
+- set->ext_size += sizeof(*c) + strlen(c->str) + 1;
++ atomic64_add(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
+ rcu_assign_pointer(comment->c, c);
+ }
+ EXPORT_SYMBOL_GPL(ip_set_init_comment);
+@@ -392,7 +392,7 @@ ip_set_comment_free(struct ip_set *set, void *ptr)
+ c = rcu_dereference_protected(comment->c, 1);
+ if (unlikely(!c))
+ return;
+- set->ext_size -= sizeof(*c) + strlen(c->str) + 1;
++ atomic64_sub(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
+ rcu_assign_pointer(comment->c, NULL);
+ kfree_rcu(c, rcu);
+ }
+diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
+index de9f291ff8c28..6588571648ead 100644
+--- a/net/netfilter/ipset/ip_set_hash_gen.h
++++ b/net/netfilter/ipset/ip_set_hash_gen.h
+@@ -1276,7 +1276,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
+ rcu_read_lock_bh();
+ t = rcu_dereference_bh(h->table);
+ mtype_ext_size(set, &elements, &ext_size);
+- memsize = mtype_ahash_memsize(h, t) + ext_size + set->ext_size;
++ memsize = mtype_ahash_memsize(h, t) + ext_size + atomic64_read(&set->ext_size);
+ htable_bits = t->htable_bits;
+ rcu_read_unlock_bh();
+
+diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
+index 7d1ba6ad514f5..bc37bc59e2828 100644
+--- a/net/netfilter/ipset/ip_set_list_set.c
++++ b/net/netfilter/ipset/ip_set_list_set.c
+@@ -421,7 +421,7 @@ list_set_flush(struct ip_set *set)
+ list_for_each_entry_safe(e, n, &map->members, list)
+ list_set_del(set, e);
+ set->elements = 0;
+- set->ext_size = 0;
++ atomic64_set(&set->ext_size, 0);
+ }
+
+ static void
+@@ -455,7 +455,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
+ {
+ const struct list_set *map = set->data;
+ struct nlattr *nested;
+- size_t memsize = list_set_memsize(map, set->dsize) + set->ext_size;
++ size_t memsize = list_set_memsize(map, set->dsize) + atomic64_read(&set->ext_size);
+
+ nested = nla_nest_start(skb, IPSET_ATTR_DATA);
+ if (!nested)
+--
+2.53.0
+
--- /dev/null
+From a637182c814db7b4aa588fbed7ce9f7139d49aa9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 30 Jun 2026 14:31:00 -0400
+Subject: NFS: Pin the 'struct nfs_server' during a FREE_STATEID call
+
+From: Anna Schumaker <anna.schumaker@hammerspace.com>
+
+[ Upstream commit cf616096a0f3a2b60f7d68b6b39674a6867ded9c ]
+
+Dan Aloni reports that he was able to hit a use-after-free bug if a
+FREE_STATEID operation gets delayed for whatever reason. Fix this by
+bumping the refcount of the 'struct nfs_server' object for the duration
+of the FREE_STATEID so it doesn't get cleaned up from underneath us
+while operations are still in flight.
+
+Reported-by: Dan Aloni <dan.aloni@vastdata.com>
+Fixes: 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call")
+Tested-by: Dan Aloni <dan.aloni@vastdata.com>
+Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/nfs4proc.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index 8258bce82e5bc..9f352f1a6eb1e 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -10388,6 +10388,7 @@ static void nfs41_free_stateid_release(void *calldata)
+ struct nfs_free_stateid_data *data = calldata;
+ struct nfs_client *clp = data->server->nfs_client;
+
++ nfs_sb_deactive(data->server->super);
+ nfs_put_client(clp);
+ kfree(calldata);
+ }
+@@ -10429,6 +10430,10 @@ static int nfs41_free_stateid(struct nfs_server *server,
+
+ if (!refcount_inc_not_zero(&clp->cl_count))
+ return -EIO;
++ if (!nfs_sb_active(server->super)) {
++ nfs_put_client(clp);
++ return -EIO;
++ }
+
+ nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
+ &task_setup.rpc_client, &msg);
+--
+2.53.0
+
--- /dev/null
+From 3e6e6c7428efd2361b315e4d25ab7d9f46999d75 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Apr 2024 18:40:09 -0500
+Subject: regulator: devres: add API for reference voltage supplies
+
+From: David Lechner <dlechner@baylibre.com>
+
+[ Upstream commit b250c20b64290808aa4b5cc6d68819a7ee28237f ]
+
+A common use case for regulators is to supply a reference voltage to an
+analog input or output device. This adds a new devres API to get,
+enable, and get the voltage in a single call. This allows eliminating
+boilerplate code in drivers that use reference supplies in this way.
+
+Signed-off-by: David Lechner <dlechner@baylibre.com>
+Link: https://lore.kernel.org/r/20240429-regulator-get-enable-get-votlage-v2-1-b1f11ab766c1@baylibre.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: fddb5ceaf901 ("hwmon: (ads7828) Fix external VREF regulator handling")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../driver-api/driver-model/devres.rst | 1 +
+ drivers/regulator/devres.c | 59 +++++++++++++++++++
+ include/linux/regulator/consumer.h | 7 +++
+ 3 files changed, 67 insertions(+)
+
+diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst
+index 56082265e8e50..11234c12718d1 100644
+--- a/Documentation/driver-api/driver-model/devres.rst
++++ b/Documentation/driver-api/driver-model/devres.rst
+@@ -413,6 +413,7 @@ REGULATOR
+ devm_regulator_bulk_put()
+ devm_regulator_get()
+ devm_regulator_get_enable()
++ devm_regulator_get_enable_read_voltage()
+ devm_regulator_get_enable_optional()
+ devm_regulator_get_exclusive()
+ devm_regulator_get_optional()
+diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c
+index 5c7ff9b3e8a79..6e8d6dc729cef 100644
+--- a/drivers/regulator/devres.c
++++ b/drivers/regulator/devres.c
+@@ -145,6 +145,65 @@ struct regulator *devm_regulator_get_optional(struct device *dev,
+ }
+ EXPORT_SYMBOL_GPL(devm_regulator_get_optional);
+
++/**
++ * devm_regulator_get_enable_read_voltage - Resource managed regulator get and
++ * enable that returns the voltage
++ * @dev: device to supply
++ * @id: supply name or regulator ID.
++ *
++ * Get and enable regulator for duration of the device life-time.
++ * regulator_disable() and regulator_put() are automatically called on driver
++ * detach. See regulator_get_optional(), regulator_enable(), and
++ * regulator_get_voltage() for more information.
++ *
++ * This is a convenience function for supplies that provide a reference voltage
++ * where the consumer driver just needs to know the voltage and keep the
++ * regulator enabled.
++ *
++ * In cases where the supply is not strictly required, callers can check for
++ * -ENODEV error and handle it accordingly.
++ *
++ * Returns: voltage in microvolts on success, or an error code on failure.
++ */
++int devm_regulator_get_enable_read_voltage(struct device *dev, const char *id)
++{
++ struct regulator *r;
++ int ret;
++
++ /*
++ * Since we need a real voltage, we use devm_regulator_get_optional()
++ * rather than getting a dummy regulator with devm_regulator_get() and
++ * then letting regulator_get_voltage() fail with -EINVAL. This way, the
++ * caller can handle the -ENODEV error code if needed instead of the
++ * ambiguous -EINVAL.
++ */
++ r = devm_regulator_get_optional(dev, id);
++ if (IS_ERR(r))
++ return PTR_ERR(r);
++
++ ret = regulator_enable(r);
++ if (ret)
++ goto err_regulator_put;
++
++ ret = devm_add_action_or_reset(dev, regulator_action_disable, r);
++ if (ret)
++ goto err_regulator_put;
++
++ ret = regulator_get_voltage(r);
++ if (ret < 0)
++ goto err_release_action;
++
++ return 0;
++
++err_release_action:
++ devm_release_action(dev, regulator_action_disable, r);
++err_regulator_put:
++ devm_regulator_put(r);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(devm_regulator_get_enable_read_voltage);
++
+ static int devm_regulator_match(struct device *dev, void *res, void *data)
+ {
+ struct regulator **r = res;
+diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
+index 60bc7e143869b..8d3afff87b6e3 100644
+--- a/include/linux/regulator/consumer.h
++++ b/include/linux/regulator/consumer.h
+@@ -209,6 +209,7 @@ struct regulator *__must_check devm_regulator_get_optional(struct device *dev,
+ const char *id);
+ int devm_regulator_get_enable(struct device *dev, const char *id);
+ int devm_regulator_get_enable_optional(struct device *dev, const char *id);
++int devm_regulator_get_enable_read_voltage(struct device *dev, const char *id);
+ void regulator_put(struct regulator *regulator);
+ void devm_regulator_put(struct regulator *regulator);
+
+@@ -372,6 +373,12 @@ static inline int devm_regulator_get_enable_optional(struct device *dev,
+ return 0;
+ }
+
++static inline int devm_regulator_get_enable_read_voltage(struct device *dev,
++ const char *id)
++{
++ return -ENODEV;
++}
++
+ static inline struct regulator *__must_check
+ regulator_get_optional(struct device *dev, const char *id)
+ {
+--
+2.53.0
+
--- /dev/null
+From b027f0b01039c63870bf12cd123f200908a3738e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 12:29:48 +0000
+Subject: Revert "net: thunderbolt: Enable end-to-end flow control also in
+ transmit"
+
+From: Fan Ye <fy15309206903@gmail.com>
+
+[ Upstream commit 1881f2efbf7f78dc0a79a387b29fde6ff56d3731 ]
+
+This reverts commit a8065af3346ebd7c76ebc113451fb3ba94cf7769.
+
+Per the USB4 spec, a Transmit Descriptor Ring with E2E flow control
+disabled does not require any credits to be available before the Host
+Interface Adapter Layer transmits a tunneled packet from it. Once E2E is
+enabled on that ring the controller must first obtain end-to-end
+credits.
+
+The ASMedia ASM4242 USB4 host router (PCI 1b21:2425) never delivers
+those credits. The controller does accept the configuration: reading the
+ring OPTIONS register back right after tb_ring_start() returns exactly
+what was written, including RING_FLAG_E2E_FLOW_CONTROL (bit 28) and the
+E2E HopID field. No credit ever arrives though, so the Tx ring's
+hardware consumer index never advances and the link carries no traffic
+at all.
+
+Measured on two hosts connected point to point, onboard ASM4242 on MSI
+X870E and X870, v6.17, stock drivers/net/thunderbolt/main.c with only
+this revert applied on top:
+
+ before: 100% packet loss to the peer; thunderbolt0 is up and the
+ XDomain handshake completes ("new host found"), but iperf3
+ fails with "No route to host" once the neighbour entry
+ expires
+ after: 0% packet loss, 0.28 ms RTT; iperf3 4.21 Gb/s one way and
+ 5.17 Gb/s the other (5 runs each, stddev <= 0.02), 1
+ retransmit in 10 s
+
+An instrumented build additionally showed a frozen-Tx-consumer watchdog
+firing ~30k times in a 10 s window before this change.
+
+Rx-side E2E is not touched by this revert, so peers that do return
+credits keep receive-side flow control.
+
+ASMedia does not look like an isolated case. The out-of-tree
+thunderbolt-ibverbs project disables native E2E on AMD NHI by default,
+noting that "Strix Halo has reproduced TX completion wedges with
+multiple native E2E rings active" -- the same failure mode, on a
+different vendor. Since the driver has no way to tell in advance which
+host router returns the credits, going back to the previous behaviour
+looks safer than adding a quirk per affected part; Tx-side E2E can be
+reintroduced as an opt-in for controllers that are known to implement
+the credit return.
+
+Note that the reverted commit was not fixing a reported problem, it was
+derived from the spec wording alone, so this revert is not expected to
+regress a known workload. Cc'ing the original author in case there was
+one.
+
+Fixes: a8065af3346e ("net: thunderbolt: Enable end-to-end flow control also in transmit")
+Cc: zhangjianrong <zhangjianrong5@huawei.com>
+Signed-off-by: Fan Ye <fy15309206903@gmail.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Link: https://patch.msgid.link/20260727123002.25225-1-fy15309206903@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/thunderbolt.c | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/thunderbolt.c b/drivers/net/thunderbolt.c
+index ef13aa36e55e8..6f01089e6f47d 100644
+--- a/drivers/net/thunderbolt.c
++++ b/drivers/net/thunderbolt.c
+@@ -884,12 +884,8 @@ static int tbnet_open(struct net_device *dev)
+
+ netif_carrier_off(dev);
+
+- flags = RING_FLAG_FRAME;
+- /* Only enable full E2E if the other end supports it too */
+- if (tbnet_e2e && net->svc->prtcstns & TBNET_E2E)
+- flags |= RING_FLAG_E2E;
+-
+- ring = tb_ring_alloc_tx(xd->tb->nhi, -1, TBNET_RING_SIZE, flags);
++ ring = tb_ring_alloc_tx(xd->tb->nhi, -1, TBNET_RING_SIZE,
++ RING_FLAG_FRAME);
+ if (!ring) {
+ netdev_err(dev, "failed to allocate Tx ring\n");
+ return -ENOMEM;
+@@ -908,6 +904,11 @@ static int tbnet_open(struct net_device *dev)
+ sof_mask = BIT(TBIP_PDF_FRAME_START);
+ eof_mask = BIT(TBIP_PDF_FRAME_END);
+
++ flags = RING_FLAG_FRAME;
++ /* Only enable full E2E if the other end supports it too */
++ if (tbnet_e2e && net->svc->prtcstns & TBNET_E2E)
++ flags |= RING_FLAG_E2E;
++
+ ring = tb_ring_alloc_rx(xd->tb->nhi, -1, TBNET_RING_SIZE, flags,
+ net->tx_ring.ring->hop, sof_mask,
+ eof_mask, tbnet_start_poll, net);
+--
+2.53.0
+
--- /dev/null
+From 879e9ab6a6e3aff68f8f71bf31158ef05ca48427 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 11:18:40 -0400
+Subject: sctp: clear control chunk transport if it is being removed
+
+From: Xin Long <lucien.xin@gmail.com>
+
+[ Upstream commit c9158ceaf27780ef64534ad72f44ffde3f8ccc49 ]
+
+sctp_make_heartbeat_ack() caches the destination transport in
+chunk->transport without taking a reference. When src_out_of_asoc_ok is
+enabled, the HEARTBEAT ACK may remain queued on control_chunk_list instead
+of being transmitted immediately.
+
+If the peer transport is removed while the chunk is still queued,
+sctp_assoc_rm_peer() drops the transport and schedules it for RCU freeing,
+but only clears cached transport pointers in out_chunk_list. The queued
+control chunk therefore retains a dangling transport pointer.
+
+Once an ASCONF_ACK clears the suppression and the queued control chunk is
+transmitted, SCTP dereferences the stale transport pointer, leading to a
+use-after-free.
+
+Fix this by also clearing chunk->transport for queued control chunks in
+control_chunk_list when removing the transport.
+
+Fixes: 8a07eb0a50ae ("sctp: Add ASCONF operation on the single-homed host")
+Reported-by: Daniele Linguaglossa <danielelinguaglossa@gmail.com>
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/7e1168cb722132152a29d47e5eafaeac4a3bf6f3.1785943120.git.lucien.xin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/associola.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/net/sctp/associola.c b/net/sctp/associola.c
+index 4dd36c8375507..4a79e855c85cd 100644
+--- a/net/sctp/associola.c
++++ b/net/sctp/associola.c
+@@ -575,6 +575,10 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
+ if (ch->transport == peer)
+ ch->transport = NULL;
+
++ list_for_each_entry(ch, &asoc->outqueue.control_chunk_list, list)
++ if (ch->transport == peer)
++ ch->transport = NULL;
++
+ asoc->peer.transport_count--;
+
+ sctp_ulpevent_notify_peer_addr_change(peer, SCTP_ADDR_REMOVED, 0);
+--
+2.53.0
+
--- /dev/null
+From 65c7b65748a0675ca35dad92c4acd80bebd5063e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 10:55:14 +0800
+Subject: sctp: fix addip_serial increment on ASCONF_ACK allocation failure
+
+From: Qing Luo <luoqing@kylinos.cn>
+
+[ Upstream commit aa2e13ae8d3cbe2c15ef4f7e971b2de0832794aa ]
+
+In sctp_process_asconf(), when sctp_make_asconf_ack() fails to allocate
+the ASCONF_ACK chunk due to memory pressure, the code jumps to the
+done label where asoc->peer.addip_serial is unconditionally incremented.
+
+This leaves the peer's ASCONF (serial N) unacknowledged while the local
+endpoint now expects serial N+1. When the peer retransmits serial N, it
+falls into the serial < addip_serial + 1 branch ,
+which attempts to look up a cached ACK for serial N. No cached ACK
+exists since the allocation failed, so the retransmission is silently
+discarded. The peer eventually times out and ABORTs the association.
+
+Move the addip_serial increment inside the if (asconf_ack) block so that
+the serial number is only advanced when the ASCONF_ACK is successfully
+created and cached. This way, on allocation failure, the serial number
+is unchanged and the peer's retransmitted ASCONF will be correctly
+re-processed.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Qing Luo <luoqing@kylinos.cn>
+Acked-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/20260804025514.241767-1-l1138897701@163.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/sm_make_chunk.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
+index 837fb8280bfd5..6d738f95aff1d 100644
+--- a/net/sctp/sm_make_chunk.c
++++ b/net/sctp/sm_make_chunk.c
+@@ -3362,12 +3362,11 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
+ goto done;
+ }
+ done:
+- asoc->peer.addip_serial++;
+-
+ /* If we are sending a new ASCONF_ACK hold a reference to it in assoc
+ * after freeing the reference to old asconf ack if any.
+ */
+ if (asconf_ack) {
++ asoc->peer.addip_serial++;
+ sctp_chunk_hold(asconf_ack);
+ list_add_tail(&asconf_ack->transmitted_list,
+ &asoc->asconf_ack_list);
+--
+2.53.0
+
--- /dev/null
+From 75fc146554b94371e37cac9821244db25bd37c27 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 21:46:35 +0200
+Subject: selftests/ftrace: refactor eprobes test to fix argument checks
+
+From: Martin Kaiser <martin@kaiser.cx>
+
+[ Upstream commit 6e3abef2a27e7402a94111c9eff85d887e64a309 ]
+
+The add/remove eprobe test installs an eprobe for the openat syscall and
+runs ls. It checks the filenames that were opened by ls against a
+whitelist and a blacklist.
+
+Commit 206b25c09080 ("tracing: eprobe: read the complete FILTER_PTR_STRING
+pointer") fixed access to some string fields in eprobes. This triggers
+test failures as the blacklist does not allow relative paths for the
+openat parameters.
+
+What makes this test unstable is the fact that the openat calls vary a
+lot between different systems.
+
+Refactor the test to make it more robust. "cd <directory>" will issue a
+chdir syscall with the target directory as parameter. Set an eprobe on
+the sys_enter_chdir event and filter for the exact directory name. Allow
+(fault) as fallback.
+
+Link: https://lore.kernel.org/all/20260804194705.760893-1-martin@kaiser.cx/
+
+Fixes: 206b25c09080 ("tracing: eprobe: read the complete FILTER_PTR_STRING pointer")
+Reported-by: kernel test robot <oliver.sang@intel.com>
+Closes: https://lore.kernel.org/oe-lkp/202607151010.b68428e1-lkp@intel.com
+Signed-off-by: Martin Kaiser <martin@kaiser.cx>
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ftrace/test.d/dynevent/add_remove_eprobe.tc | 16 +++++-----------
+ 1 file changed, 5 insertions(+), 11 deletions(-)
+
+diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
+index c300eb0202620..e2322693d0c32 100644
+--- a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
++++ b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
+@@ -1,16 +1,16 @@
+ #!/bin/sh
+ # SPDX-License-Identifier: GPL-2.0
+ # description: Generic dynamic event - add/remove eprobe events
+-# requires: dynamic_events events/syscalls/sys_enter_openat "<attached-group>.<attached-event> [<args>]":README
++# requires: dynamic_events events/syscalls/sys_enter_chdir "<attached-group>.<attached-event> [<args>]":README
+
+ echo 0 > events/enable
+
+ clear_dynamic_events
+
+ SYSTEM="syscalls"
+-EVENT="sys_enter_openat"
++EVENT="sys_enter_chdir"
+ FIELD="filename"
+-EPROBE="eprobe_open"
++EPROBE="eprobe_chdir"
+ OPTIONS="file=+0(\$filename):ustring"
+ echo "e:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
+
+@@ -18,20 +18,14 @@ grep -q "$EPROBE" dynamic_events
+ test -d events/eprobes/$EPROBE
+
+ echo 1 > events/eprobes/$EPROBE/enable
+-ls
++cd /sys/kernel/tracing
+ echo 0 > events/eprobes/$EPROBE/enable
+
+-content=`grep '^ *ls-' trace | grep 'file='`
+-nocontent=`grep '^ *ls-' trace | grep 'file=' | grep -v -e '"/' -e '"."' -e '(fault)' ` || true
+-
++content=`grep -e 'file="/sys/kernel/tracing"\|(fault)' trace`
+ if [ -z "$content" ]; then
+ exit_fail
+ fi
+
+-if [ ! -z "$nocontent" ]; then
+- exit_fail
+-fi
+-
+ echo "-:$EPROBE" >> dynamic_events
+
+ ! grep -q "$EPROBE" dynamic_events
+--
+2.53.0
+
bluetooth-hci_conn-fix-potential-uaf-in-create_big_s.patch
mount-honour-sb_nouser-in-the-new-mount-api.patch
s390-zcrypt-fix-missing-mem-scrub-at-clear-key-impor.patch
+nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch
+arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch
+revert-net-thunderbolt-enable-end-to-end-flow-contro.patch
+bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch
+netfilter-ipset-switch-ext_size-to-atomic64_t.patch
+ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch
+ipvs-return-the-csum-validation-for-forward-hook.patch
+btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch
+bpf-preserve-pointer-state-for-commuted-arithmetic.patch
+net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch
+net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch
+net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch
+net-mlx5-fw_tracer-return-null-on-create-error.patch
+counter-microchip-tcb-capture-fix-dt-channel-validat.patch
+tcp-add-a-scheduling-point-in-established_get_first.patch
+bpf-tcp-make-mem-flags-configurable-through-bpf_iter.patch
+bpf-tcp-make-sure-iter-batch-always-contains-a-full-.patch
+bpf-tcp-get-rid-of-st_bucket_done.patch
+bpf-tcp-use-bpf_tcp_iter_batch_item-for-bpf_tcp_iter.patch
+bpf-tcp-avoid-socket-skips-and-repeats-during-iterat.patch
+bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch
+vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch
+udp-fix-potential-use-after-free-in-tunnel-segmentat.patch
+net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch
+net-openvswitch-check-ethernet-header-length-in-key_.patch
+hwmon-nzxt-smart2-check-return-value-of-init_device-.patch
+hwmon-lm25066-use-i2c_get_match_data.patch
+hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch
+selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch
+bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch
+bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch
+bnxt_en-fix-ptp-pps-setting-bug.patch
+sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch
+tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch
+net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch
+net-prestera-validate-firmware-header-length.patch
+net-remove-warn_on_once-from-sk_mc_loop.patch
+net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch
+net-qrtr-ns-raise-lookup-limit-to-128.patch
+net-thunderbolt-tear-down-dma-paths-before-stopping-.patch
+ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch
+net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch
+sctp-clear-control-chunk-transport-if-it-is-being-re.patch
+tls-don-t-abort-the-connection-on-signal-interrupted.patch
+hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch
+regulator-devres-add-api-for-reference-voltage-suppl.patch
+hwmon-ads7828-fix-external-vref-regulator-handling.patch
--- /dev/null
+From 9e8a8420178d9d36a834579bd7d9d7583b31343e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Jul 2023 11:24:05 +0800
+Subject: tcp: add a scheduling point in established_get_first()
+
+From: Jian Wen <wenjianhn@gmail.com>
+
+[ Upstream commit 9f4a7c930284bf2b5b84d3636a8e88857149328f ]
+
+Kubernetes[1] is going to stick with /proc/net/tcp for a while.
+
+This commit reduces the scheduling latency introduced by
+established_get_first(), similar to commit acffb584cda7 ("net: diag:
+add a scheduling point in inet_diag_dump_icsk()").
+
+In our environment, the scheduling latency affects the performance of
+latency-sensitive services like Redis.
+
+Changes in V2 :
+ - call cond_resched() before checking if a bucket is empty as
+ suggested by Eric Dumazet
+ - removed the delay of synchronize_net() from the commit message
+
+[1] https://github.com/google/cadvisor/blob/v0.47.2/container/libcontainer/handler.go#L130
+
+Signed-off-by: Jian Wen <wenjian1@xiaomi.com>
+Reviewed-by: Simon Horman <simon.horman@corigine.com>
+Link: https://lore.kernel.org/r/20230711032405.3253025-1-wenjian1@xiaomi.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index 00348cb9a211b..89200b4314018 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -57,6 +57,7 @@
+ #include <linux/init.h>
+ #include <linux/times.h>
+ #include <linux/slab.h>
++#include <linux/sched.h>
+
+ #include <net/net_namespace.h>
+ #include <net/icmp.h>
+@@ -2412,6 +2413,8 @@ static void *established_get_first(struct seq_file *seq)
+ struct hlist_nulls_node *node;
+ spinlock_t *lock = inet_ehash_lockp(hinfo, st->bucket);
+
++ cond_resched();
++
+ /* Lockless fast path for the common case of empty buckets */
+ if (empty_bucket(hinfo, st))
+ continue;
+--
+2.53.0
+
--- /dev/null
+From b46f82e783f2f0681bd1909b9108db735c1c0ce8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 14:17:38 +0800
+Subject: tcp: fix TFO max_qlen accounting across reuseport migration
+
+From: Jiayuan Chen <jiayuan.chen@linux.dev>
+
+[ Upstream commit a0ab2ba83e35159d81cec830a92e885ecf8139be ]
+
+A listener's TCP_FASTOPEN max_qlen stops being accurate and lets through
+far more pending Fast Open requests than it was configured for.
+
+This only shows up with SO_REUSEPORT listener migration, where closing a
+listener hands its still-pending TFO children over to a surviving one.
+
+fastopenq.qlen is charged in tcp_fastopen_create_child() when the child
+is created and uncharged in reqsk_fastopen_remove() when the handshake
+completes. The uncharge follows rsk_listener of the request the child
+points at, and inet_reqsk_clone() has repointed the child at a new
+request owned by the new listener, so the ++ and the -- land on two
+different sockets. The new listener's qlen drifts negative and its
+limit no longer binds.
+
+Charge the new listener during migration, like reqsk_queue_migrated()
+already does for queue->young and queue->qlen.
+
+Fixes: 54b92e841937 ("tcp: Migrate TCP_ESTABLISHED/TCP_SYN_RECV sockets in accept queues.")
+Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260803061739.134737-1-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/inet_connection_sock.c | 20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
+index a275ab5321a96..a0014311c520c 100644
+--- a/net/ipv4/inet_connection_sock.c
++++ b/net/ipv4/inet_connection_sock.c
+@@ -927,11 +927,23 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req,
+
+ nreq->rsk_listener = sk;
+
+- /* We need not acquire fastopenq->lock
+- * because the child socket is locked in inet_csk_listen_stop().
+- */
+- if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener)
++ if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener) {
++ struct fastopen_queue *fastopenq;
++
++ /* reqsk_fastopen_remove() will uncharge nreq->rsk_listener,
++ * that is @sk, so charge it here. Unlike the listener
++ * being closed, @sk is live and needs its lock.
++ */
++ fastopenq = &inet_csk(sk)->icsk_accept_queue.fastopenq;
++ spin_lock_bh(&fastopenq->lock);
++ fastopenq->qlen++;
++ spin_unlock_bh(&fastopenq->lock);
++
++ /* We need not acquire fastopenq->lock
++ * because the child socket is locked in inet_csk_listen_stop().
++ */
+ rcu_assign_pointer(tcp_sk(nreq->sk)->fastopen_rsk, nreq);
++ }
+
+ return nreq;
+ }
+--
+2.53.0
+
--- /dev/null
+From 63ed3bacda49ea105900dcc7ff518c9c99ff608e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 08:22:48 +0200
+Subject: tls: don't abort the connection on signal-interrupted sends
+
+From: Maximilian Immanuel Brandtner <maxbr@linux.ibm.com>
+
+[ Upstream commit af0e5cdd031f4f4a8f6d4160bfbda4f36872b0ed ]
+
+When a signal interrupts a blocking send, tls_tx_records() treats the
+resulting -ERESTARTSYS as a transmission failure and marks the socket
+errored via tls_err_abort() with the raw error code. Later syscalls
+return the kernel-internal errno 512 (ERESTARTSYS) to userspace, as the
+signal it stems from is no longer pending during syscall exit and thus
+never translated.
+
+An interrupted send is not a connection error: the partially sent record
+stays queued and is resent later. Interrupt error codes are therefore
+excluded from the abort in the same way as -EAGAIN.
+
+Fixes: b341ca51d267 ("tls: Fix tls_sw_sendmsg error handling")
+Signed-off-by: Maximilian Immanuel Brandtner <maxbr@linux.ibm.com>
+Link: https://patch.msgid.link/20260805063109.1772314-1-maxbr@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tls/tls_sw.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
+index 1b4e35dcb996b..5eec7c10acc20 100644
+--- a/net/tls/tls_sw.c
++++ b/net/tls/tls_sw.c
+@@ -457,7 +457,7 @@ int tls_tx_records(struct sock *sk, int flags)
+ }
+
+ tx_err:
+- if (rc < 0 && rc != -EAGAIN)
++ if (rc < 0 && rc != -EAGAIN && rc != -EINTR && rc != -ERESTARTSYS)
+ tls_err_abort(sk, rc);
+
+ return rc;
+--
+2.53.0
+
--- /dev/null
+From 9fd99edd87f85f925d5d78255f681109cc34c539 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 17:35:54 +0800
+Subject: udp: fix potential use-after-free in tunnel segmentation
+
+From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+
+[ Upstream commit d0f86fb36eb260abd10007b62c9dcc1028e03e61 ]
+
+__skb_udp_tunnel_segment() gets the UDP header before ensuring the
+tunnel header is in the skb head. If the pull reallocates skb->head,
+the saved UDP header pointer is no longer valid.
+
+Get the UDP header after the pull to avoid a potential use-after-free.
+
+Fixes: dbef491ebe7f ("udp: Use uh->len instead of skb->len to compute checksum in segmentation")
+Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+Reviewed-by: Antoine Tenart <atenart@kernel.org>
+Link: https://patch.msgid.link/20260730093554.68127-1-xuanqiang.luo@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/udp_offload.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
+index 35c014e10f24b..60fbb4ca34e00 100644
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -21,17 +21,19 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
+ int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
+ bool remcsum, need_csum, offload_csum, gso_partial;
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+- struct udphdr *uh = udp_hdr(skb);
+ u16 mac_offset = skb->mac_header;
+ __be16 protocol = skb->protocol;
+ u16 mac_len = skb->mac_len;
+ int udp_offset, outer_hlen;
++ struct udphdr *uh;
+ __wsum partial;
+ bool need_ipsec;
+
+ if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
+ goto out;
+
++ uh = udp_hdr(skb);
++
+ /* Adjust partial header checksum to negate old length.
+ * We cannot rely on the value contained in uh->len as it is
+ * possible that the actual value exceeds the boundaries of the
+--
+2.53.0
+
--- /dev/null
+From ba38e29ad91f4d3dbbe63dfe5142cba98e94c0d3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Jun 2026 15:02:02 -0700
+Subject: vhost/vdpa: reject overflowing PA map page counts on 32-bit
+
+From: Yousef Alhouseen <alhouseenyousef@gmail.com>
+
+[ Upstream commit 0619aaa34c0c2a2dcb07f0e9c8a34e7efb8c4cdf ]
+
+vhost_vdpa_pa_map() adds the IOVA page offset to the user-controlled map
+size before computing the number of pages to pin. On 32-bit systems,
+where unsigned long is narrower than u64, that addition can overflow and
+the code can pin and map fewer pages than the requested IOTLB range.
+
+Reject sizes that overflow the unsigned long page-count calculation.
+
+Fixes: 22af48cf91aa ("vdpa: factor out vhost_vdpa_pa_map() and vhost_vdpa_pa_unmap()")
+Acked-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Message-ID: <CAMuQ4bX-iDvcUOPPY+NLz95tkRJYwWqvzAr=U48uNaub_HZLGw@mail.gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vhost/vdpa.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
+index 7684c16e9e07a..df71ca25a1012 100644
+--- a/drivers/vhost/vdpa.c
++++ b/drivers/vhost/vdpa.c
+@@ -920,6 +920,7 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
+ unsigned int gup_flags = FOLL_LONGTERM;
+ unsigned long npages, cur_base, map_pfn, last_pfn = 0;
+ unsigned long lock_limit, sz2pin, nchunks, i;
++ unsigned long page_offset;
+ u64 start = iova;
+ long pinned;
+ int ret = 0;
+@@ -932,7 +933,13 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
+ if (perm & VHOST_ACCESS_WO)
+ gup_flags |= FOLL_WRITE;
+
+- npages = PFN_UP(size + (iova & ~PAGE_MASK));
++ page_offset = iova & ~PAGE_MASK;
++ if (size > ULONG_MAX - page_offset) {
++ ret = -EINVAL;
++ goto free;
++ }
++
++ npages = PFN_UP(size + page_offset);
+ if (!npages) {
+ ret = -EINVAL;
+ goto free;
+--
+2.53.0
+
--- /dev/null
+From 00e90e1126706b1f5d9a21ddcc2adb8ca4d81471 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 25 Jul 2026 14:57:22 -0700
+Subject: ARM: dts: BCM5301X: fix PCIe controller 2 second interrupt
+
+From: Rosen Penev <rosenp@gmail.com>
+
+[ Upstream commit bab4d538f8485e0d48538fcb82b285df3779278e ]
+
+PCIe controller 2 has interrupts 0-4 mapping to GIC SPI 138-142. The
+mapping for interrupt 1 was incorrectly set to 138 due to a copy-paste
+error. Fix it to 139.
+
+Assisted-by: opencode:big-pickle
+Signed-off-by: Rosen Penev <rosenp@gmail.com>
+Link: https://lore.kernel.org/r/20260725215722.9323-1-rosenp@gmail.com
+Fixes: 3b3e35b279be ("ARM: dts: BCM5301X: Relicense AXI interrupts code to the GPL 2.0+ / MIT")
+Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/boot/dts/broadcom/bcm-ns.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/broadcom/bcm-ns.dtsi b/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
+index d0d5f7e52a917..f08d0a27de0b4 100644
+--- a/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
+@@ -138,7 +138,7 @@ axi@18000000 {
+
+ /* PCIe Controller 2 */
+ <0x00014000 0 &gic GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
+- <0x00014000 1 &gic GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00014000 1 &gic GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 2 &gic GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 3 &gic GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 4 &gic GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+--
+2.53.0
+
--- /dev/null
+From 04d0bd8271e8d4919abe1bdbd73a4789a8a1e68f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 24 May 2026 23:38:46 -0400
+Subject: ARM: npcm: Fix OF node refcount leaks in SMP setup
+
+From: Yuho Choi <dbgh9129@gmail.com>
+
+[ Upstream commit 8eb052f48331474c2789d07b7f11165c323bd2f9 ]
+
+npcm7xx_smp_boot_secondary() and npcm7xx_smp_prepare_cpus() look up
+the GCR and SCU nodes with of_find_compatible_node(). The returned
+nodes are used for of_iomap(), but the node references are never
+released.
+
+of_iomap() does not consume the device node reference, and iounmap()
+only releases the MMIO mapping. Drop each node reference after the
+corresponding mapping attempt.
+
+Fixes: 7bffa14c9aed ("arm: npcm: add basic support for Nuvoton BMCs")
+Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
+Reviewed-by: Avi Fishman <avifishman70@gmail.com>
+Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/mach-npcm/platsmp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arm/mach-npcm/platsmp.c b/arch/arm/mach-npcm/platsmp.c
+index 41891d3aa1247..4c1fc9983746c 100644
+--- a/arch/arm/mach-npcm/platsmp.c
++++ b/arch/arm/mach-npcm/platsmp.c
+@@ -32,6 +32,7 @@ static int npcm7xx_smp_boot_secondary(unsigned int cpu,
+ goto out;
+ }
+ gcr_base = of_iomap(gcr_np, 0);
++ of_node_put(gcr_np);
+ if (!gcr_base) {
+ pr_err("could not iomap gcr");
+ ret = -ENOMEM;
+@@ -60,6 +61,7 @@ static void __init npcm7xx_smp_prepare_cpus(unsigned int max_cpus)
+ return;
+ }
+ scu_base = of_iomap(scu_np, 0);
++ of_node_put(scu_np);
+ if (!scu_base) {
+ pr_err("could not iomap scu");
+ return;
+--
+2.53.0
+
--- /dev/null
+From 043772828440f5fcf298190ad3f107baa002cc74 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 21:45:27 +0100
+Subject: arm64: dts: broadcom: bcm2712: Remove non-functional EL2 virtual
+ timer
+
+From: Daniel Drake <dan@reactivated.net>
+
+[ Upstream commit 75952cfc7752c52a2b692b59d34ce160d3edabb2 ]
+
+Commit d87773de9efe1 ("clocksource/drivers/arm_arch_timer: Default to EL2
+virtual timer when running VHE") causes boot to hang on Raspberry Pi 5.
+The newly-selected EL2 virtual timer does not generate any interrupts,
+even though the GIC_DIST_ENABLE_SET flag has been confirmed set via
+readback.
+
+It is highly unusual that this timer interrupt is non-operational because
+this is a standard GIC interrupt corresponding to a standard Cortex-A76
+CPU timer. However, Broadcom have confirmed for this SoC:
+
+> the interrupt line was never connected in the first place as this was
+> not identified as being a requirement
+
+Remove the corresponding DeviceTree entry.
+
+Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Closes: https://lore.kernel.org/all/ea15cce1-b393-43f6-8d58-3d6f90f0c0cd@samsung.com/
+Fixes: faa3381267d0 ("arm64: dts: broadcom: Add minimal support for Raspberry Pi 5")
+Signed-off-by: Daniel Drake <dan@reactivated.net>
+Link: https://lore.kernel.org/r/20260716-bcm2712-el2-v2-1-e708f7fb42fa@reactivated.net
+Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+index 209f99b1ceae7..c8e809d77b3fe 100644
+--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+@@ -279,8 +279,6 @@ IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
+ IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_LOW)>,
+- <GIC_PPI 12 (GIC_CPU_MASK_SIMPLE(4) |
+ IRQ_TYPE_LEVEL_LOW)>;
+ };
+ };
+--
+2.53.0
+
--- /dev/null
+From 6de6aaa202d283ccc747b28870d61ed42956dd2e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 14:06:28 +0800
+Subject: ata: pata_sl82c105: fix bridge revision use-after-free
+
+From: Hongyan Xu <getshell@seu.edu.cn>
+
+[ Upstream commit 7700a31039cdc6715cb6cce7e7a664ee4e945f67 ]
+
+pci_get_slot() returns a referenced PCI device. Commit 44c10138fd4b
+("PCI: Change all drivers to use pci_device->revision") replaced a
+configuration-space read with direct access to the cached revision field,
+but left that access after pci_dev_put(). The bridge may therefore be freed
+before its revision is read.
+
+Read the revision before dropping the reference.
+
+Fixes: 44c10138fd4b ("PCI: Change all drivers to use pci_device->revision")
+Signed-off-by: Hongyan Xu <getshell@seu.edu.cn>
+Reviewed-by: Niklas Cassel <cassel@kernel.org>
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ata/pata_sl82c105.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
+index 93882e976ede4..2a5ce46af5a0a 100644
+--- a/drivers/ata/pata_sl82c105.c
++++ b/drivers/ata/pata_sl82c105.c
+@@ -264,6 +264,7 @@ static struct ata_port_operations sl82c105_port_ops = {
+ static int sl82c105_bridge_revision(struct pci_dev *pdev)
+ {
+ struct pci_dev *bridge;
++ u8 revision;
+
+ /*
+ * The bridge should be part of the same device, but function 0.
+@@ -285,8 +286,9 @@ static int sl82c105_bridge_revision(struct pci_dev *pdev)
+ /*
+ * We need to find function 0's revision, not function 1
+ */
++ revision = bridge->revision;
+ pci_dev_put(bridge);
+- return bridge->revision;
++ return revision;
+ }
+
+ static void sl82c105_fixup(struct pci_dev *pdev)
+--
+2.53.0
+
--- /dev/null
+From fb2de7155c33a54ebc8104369b5db136c6e8eb60 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:34 -0700
+Subject: bnxt_en: Determine and store default RX ring in vnic structure
+
+From: Shravya KN <shravya.k-n@broadcom.com>
+
+[ Upstream commit 53f01cd594e223aabb538d5288e60111523c96f2 ]
+
+Each VNIC has a default RX ring. The purpose of the default RX ring
+is to provide a destination for any packets that cannot be parsed by
+the RSS logic. Up until now, the default RX ring is always Ring 0.
+
+We neglected to take care of this default RX ring when adding the
+queue restart feature. If ring 0 (default ring) is re-started, it
+may now have a new FW ring ID after freeing the old one and
+allocating a new one. The VNIC now may have a stale default ring
+and it may generate an internal exception. This exception may
+appear in dmesg:
+
+FW reported unknown error type 10
+
+The best way to resolve this issue is to use a more appropriate
+ring for the default ring instead of always ring 0. Ring 0 may not
+even be in the RSS table, especially on a new RSS context.
+
+This patch adds the logic to determine and store the proper default
+RX ring for a VNIC. For an RSS VNIC, the default ring is the lowest
+ring number in the RSS table. The next patch will add proper logic
+to update the VNIC if the default ring changes after queue restart.
+
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Shravya KN <shravya.k-n@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-3-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 0b137529a899 ("bnxt_en: Refresh VNIC default ring on queue restart if needed")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 33 +++++++++++++++--------
+ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
+ 2 files changed, 23 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index ce7de01000160..31971a45ac3d4 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -6365,25 +6365,36 @@ int bnxt_get_nr_rss_ctxs(struct bnxt *bp, int rx_rings)
+ static void bnxt_fill_hw_rss_tbl(struct bnxt *bp, struct bnxt_vnic_info *vnic)
+ {
+ bool no_rss = !(vnic->flags & BNXT_VNIC_RSS_FLAG);
+- u16 i, j;
++ u16 i, j, min_j = bp->rx_nr_rings - 1;
+
+ if (!vnic->rss_table)
+- return;
++ goto skip_rss_tbl;
+
+ /* Fill the RSS indirection table with ring group ids */
+ for (i = 0, j = 0; i < HW_HASH_INDEX_SIZE; i++) {
+ if (!no_rss)
+ j = bp->rss_indir_tbl[i];
++ min_j = min(j, min_j);
+ vnic->rss_table[i] = cpu_to_le16(vnic->fw_grp_ids[j]);
+ }
++
++skip_rss_tbl:
++ if (vnic->rss_table && !no_rss)
++ vnic->default_rx_ring = min_j;
++ else if (vnic->flags & BNXT_VNIC_RFS_FLAG)
++ vnic->default_rx_ring = vnic->vnic_id - 1;
++ else if ((vnic->vnic_id == 1) && BNXT_CHIP_TYPE_NITRO_A0(bp))
++ vnic->default_rx_ring = bp->rx_nr_rings - 1;
++ else
++ vnic->default_rx_ring = 0;
+ }
+
+ static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp,
+ struct bnxt_vnic_info *vnic)
+ {
++ u16 tbl_size, i, min_j = bp->rx_nr_rings - 1;
+ __le16 *ring_tbl = vnic->rss_table;
+ struct bnxt_rx_ring_info *rxr;
+- u16 tbl_size, i;
+
+ tbl_size = bnxt_get_rxfh_indir_size(bp->dev);
+
+@@ -6396,6 +6407,7 @@ static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp,
+ j = ethtool_rxfh_context_indir(vnic->rss_ctx)[i];
+ else
+ j = bp->rss_indir_tbl[i];
++ min_j = min(j, min_j);
+ rxr = &bp->rx_ring[j];
+
+ ring_id = rxr->rx_ring_struct.fw_ring_id;
+@@ -6403,6 +6415,7 @@ static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp,
+ ring_id = bnxt_cp_ring_for_rx(bp, rxr);
+ *ring_tbl++ = cpu_to_le16(ring_id);
+ }
++ vnic->default_rx_ring = min_j;
+ }
+
+ static void
+@@ -6600,8 +6613,9 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, struct bnxt_vnic_info *vnic)
+ return rc;
+
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
+- struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0];
++ struct bnxt_rx_ring_info *rxr;
+
++ rxr = &bp->rx_ring[vnic->default_rx_ring];
+ req->default_rx_ring_id =
+ cpu_to_le16(rxr->rx_ring_struct.fw_ring_id);
+ req->default_cmpl_ring_id =
+@@ -6634,13 +6648,7 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, struct bnxt_vnic_info *vnic)
+ req->cos_rule = cpu_to_le16(0xffff);
+ }
+
+- if (vnic->flags & BNXT_VNIC_RSS_FLAG)
+- ring = 0;
+- else if (vnic->flags & BNXT_VNIC_RFS_FLAG)
+- ring = vnic->vnic_id - 1;
+- else if ((vnic->vnic_id == 1) && BNXT_CHIP_TYPE_NITRO_A0(bp))
+- ring = bp->rx_nr_rings - 1;
+-
++ ring = vnic->default_rx_ring;
+ grp_idx = bp->rx_ring[ring].bnapi->index;
+ req->dflt_ring_grp = cpu_to_le16(bp->grp_info[grp_idx].fw_grp_id);
+ req->lb_rule = cpu_to_le16(0xffff);
+@@ -10604,6 +10612,9 @@ static int bnxt_setup_nitroa0_vnic(struct bnxt *bp)
+ return rc;
+ }
+
++ /* Setup the proper default RX ring */
++ bnxt_fill_hw_rss_tbl(bp, vnic);
++
+ rc = bnxt_hwrm_vnic_cfg(bp, vnic);
+ if (rc) {
+ netdev_err(bp->dev, "Cannot allocate special vnic for NS2 A0: %x\n",
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+index 37fb74f18eeec..f50fe72f83ac6 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+@@ -1300,6 +1300,7 @@ struct bnxt_vnic_info {
+ #define BNXT_VNIC_RSSCTX_FLAG 0x40
+ struct ethtool_rxfh_context *rss_ctx;
+ u32 vnic_id;
++ u16 default_rx_ring;
+ };
+
+ struct bnxt_rss_ctx {
+--
+2.53.0
+
--- /dev/null
+From 6cb21e23d9f2c83e3a40bd7a3326a06500b3c1a8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:37 -0700
+Subject: bnxt_en: Fix PTP PPS setting bug
+
+From: Keegan Freyhof <keegan.freyhof@broadcom.com>
+
+[ Upstream commit 80eaf88efec33ac77ed7726d066c4f2f932cc329 ]
+
+The existing driver logic is always turning on PTP_CLK_REQ_PPS
+regardless of the "on" parameter passed to bnxt_ptp_enable().
+During shutdown, PTP_CLK_REQ_PPS may be turned off and this
+bug will do the opposite and may trigger a PCIe PTM request TLP.
+On some systems this can trigger a PCIe AER.
+
+Fix it by properly configuring PTP_CLK_REQ_PPS based on the "on"
+parameter.
+
+Fixes: 9e518f25802c ("bnxt_en: 1PPS functions to configure TSIO pins")
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Keegan Freyhof <keegan.freyhof@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-6-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
+index 6dfa0ab74c332..02276b9ac5c62 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
+@@ -494,12 +494,15 @@ static int bnxt_ptp_enable(struct ptp_clock_info *ptp_info,
+ return rc;
+ case PTP_CLK_REQ_PPS:
+ /* Configure PHC PPS IN */
+- rc = bnxt_ptp_cfg_pin(bp, 0, BNXT_PPS_PIN_PPS_IN);
++ pin_id = 0;
++ if (!on)
++ break;
++ rc = bnxt_ptp_cfg_pin(bp, pin_id, BNXT_PPS_PIN_PPS_IN);
+ if (rc)
+ return rc;
+ rc = bnxt_ptp_cfg_event(bp, BNXT_PPS_EVENT_INTERNAL);
+ if (!rc)
+- ptp->pps_info.pins[0].event = BNXT_PPS_EVENT_INTERNAL;
++ ptp->pps_info.pins[pin_id].event = BNXT_PPS_EVENT_INTERNAL;
+ return rc;
+ default:
+ netdev_err(ptp->bp->dev, "Unrecognized PIN function\n");
+--
+2.53.0
+
--- /dev/null
+From 89afe7938643972de8d72e7efa0bef8090cc3614 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:33 -0700
+Subject: bnxt_en: Move RSS table fill outside __bnxt_hwrm_vnic_set_rss()
+
+From: Shravya KN <shravya.k-n@broadcom.com>
+
+[ Upstream commit 1d0fc6c7ea49994b8ff50d02979d1e4207ec6c4f ]
+
+This is a refactor patch with no change in behavior. The caller
+will now fill the RSS table before calling __bnxt_hwrm_vnic_set_rss().
+In the next patch, we'll add code to determine the default ring for
+the VNIC when we fill the RSS table.
+
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Shravya KN <shravya.k-n@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-2-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 0b137529a899 ("bnxt_en: Refresh VNIC default ring on queue restart if needed")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 4970e20b2cb1b..ce7de01000160 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -6367,6 +6367,9 @@ static void bnxt_fill_hw_rss_tbl(struct bnxt *bp, struct bnxt_vnic_info *vnic)
+ bool no_rss = !(vnic->flags & BNXT_VNIC_RSS_FLAG);
+ u16 i, j;
+
++ if (!vnic->rss_table)
++ return;
++
+ /* Fill the RSS indirection table with ring group ids */
+ for (i = 0, j = 0; i < HW_HASH_INDEX_SIZE; i++) {
+ if (!no_rss)
+@@ -6406,13 +6409,8 @@ static void
+ __bnxt_hwrm_vnic_set_rss(struct bnxt *bp, struct hwrm_vnic_rss_cfg_input *req,
+ struct bnxt_vnic_info *vnic)
+ {
+- if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
+- bnxt_fill_hw_rss_tbl_p5(bp, vnic);
+- if (bp->flags & BNXT_FLAG_CHIP_P7)
+- req->flags |= VNIC_RSS_CFG_REQ_FLAGS_IPSEC_HASH_TYPE_CFG_SUPPORT;
+- } else {
+- bnxt_fill_hw_rss_tbl(bp, vnic);
+- }
++ if (bp->flags & BNXT_FLAG_CHIP_P7)
++ req->flags |= VNIC_RSS_CFG_REQ_FLAGS_IPSEC_HASH_TYPE_CFG_SUPPORT;
+
+ if (bp->rss_hash_delta) {
+ req->hash_type = cpu_to_le32(bp->rss_hash_delta);
+@@ -6464,6 +6462,7 @@ static int bnxt_hwrm_vnic_set_rss_p5(struct bnxt *bp,
+ if (!set_rss)
+ return hwrm_req_send(bp, req);
+
++ bnxt_fill_hw_rss_tbl_p5(bp, vnic);
+ __bnxt_hwrm_vnic_set_rss(bp, req, vnic);
+ ring_tbl_map = vnic->rss_table_dma_addr;
+ nr_ctxs = bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings);
+@@ -10299,6 +10298,7 @@ static int __bnxt_setup_vnic(struct bnxt *bp, struct bnxt_vnic_info *vnic)
+ }
+
+ skip_rss_ctx:
++ bnxt_fill_hw_rss_tbl(bp, vnic);
+ /* configure default vnic, ring grp */
+ rc = bnxt_hwrm_vnic_cfg(bp, vnic);
+ if (rc) {
+--
+2.53.0
+
--- /dev/null
+From a00c79fd277fc35ea09d592e55766b979e1cd5cc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:35 -0700
+Subject: bnxt_en: Refresh VNIC default ring on queue restart if needed
+
+From: Shravya KN <shravya.k-n@broadcom.com>
+
+[ Upstream commit 0b137529a8997caf67190ca1d71ba8bbdb44fbfb ]
+
+When a queue is restarted, refresh VNIC_CFG for all VNICs whose
+default RX ring is the restarted ring. This will eliminate this
+possible FW warning caused by a stale default ring in the VNIC:
+
+FW reported unknown error type 10
+
+Fixes: 5ac066b7b062 ("bnxt_en: Fix queue start to update vnic RSS table")
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Shravya KN <shravya.k-n@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-4-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 31971a45ac3d4..2356b7ba7fcfb 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -10531,6 +10531,11 @@ static int bnxt_set_vnic_mru_p5(struct bnxt *bp, struct bnxt_vnic_info *vnic,
+ vnic->vnic_id, rc);
+ return rc;
+ }
++ if (rxr_id == vnic->default_rx_ring) {
++ rc = bnxt_hwrm_vnic_cfg(bp, vnic);
++ if (rc)
++ return rc;
++ }
+ }
+ vnic->mru = mru;
+ bnxt_hwrm_vnic_update(bp, vnic,
+--
+2.53.0
+
--- /dev/null
+From 27a457e89c78d1324b92e92ff0deb5395fe76840 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 25 Jul 2026 23:39:30 +0000
+Subject: bonding: alb: re-check primary_is_promisc under RTNL in
+ bond_alb_monitor
+
+From: Xiang Mei (Microsoft) <xmei5@asu.edu>
+
+[ Upstream commit 683c6ba6e58e6ed1037831ea97dd58d9c0e76b8d ]
+
+bond_alb_monitor() reads primary_is_promisc under RCU, then drops RCU and
+takes RTNL via rtnl_trylock() before undoing the promiscuity it set on the
+active slave. In that window the active slave can change under RTNL
+(RTM_DELLINK -> __bond_release_one() -> bond_alb_handle_active_change()),
+which already drops the promiscuity and clears primary_is_promisc. The
+monitor still acts on the stale decision: if the slave was removed with no
+failover, curr_active_slave is now NULL and the deref faults; if it failed
+over, the stale dev_set_promiscuity(-1) underflows the new slave's
+promiscuity counter and pins it in IFF_PROMISC.
+
+ Oops: general protection fault, probably for non-canonical address ...
+ KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
+ Workqueue: b42 bond_alb_monitor
+ RIP: 0010:bond_alb_monitor (drivers/net/bonding/bond_alb.c:1600)
+ process_one_work (kernel/workqueue.c:3322)
+ worker_thread (kernel/workqueue.c:3486)
+ kthread (kernel/kthread.c:436)
+ ret_from_fork (arch/x86/kernel/process.c:158)
+ Kernel panic - not syncing: Fatal exception
+
+Re-check primary_is_promisc (and curr_active_slave) after taking RTNL so
+the monitor only undoes an increment it still owns. The other bonding
+monitors already re-read state under RTNL in their commit phase
+(bond_miimon_commit/bond_ab_arp_commit); bond_alb_monitor() was the only
+one acting on the pre-trylock decision.
+
+Fixes: d0e81b7e2246 ("bonding: Acquire correct locks in alb for promisc change")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
+Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
+Acked-by: Jay Vosburgh <jv@jvosburgh.net>
+Link: https://patch.msgid.link/20260725233930.2957317-1-xmei5@asu.edu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/bonding/bond_alb.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
+index 7edf0fd58c346..ce6a3a0a2e153 100644
+--- a/drivers/net/bonding/bond_alb.c
++++ b/drivers/net/bonding/bond_alb.c
+@@ -1535,8 +1535,8 @@ void bond_alb_monitor(struct work_struct *work)
+ struct bonding *bond = container_of(work, struct bonding,
+ alb_work.work);
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
++ struct slave *slave, *curr;
+ struct list_head *iter;
+- struct slave *slave;
+
+ if (!bond_has_slaves(bond)) {
+ atomic_set(&bond_info->tx_rebalance_counter, 0);
+@@ -1598,9 +1598,11 @@ void bond_alb_monitor(struct work_struct *work)
+ * because a slave was disabled then
+ * it can now leave promiscuous mode.
+ */
+- dev_set_promiscuity(rtnl_dereference(bond->curr_active_slave)->dev,
+- -1);
+- bond_info->primary_is_promisc = 0;
++ curr = rtnl_dereference(bond->curr_active_slave);
++ if (bond_info->primary_is_promisc && curr) {
++ dev_set_promiscuity(curr->dev, -1);
++ bond_info->primary_is_promisc = 0;
++ }
+
+ rtnl_unlock();
+ rcu_read_lock();
+--
+2.53.0
+
--- /dev/null
+From 436fac20447f0da139539fc8ce1882f9bba4f227 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:18:28 +0000
+Subject: bpf: Preserve pointer state for commuted arithmetic
+
+From: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+
+[ Upstream commit a4c6f804b44c5c790269b25e0e61cf4e9f117c86 ]
+
+When scalar += pointer is handled in adjust_ptr_min_max_vals(), the
+destination register inherits the pointer state from the source pointer.
+Copying only selected fields is fragile because pointer provenance is
+tracked by several bpf_reg_state fields.
+
+Use the caller's temporary offset register to preserve the scalar operand
+while replacing the destination with the full pointer state. This preserves
+the frame number for PTR_TO_STACK registers and keeps parent identity
+fields consistent.
+
+Fixes: f4d7e40a5b71 ("bpf: introduce function calls (verification)")
+Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+Tested-by: Daniel Wade <danjwade95@gmail.com>
+Acked-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-2-8ee297e2346b@mails.tsinghua.edu.cn
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 77183b436da5e..275c9fabc955e 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -13565,11 +13565,12 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ return -EACCES;
+ }
+
+- /* In case of 'scalar += pointer', dst_reg inherits pointer type and id.
+- * The id may be overwritten later if we create a new variable offset.
++ /* For 'scalar += pointer', dst_reg inherits the complete pointer
++ * register state. Individual fields may be adjusted later by pointer
++ * arithmetic. Callers guarantee that below does not overwrite off_reg.
+ */
+- dst_reg->type = ptr_reg->type;
+- dst_reg->id = ptr_reg->id;
++ if (dst_reg != ptr_reg)
++ *dst_reg = *ptr_reg;
+
+ if (!check_reg_sane_offset(env, off_reg, ptr_reg->type) ||
+ !check_reg_sane_offset(env, ptr_reg, ptr_reg->type))
+@@ -13631,7 +13632,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ }
+ break;
+ case BPF_SUB:
+- if (dst_reg == off_reg) {
++ if (dst_reg != ptr_reg) {
+ /* scalar -= pointer. Creates an unknown scalar */
+ verbose(env, "R%d tried to subtract pointer from scalar\n",
+ dst);
+@@ -14490,8 +14491,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
+ err = mark_chain_precision(env, insn->dst_reg);
+ if (err)
+ return err;
+- return adjust_ptr_min_max_vals(env, insn,
+- src_reg, dst_reg);
++ off_reg = *dst_reg;
++ return adjust_ptr_min_max_vals(env, insn, src_reg, &off_reg);
+ }
+ } else if (ptr_reg) {
+ /* pointer += scalar */
+--
+2.53.0
+
--- /dev/null
+From 9ae64c65e362fdbae2f62491e7e87f50e6ed3cf1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Jul 2025 11:09:09 -0700
+Subject: bpf: tcp: Avoid socket skips and repeats during iteration
+
+From: Jordan Rife <jordan@jrife.io>
+
+[ Upstream commit f5080f612a1c587bf636bb23d2a2f4de276d60e4 ]
+
+Replace the offset-based approach for tracking progress through a bucket
+in the TCP table with one based on socket cookies. Remember the cookies
+of unprocessed sockets from the last batch and use this list to
+pick up where we left off or, in the case that the next socket
+disappears between reads, find the first socket after that point that
+still exists in the bucket and resume from there.
+
+This approach guarantees that all sockets that existed when iteration
+began and continue to exist throughout will be visited exactly once.
+Sockets that are added to the table during iteration may or may not be
+seen, but if they are they will be seen exactly once.
+
+Signed-off-by: Jordan Rife <jordan@jrife.io>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 147 ++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 115 insertions(+), 32 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index 6a8241367672b..7785c177f2cd3 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -58,6 +58,7 @@
+ #include <linux/times.h>
+ #include <linux/slab.h>
+ #include <linux/sched.h>
++#include <linux/sock_diag.h>
+
+ #include <net/net_namespace.h>
+ #include <net/icmp.h>
+@@ -3000,6 +3001,7 @@ static int tcp4_seq_show(struct seq_file *seq, void *v)
+ #ifdef CONFIG_BPF_SYSCALL
+ union bpf_tcp_iter_batch_item {
+ struct sock *sk;
++ __u64 cookie;
+ };
+
+ struct bpf_tcp_iter_state {
+@@ -3030,10 +3032,19 @@ static int tcp_prog_seq_show(struct bpf_prog *prog, struct bpf_iter_meta *meta,
+
+ static void bpf_iter_tcp_put_batch(struct bpf_tcp_iter_state *iter)
+ {
++ union bpf_tcp_iter_batch_item *item;
+ unsigned int cur_sk = iter->cur_sk;
++ __u64 cookie;
+
+- while (cur_sk < iter->end_sk)
+- sock_gen_put(iter->batch[cur_sk++].sk);
++ /* Remember the cookies of the sockets we haven't seen yet, so we can
++ * pick up where we left off next time around.
++ */
++ while (cur_sk < iter->end_sk) {
++ item = &iter->batch[cur_sk++];
++ cookie = sock_gen_cookie(item->sk);
++ sock_gen_put(item->sk);
++ item->cookie = cookie;
++ }
+ }
+
+ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+@@ -3054,6 +3065,106 @@ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+ return 0;
+ }
+
++static struct sock *bpf_iter_tcp_resume_bucket(struct sock *first_sk,
++ union bpf_tcp_iter_batch_item *cookies,
++ int n_cookies)
++{
++ struct hlist_nulls_node *node;
++ struct sock *sk;
++ int i;
++
++ for (i = 0; i < n_cookies; i++) {
++ sk = first_sk;
++ sk_nulls_for_each_from(sk, node)
++ if (cookies[i].cookie == atomic64_read(&sk->sk_cookie))
++ return sk;
++ }
++
++ return NULL;
++}
++
++static struct sock *bpf_iter_tcp_resume_listening(struct seq_file *seq)
++{
++ struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
++ struct bpf_tcp_iter_state *iter = seq->private;
++ struct tcp_iter_state *st = &iter->state;
++ unsigned int find_cookie = iter->cur_sk;
++ unsigned int end_cookie = iter->end_sk;
++ int resume_bucket = st->bucket;
++ struct sock *sk;
++
++ if (end_cookie && find_cookie == end_cookie)
++ ++st->bucket;
++
++ sk = listening_get_first(seq);
++ iter->cur_sk = 0;
++ iter->end_sk = 0;
++
++ if (sk && st->bucket == resume_bucket && end_cookie) {
++ sk = bpf_iter_tcp_resume_bucket(sk, &iter->batch[find_cookie],
++ end_cookie - find_cookie);
++ if (!sk) {
++ spin_unlock(&hinfo->lhash2[st->bucket].lock);
++ ++st->bucket;
++ sk = listening_get_first(seq);
++ }
++ }
++
++ return sk;
++}
++
++static struct sock *bpf_iter_tcp_resume_established(struct seq_file *seq)
++{
++ struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
++ struct bpf_tcp_iter_state *iter = seq->private;
++ struct tcp_iter_state *st = &iter->state;
++ unsigned int find_cookie = iter->cur_sk;
++ unsigned int end_cookie = iter->end_sk;
++ int resume_bucket = st->bucket;
++ struct sock *sk;
++
++ if (end_cookie && find_cookie == end_cookie)
++ ++st->bucket;
++
++ sk = established_get_first(seq);
++ iter->cur_sk = 0;
++ iter->end_sk = 0;
++
++ if (sk && st->bucket == resume_bucket && end_cookie) {
++ sk = bpf_iter_tcp_resume_bucket(sk, &iter->batch[find_cookie],
++ end_cookie - find_cookie);
++ if (!sk) {
++ spin_unlock_bh(inet_ehash_lockp(hinfo, st->bucket));
++ ++st->bucket;
++ sk = established_get_first(seq);
++ }
++ }
++
++ return sk;
++}
++
++static struct sock *bpf_iter_tcp_resume(struct seq_file *seq)
++{
++ struct bpf_tcp_iter_state *iter = seq->private;
++ struct tcp_iter_state *st = &iter->state;
++ struct sock *sk = NULL;
++
++ switch (st->state) {
++ case TCP_SEQ_STATE_LISTENING:
++ sk = bpf_iter_tcp_resume_listening(seq);
++ if (sk)
++ break;
++ st->bucket = 0;
++ st->state = TCP_SEQ_STATE_ESTABLISHED;
++ fallthrough;
++ case TCP_SEQ_STATE_ESTABLISHED:
++ sk = bpf_iter_tcp_resume_established(seq);
++ break;
++ }
++
++ return sk;
++}
++
+ static unsigned int bpf_iter_tcp_listening_batch(struct seq_file *seq,
+ struct sock **start_sk)
+ {
+@@ -3138,32 +3249,12 @@ static void bpf_iter_tcp_unlock_bucket(struct seq_file *seq)
+
+ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ {
+- struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
+ struct bpf_tcp_iter_state *iter = seq->private;
+- struct tcp_iter_state *st = &iter->state;
+ unsigned int expected;
+ struct sock *sk;
+ int err;
+
+- /* The st->bucket is done. Directly advance to the next
+- * bucket instead of having the tcp_seek_last_pos() to skip
+- * one by one in the current bucket and eventually find out
+- * it has to advance to the next bucket.
+- */
+- if (iter->end_sk && iter->cur_sk == iter->end_sk) {
+- st->offset = 0;
+- st->bucket++;
+- if (st->state == TCP_SEQ_STATE_LISTENING &&
+- st->bucket > hinfo->lhash2_mask) {
+- st->state = TCP_SEQ_STATE_ESTABLISHED;
+- st->bucket = 0;
+- }
+- }
+-
+- iter->cur_sk = 0;
+- iter->end_sk = 0;
+-
+- sk = tcp_seek_last_pos(seq);
++ sk = bpf_iter_tcp_resume(seq);
+ if (!sk)
+ return NULL; /* Done */
+
+@@ -3179,10 +3270,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ if (err)
+ return ERR_PTR(err);
+
+- iter->cur_sk = 0;
+- iter->end_sk = 0;
+-
+- sk = tcp_seek_last_pos(seq);
++ sk = bpf_iter_tcp_resume(seq);
+ if (!sk)
+ return NULL; /* Done */
+
+@@ -3234,11 +3322,6 @@ static void *bpf_iter_tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+ * meta.seq_num is used instead.
+ */
+ st->num++;
+- /* Move st->offset to the next sk in the bucket such that
+- * the future start() will resume at st->offset in
+- * st->bucket. See tcp_seek_last_pos().
+- */
+- st->offset++;
+ sock_gen_put(iter->batch[iter->cur_sk++].sk);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 8d7757764746b30097751e52c837e09313d587df Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 22:32:47 +0000
+Subject: bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()
+
+From: Jose Fernandez (Anthropic) <jose.fernandez@linux.dev>
+
+[ Upstream commit e5fd3f514e27db1f05fbd72ba615d74941e23c51 ]
+
+reqsk_queue_hash_req() publishes a TCP_NEW_SYN_RECV request_sock onto
+the ehash chain, drops the bucket lock, and only afterwards sets
+rsk_refcnt to 3.
+
+Lockless readers such as __inet_lookup_established() handle this with
+refcount_inc_not_zero(), but bpf_iter_tcp_established_batch() uses plain
+sock_hold() while holding the bucket lock, on the assumption that the
+lock guarantees sk_refcnt > 0. That assumption does not hold for
+request_sock:
+
+ CPU 0 CPU 1
+ ----- -----
+ tcp_conn_request()
+ reqsk_queue_hash_req()
+ inet_ehash_insert(req)
+ spin_lock(bucket)
+ __sk_nulls_add_node_rcu(req) // rsk_refcnt == 0
+ spin_unlock(bucket)
+ bpf_iter_tcp_established_batch()
+ spin_lock(bucket)
+ sock_hold(req) <-- addition on 0
+ spin_unlock(bucket)
+ refcount_set(&req->rsk_refcnt, 3) // clobbers saturated value
+
+which surfaces as:
+
+ refcount_t: addition on 0; use-after-free.
+ WARNING: lib/refcount.c:25 at refcount_warn_saturate+0x48/0x90, CPU#1
+ Call Trace:
+ bpf_iter_tcp_established_batch+0x14e/0x170
+ bpf_iter_tcp_batch+0x53/0x200
+ bpf_iter_tcp_seq_next+0x27/0x70
+ bpf_seq_read+0x107/0x410
+ vfs_read+0xb9/0x380
+
+The iterator's stolen reference is lost when the publishing CPU's
+refcount_set() overwrites the count, leaving the socket one reference
+short. When the last legitimate owner drops its reference the reqsk is
+freed while still reachable, leading to use-after-free.
+
+This reproduces in seconds with tcp_syncookies=0, a handful of threads
+doing connect()/close() to a local listener while others read an
+iter/tcp link in a tight loop.
+
+Use refcount_inc_not_zero() and skip the socket on failure. A skipped
+socket is still part of the bucket, so keep counting it in expected.
+The reallocations are sized from expected, and a request sock whose
+refcount gets published while the lock is held across the last realloc
+must already have room.
+
+A skipped socket is counted in expected but never batched, so end_sk
+can be short of expected on a batch that is actually complete. Decide
+completeness by whether the walk left any socket behind instead. The
+WARN after the locked realloc checks the same, replacing an
+end_sk == expected check that could not hold on that path since
+commit cdec67a489d4 ("bpf: tcp: Make sure iter->batch always
+contains a full bucket snapshot").
+
+If every matching socket in a bucket is mid-init (refcount 0), end_sk
+stays 0. Advance to the next bucket rather than returning a batch entry
+that was never filled this round.
+
+Fixes: 04c7820b776f ("bpf: tcp: Bpf iter batching and lock_sock")
+Assisted-by: Claude:unspecified
+Signed-off-by: Jose Fernandez (Anthropic) <jose.fernandez@linux.dev>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Link: https://lore.kernel.org/bpf/20260730-bpf-iter-tcp-refcnt-v3-1-754b9c8a6717@linux.dev
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 43 ++++++++++++++++++++++++-------------------
+ 1 file changed, 24 insertions(+), 19 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index 7785c177f2cd3..08154b1f4a8c4 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -3199,24 +3199,24 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,
+ {
+ struct bpf_tcp_iter_state *iter = seq->private;
+ struct hlist_nulls_node *node;
+- unsigned int expected = 1;
+- struct sock *sk;
+-
+- sock_hold(*start_sk);
+- iter->batch[iter->end_sk++].sk = *start_sk;
++ struct sock *sk = *start_sk;
++ unsigned int expected = 0;
+
+- sk = sk_nulls_next(*start_sk);
+ *start_sk = NULL;
+ sk_nulls_for_each_from(sk, node) {
+- if (seq_sk_match(seq, sk)) {
+- if (iter->end_sk < iter->max_sk) {
+- sock_hold(sk);
+- iter->batch[iter->end_sk++].sk = sk;
+- } else if (!*start_sk) {
+- /* Remember where we left off. */
+- *start_sk = sk;
+- }
+- expected++;
++ if (!seq_sk_match(seq, sk))
++ continue;
++ expected++;
++ if (iter->end_sk < iter->max_sk) {
++ /* reqsk_queue_hash_req() inserts with sk_refcnt == 0
++ * and refcount_set()s it after the bucket lock drops.
++ */
++ if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
++ continue;
++ iter->batch[iter->end_sk++].sk = sk;
++ } else if (!*start_sk) {
++ /* Remember where we left off. */
++ *start_sk = sk;
+ }
+ }
+
+@@ -3254,12 +3254,13 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ struct sock *sk;
+ int err;
+
++again:
+ sk = bpf_iter_tcp_resume(seq);
+ if (!sk)
+ return NULL; /* Done */
+
+ expected = bpf_iter_fill_batch(seq, &sk);
+- if (likely(iter->end_sk == expected))
++ if (likely(!sk))
+ goto done;
+
+ /* Batch size was too small. */
+@@ -3275,7 +3276,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ return NULL; /* Done */
+
+ expected = bpf_iter_fill_batch(seq, &sk);
+- if (likely(iter->end_sk == expected))
++ if (likely(!sk))
+ goto done;
+
+ /* Batch size was still too small. Hold onto the lock while we try
+@@ -3288,10 +3289,14 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ return ERR_PTR(err);
+ }
+
+- expected = bpf_iter_fill_batch(seq, &sk);
+- WARN_ON_ONCE(iter->end_sk != expected);
++ bpf_iter_fill_batch(seq, &sk);
++ WARN_ON_ONCE(sk);
+ done:
+ bpf_iter_tcp_unlock_bucket(seq);
++ if (unlikely(!iter->end_sk)) {
++ ++iter->state.bucket;
++ goto again;
++ }
+ return iter->batch[0].sk;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 139dc03673e06ef584644ff2116efe20a1a97d4c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Jul 2025 11:09:07 -0700
+Subject: bpf: tcp: Get rid of st_bucket_done
+
+From: Jordan Rife <jordan@jrife.io>
+
+[ Upstream commit e25ab9b874a4bd8c6e3e5ce66cbe8a1dd4096e2e ]
+
+Get rid of the st_bucket_done field to simplify TCP iterator state and
+logic. Before, st_bucket_done could be false if bpf_iter_tcp_batch
+returned a partial batch; however, with the last patch ("bpf: tcp: Make
+sure iter->batch always contains a full bucket snapshot"),
+st_bucket_done == true is equivalent to iter->cur_sk == iter->end_sk.
+
+Signed-off-by: Jordan Rife <jordan@jrife.io>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 14 ++++++--------
+ 1 file changed, 6 insertions(+), 8 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index 2bcc037521930..c18eee7ed5378 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -3004,7 +3004,6 @@ struct bpf_tcp_iter_state {
+ unsigned int end_sk;
+ unsigned int max_sk;
+ struct sock **batch;
+- bool st_bucket_done;
+ };
+
+ struct bpf_iter__tcp {
+@@ -3027,8 +3026,10 @@ static int tcp_prog_seq_show(struct bpf_prog *prog, struct bpf_iter_meta *meta,
+
+ static void bpf_iter_tcp_put_batch(struct bpf_tcp_iter_state *iter)
+ {
+- while (iter->cur_sk < iter->end_sk)
+- sock_gen_put(iter->batch[iter->cur_sk++]);
++ unsigned int cur_sk = iter->cur_sk;
++
++ while (cur_sk < iter->end_sk)
++ sock_gen_put(iter->batch[cur_sk++]);
+ }
+
+ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+@@ -3145,7 +3146,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ * one by one in the current bucket and eventually find out
+ * it has to advance to the next bucket.
+ */
+- if (iter->st_bucket_done) {
++ if (iter->end_sk && iter->cur_sk == iter->end_sk) {
+ st->offset = 0;
+ st->bucket++;
+ if (st->state == TCP_SEQ_STATE_LISTENING &&
+@@ -3157,7 +3158,6 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+
+ iter->cur_sk = 0;
+ iter->end_sk = 0;
+- iter->st_bucket_done = true;
+
+ sk = tcp_seek_last_pos(seq);
+ if (!sk)
+@@ -3305,10 +3305,8 @@ static void bpf_iter_tcp_seq_stop(struct seq_file *seq, void *v)
+ (void)tcp_prog_seq_show(prog, &meta, v, 0);
+ }
+
+- if (iter->cur_sk < iter->end_sk) {
++ if (iter->cur_sk < iter->end_sk)
+ bpf_iter_tcp_put_batch(iter);
+- iter->st_bucket_done = false;
+- }
+ }
+
+ static const struct seq_operations bpf_iter_tcp_seq_ops = {
+--
+2.53.0
+
--- /dev/null
+From 009d9d25c6e9cbf1db069fb3ff0686e37c2a939b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Jul 2025 11:09:05 -0700
+Subject: bpf: tcp: Make mem flags configurable through
+ bpf_iter_tcp_realloc_batch
+
+From: Jordan Rife <jordan@jrife.io>
+
+[ Upstream commit 8271bec9fc1cfe522b1a18cacbefd6712a3d41c2 ]
+
+Prepare for the next patch which needs to be able to choose either
+GFP_USER or GFP_NOWAIT for calls to bpf_iter_tcp_realloc_batch.
+
+Signed-off-by: Jordan Rife <jordan@jrife.io>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index a9f3ee89302ce..cffa0fc1ae6e1 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -3032,12 +3032,12 @@ static void bpf_iter_tcp_put_batch(struct bpf_tcp_iter_state *iter)
+ }
+
+ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+- unsigned int new_batch_sz)
++ unsigned int new_batch_sz, gfp_t flags)
+ {
+ struct sock **new_batch;
+
+ new_batch = kvmalloc(sizeof(*new_batch) * new_batch_sz,
+- GFP_USER | __GFP_NOWARN);
++ flags | __GFP_NOWARN);
+ if (!new_batch)
+ return -ENOMEM;
+
+@@ -3149,7 +3149,8 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ return sk;
+ }
+
+- if (!resized && !bpf_iter_tcp_realloc_batch(iter, expected * 3 / 2)) {
++ if (!resized && !bpf_iter_tcp_realloc_batch(iter, expected * 3 / 2,
++ GFP_USER)) {
+ resized = true;
+ goto again;
+ }
+@@ -3578,7 +3579,7 @@ static int bpf_iter_init_tcp(void *priv_data, struct bpf_iter_aux_info *aux)
+ if (err)
+ return err;
+
+- err = bpf_iter_tcp_realloc_batch(iter, INIT_BATCH_SZ);
++ err = bpf_iter_tcp_realloc_batch(iter, INIT_BATCH_SZ, GFP_USER);
+ if (err) {
+ bpf_iter_fini_seq_net(priv_data);
+ return err;
+--
+2.53.0
+
--- /dev/null
+From f3e42445ab9d1223446821a4e07ebd1692bfd80b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Jul 2025 11:09:06 -0700
+Subject: bpf: tcp: Make sure iter->batch always contains a full bucket
+ snapshot
+
+From: Jordan Rife <jordan@jrife.io>
+
+[ Upstream commit cdec67a489d4fdae3e83e04fca0419136a83c4c2 ]
+
+Require that iter->batch always contains a full bucket snapshot. This
+invariant is important to avoid skipping or repeating sockets during
+iteration when combined with the next few patches. Before, there were
+two cases where a call to bpf_iter_tcp_batch may only capture part of a
+bucket:
+
+1. When bpf_iter_tcp_realloc_batch() returns -ENOMEM.
+2. When more sockets are added to the bucket while calling
+ bpf_iter_tcp_realloc_batch(), making the updated batch size
+ insufficient.
+
+In cases where the batch size only covers part of a bucket, it is
+possible to forget which sockets were already visited, especially if we
+have to process a bucket in more than two batches. This forces us to
+choose between repeating or skipping sockets, so don't allow this:
+
+1. Stop iteration and propagate -ENOMEM up to userspace if reallocation
+ fails instead of continuing with a partial batch.
+2. Try bpf_iter_tcp_realloc_batch() with GFP_USER just as before, but if
+ we still aren't able to capture the full bucket, call
+ bpf_iter_tcp_realloc_batch() again while holding the bucket lock to
+ guarantee the bucket does not change. On the second attempt use
+ GFP_NOWAIT since we hold onto the spin lock.
+
+I did some manual testing to exercise the code paths where GFP_NOWAIT is
+used and where ERR_PTR(err) is returned. I used the realloc test cases
+included later in this series to trigger a scenario where a realloc
+happens inside bpf_iter_tcp_batch and made a small code tweak to force
+the first realloc attempt to allocate a too-small batch, thus requiring
+another attempt with GFP_NOWAIT. Some printks showed both reallocs with
+the tests passing:
+
+Jun 27 00:00:53 crow kernel: again GFP_USER
+Jun 27 00:00:53 crow kernel: again GFP_NOWAIT
+Jun 27 00:00:53 crow kernel: again GFP_USER
+Jun 27 00:00:53 crow kernel: again GFP_NOWAIT
+
+With this setup, I also forced each of the bpf_iter_tcp_realloc_batch
+calls to return -ENOMEM to ensure that iteration ends and that the
+read() in userspace fails.
+
+Signed-off-by: Jordan Rife <jordan@jrife.io>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 109 +++++++++++++++++++++++++++++++-------------
+ 1 file changed, 77 insertions(+), 32 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index cffa0fc1ae6e1..2bcc037521930 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -3041,7 +3041,7 @@ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+ if (!new_batch)
+ return -ENOMEM;
+
+- bpf_iter_tcp_put_batch(iter);
++ memcpy(new_batch, iter->batch, sizeof(*iter->batch) * iter->end_sk);
+ kvfree(iter->batch);
+ iter->batch = new_batch;
+ iter->max_sk = new_batch_sz;
+@@ -3050,69 +3050,95 @@ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+ }
+
+ static unsigned int bpf_iter_tcp_listening_batch(struct seq_file *seq,
+- struct sock *start_sk)
++ struct sock **start_sk)
+ {
+- struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
+ struct bpf_tcp_iter_state *iter = seq->private;
+- struct tcp_iter_state *st = &iter->state;
+ struct hlist_nulls_node *node;
+ unsigned int expected = 1;
+ struct sock *sk;
+
+- sock_hold(start_sk);
+- iter->batch[iter->end_sk++] = start_sk;
++ sock_hold(*start_sk);
++ iter->batch[iter->end_sk++] = *start_sk;
+
+- sk = sk_nulls_next(start_sk);
++ sk = sk_nulls_next(*start_sk);
++ *start_sk = NULL;
+ sk_nulls_for_each_from(sk, node) {
+ if (seq_sk_match(seq, sk)) {
+ if (iter->end_sk < iter->max_sk) {
+ sock_hold(sk);
+ iter->batch[iter->end_sk++] = sk;
++ } else if (!*start_sk) {
++ /* Remember where we left off. */
++ *start_sk = sk;
+ }
+ expected++;
+ }
+ }
+- spin_unlock(&hinfo->lhash2[st->bucket].lock);
+
+ return expected;
+ }
+
+ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,
+- struct sock *start_sk)
++ struct sock **start_sk)
+ {
+- struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
+ struct bpf_tcp_iter_state *iter = seq->private;
+- struct tcp_iter_state *st = &iter->state;
+ struct hlist_nulls_node *node;
+ unsigned int expected = 1;
+ struct sock *sk;
+
+- sock_hold(start_sk);
+- iter->batch[iter->end_sk++] = start_sk;
++ sock_hold(*start_sk);
++ iter->batch[iter->end_sk++] = *start_sk;
+
+- sk = sk_nulls_next(start_sk);
++ sk = sk_nulls_next(*start_sk);
++ *start_sk = NULL;
+ sk_nulls_for_each_from(sk, node) {
+ if (seq_sk_match(seq, sk)) {
+ if (iter->end_sk < iter->max_sk) {
+ sock_hold(sk);
+ iter->batch[iter->end_sk++] = sk;
++ } else if (!*start_sk) {
++ /* Remember where we left off. */
++ *start_sk = sk;
+ }
+ expected++;
+ }
+ }
+- spin_unlock_bh(inet_ehash_lockp(hinfo, st->bucket));
+
+ return expected;
+ }
+
++static unsigned int bpf_iter_fill_batch(struct seq_file *seq,
++ struct sock **start_sk)
++{
++ struct bpf_tcp_iter_state *iter = seq->private;
++ struct tcp_iter_state *st = &iter->state;
++
++ if (st->state == TCP_SEQ_STATE_LISTENING)
++ return bpf_iter_tcp_listening_batch(seq, start_sk);
++ else
++ return bpf_iter_tcp_established_batch(seq, start_sk);
++}
++
++static void bpf_iter_tcp_unlock_bucket(struct seq_file *seq)
++{
++ struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
++ struct bpf_tcp_iter_state *iter = seq->private;
++ struct tcp_iter_state *st = &iter->state;
++
++ if (st->state == TCP_SEQ_STATE_LISTENING)
++ spin_unlock(&hinfo->lhash2[st->bucket].lock);
++ else
++ spin_unlock_bh(inet_ehash_lockp(hinfo, st->bucket));
++}
++
+ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ {
+ struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
+ struct bpf_tcp_iter_state *iter = seq->private;
+ struct tcp_iter_state *st = &iter->state;
+ unsigned int expected;
+- bool resized = false;
+ struct sock *sk;
++ int err;
+
+ /* The st->bucket is done. Directly advance to the next
+ * bucket instead of having the tcp_seek_last_pos() to skip
+@@ -3129,33 +3155,52 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ }
+ }
+
+-again:
+- /* Get a new batch */
+ iter->cur_sk = 0;
+ iter->end_sk = 0;
+- iter->st_bucket_done = false;
++ iter->st_bucket_done = true;
+
+ sk = tcp_seek_last_pos(seq);
+ if (!sk)
+ return NULL; /* Done */
+
+- if (st->state == TCP_SEQ_STATE_LISTENING)
+- expected = bpf_iter_tcp_listening_batch(seq, sk);
+- else
+- expected = bpf_iter_tcp_established_batch(seq, sk);
++ expected = bpf_iter_fill_batch(seq, &sk);
++ if (likely(iter->end_sk == expected))
++ goto done;
+
+- if (iter->end_sk == expected) {
+- iter->st_bucket_done = true;
+- return sk;
+- }
++ /* Batch size was too small. */
++ bpf_iter_tcp_unlock_bucket(seq);
++ bpf_iter_tcp_put_batch(iter);
++ err = bpf_iter_tcp_realloc_batch(iter, expected * 3 / 2,
++ GFP_USER);
++ if (err)
++ return ERR_PTR(err);
++
++ iter->cur_sk = 0;
++ iter->end_sk = 0;
++
++ sk = tcp_seek_last_pos(seq);
++ if (!sk)
++ return NULL; /* Done */
++
++ expected = bpf_iter_fill_batch(seq, &sk);
++ if (likely(iter->end_sk == expected))
++ goto done;
+
+- if (!resized && !bpf_iter_tcp_realloc_batch(iter, expected * 3 / 2,
+- GFP_USER)) {
+- resized = true;
+- goto again;
++ /* Batch size was still too small. Hold onto the lock while we try
++ * again with a larger batch to make sure the current bucket's size
++ * does not change in the meantime.
++ */
++ err = bpf_iter_tcp_realloc_batch(iter, expected, GFP_NOWAIT);
++ if (err) {
++ bpf_iter_tcp_unlock_bucket(seq);
++ return ERR_PTR(err);
+ }
+
+- return sk;
++ expected = bpf_iter_fill_batch(seq, &sk);
++ WARN_ON_ONCE(iter->end_sk != expected);
++done:
++ bpf_iter_tcp_unlock_bucket(seq);
++ return iter->batch[0];
+ }
+
+ static void *bpf_iter_tcp_seq_start(struct seq_file *seq, loff_t *pos)
+--
+2.53.0
+
--- /dev/null
+From 7e3b3d5ea0bbccea9dc8004d4d619bcaa8ec62f1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Jul 2025 11:09:08 -0700
+Subject: bpf: tcp: Use bpf_tcp_iter_batch_item for bpf_tcp_iter_state batch
+ items
+
+From: Jordan Rife <jordan@jrife.io>
+
+[ Upstream commit efeb820951ebf3778830256496ff72d00d135310 ]
+
+Prepare for the next patch that tracks cookies between iterations by
+converting struct sock **batch to union bpf_tcp_iter_batch_item *batch
+inside struct bpf_tcp_iter_state.
+
+Signed-off-by: Jordan Rife <jordan@jrife.io>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 24 ++++++++++++++----------
+ 1 file changed, 14 insertions(+), 10 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index c18eee7ed5378..6a8241367672b 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -2998,12 +2998,16 @@ static int tcp4_seq_show(struct seq_file *seq, void *v)
+ }
+
+ #ifdef CONFIG_BPF_SYSCALL
++union bpf_tcp_iter_batch_item {
++ struct sock *sk;
++};
++
+ struct bpf_tcp_iter_state {
+ struct tcp_iter_state state;
+ unsigned int cur_sk;
+ unsigned int end_sk;
+ unsigned int max_sk;
+- struct sock **batch;
++ union bpf_tcp_iter_batch_item *batch;
+ };
+
+ struct bpf_iter__tcp {
+@@ -3029,13 +3033,13 @@ static void bpf_iter_tcp_put_batch(struct bpf_tcp_iter_state *iter)
+ unsigned int cur_sk = iter->cur_sk;
+
+ while (cur_sk < iter->end_sk)
+- sock_gen_put(iter->batch[cur_sk++]);
++ sock_gen_put(iter->batch[cur_sk++].sk);
+ }
+
+ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+ unsigned int new_batch_sz, gfp_t flags)
+ {
+- struct sock **new_batch;
++ union bpf_tcp_iter_batch_item *new_batch;
+
+ new_batch = kvmalloc(sizeof(*new_batch) * new_batch_sz,
+ flags | __GFP_NOWARN);
+@@ -3059,7 +3063,7 @@ static unsigned int bpf_iter_tcp_listening_batch(struct seq_file *seq,
+ struct sock *sk;
+
+ sock_hold(*start_sk);
+- iter->batch[iter->end_sk++] = *start_sk;
++ iter->batch[iter->end_sk++].sk = *start_sk;
+
+ sk = sk_nulls_next(*start_sk);
+ *start_sk = NULL;
+@@ -3067,7 +3071,7 @@ static unsigned int bpf_iter_tcp_listening_batch(struct seq_file *seq,
+ if (seq_sk_match(seq, sk)) {
+ if (iter->end_sk < iter->max_sk) {
+ sock_hold(sk);
+- iter->batch[iter->end_sk++] = sk;
++ iter->batch[iter->end_sk++].sk = sk;
+ } else if (!*start_sk) {
+ /* Remember where we left off. */
+ *start_sk = sk;
+@@ -3088,7 +3092,7 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,
+ struct sock *sk;
+
+ sock_hold(*start_sk);
+- iter->batch[iter->end_sk++] = *start_sk;
++ iter->batch[iter->end_sk++].sk = *start_sk;
+
+ sk = sk_nulls_next(*start_sk);
+ *start_sk = NULL;
+@@ -3096,7 +3100,7 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,
+ if (seq_sk_match(seq, sk)) {
+ if (iter->end_sk < iter->max_sk) {
+ sock_hold(sk);
+- iter->batch[iter->end_sk++] = sk;
++ iter->batch[iter->end_sk++].sk = sk;
+ } else if (!*start_sk) {
+ /* Remember where we left off. */
+ *start_sk = sk;
+@@ -3200,7 +3204,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ WARN_ON_ONCE(iter->end_sk != expected);
+ done:
+ bpf_iter_tcp_unlock_bucket(seq);
+- return iter->batch[0];
++ return iter->batch[0].sk;
+ }
+
+ static void *bpf_iter_tcp_seq_start(struct seq_file *seq, loff_t *pos)
+@@ -3235,11 +3239,11 @@ static void *bpf_iter_tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+ * st->bucket. See tcp_seek_last_pos().
+ */
+ st->offset++;
+- sock_gen_put(iter->batch[iter->cur_sk++]);
++ sock_gen_put(iter->batch[iter->cur_sk++].sk);
+ }
+
+ if (iter->cur_sk < iter->end_sk)
+- sk = iter->batch[iter->cur_sk];
++ sk = iter->batch[iter->cur_sk].sk;
+ else
+ sk = bpf_iter_tcp_batch(seq);
+
+--
+2.53.0
+
--- /dev/null
+From 85600276fea216f797cf6d957f07becd1f798476 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 14:53:52 +0300
+Subject: btrfs: fix memory leak in btrfs_do_encoded_write()
+
+From: Dmitry Antipov <dmantipov@yandex.ru>
+
+[ Upstream commit d2a4e4e626b2f4670b69b430c357f03f53eb6632 ]
+
+Local fuzzing of 6.12.94 has found the following memory leak:
+
+Unreferenced object 0xffff888018050a80 (size 64):
+ comm "syz.0.17", pid 10297, jiffies 4294953601
+ hex dump (first 32 bytes):
+ 00 10 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................
+ 10 0a 05 18 80 88 ff ff 10 0a 05 18 80 88 ff ff ................
+ backtrace (crc a8a6fc29):
+ kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
+ slab_post_alloc_hook mm/slub.c:4152 [inline]
+ slab_alloc_node mm/slub.c:4197 [inline]
+ __kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358
+ kmalloc_noprof include/linux/slab.h:878 [inline]
+ extent_changeset_alloc fs/btrfs/extent_io.h:207 [inline]
+ qgroup_reserve_data+0x1c5/0x7d0 fs/btrfs/qgroup.c:4305
+ btrfs_qgroup_reserve_data+0x2e/0xb0 fs/btrfs/qgroup.c:4355
+ btrfs_do_encoded_write+0x92e/0x1040 fs/btrfs/inode.c:9746
+ btrfs_encoded_write fs/btrfs/file.c:1482 [inline]
+ btrfs_do_write_iter+0x280/0x610 fs/btrfs/file.c:1507
+ btrfs_ioctl_encoded_write+0x3d6/0x490 fs/btrfs/ioctl.c:4738
+ btrfs_ioctl+0x6f9/0xc90 fs/btrfs/ioctl.c:-1
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:906 [inline]
+ __se_sys_ioctl+0xf9/0x170 fs/ioctl.c:892
+ do_syscall_x64 arch/x86/entry/common.c:47 [inline]
+ do_syscall_64+0xbe/0x1a0 arch/x86/entry/common.c:78
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Unreferenced object 0xffff888018050a00 (size 64):
+ comm "syz.0.17", pid 10297, jiffies 4294953601
+ hex dump (first 32 bytes):
+ 00 00 00 00 00 00 00 00 ff 0f 00 00 00 00 00 00 ................
+ 90 0a 05 18 80 88 ff ff 90 0a 05 18 80 88 ff ff ................
+ backtrace (crc cb5c9580):
+ kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
+ slab_post_alloc_hook mm/slub.c:4152 [inline]
+ slab_alloc_node mm/slub.c:4197 [inline]
+ __kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358
+ kmalloc_noprof include/linux/slab.h:878 [inline]
+ kzalloc_noprof include/linux/slab.h:1014 [inline]
+ ulist_prealloc+0x9c/0x110 fs/btrfs/ulist.c:114
+ extent_changeset_prealloc fs/btrfs/extent_io.h:217 [inline]
+ __set_extent_bit+0x16b/0x1a70 fs/btrfs/extent-io-tree.c:1086
+ set_record_extent_bits+0x50/0x90 fs/btrfs/extent-io-tree.c:1821
+ qgroup_reserve_data+0x274/0x7d0 fs/btrfs/qgroup.c:4312
+ btrfs_qgroup_reserve_data+0x2e/0xb0 fs/btrfs/qgroup.c:4355
+ btrfs_do_encoded_write+0x92e/0x1040 fs/btrfs/inode.c:9746
+ btrfs_encoded_write fs/btrfs/file.c:1482 [inline]
+ btrfs_do_write_iter+0x280/0x610 fs/btrfs/file.c:1507
+ btrfs_ioctl_encoded_write+0x3d6/0x490 fs/btrfs/ioctl.c:4738
+ btrfs_ioctl+0x6f9/0xc90 fs/btrfs/ioctl.c:-1
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:906 [inline]
+ __se_sys_ioctl+0xf9/0x170 fs/ioctl.c:892
+ do_syscall_x64 arch/x86/entry/common.c:47 [inline]
+ do_syscall_64+0xbe/0x1a0 arch/x86/entry/common.c:78
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Fix this by freeing an extent changeset before returning from
+btrfs_do_encoded_write().
+
+Fixes: 7c0c7269f7b5 ("btrfs: add BTRFS_IOC_ENCODED_WRITE")
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/inode.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index f60f8bf38dc50..ab7f19ca21457 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -9684,6 +9684,7 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
+ }
+ kvfree(folios);
+ out:
++ extent_changeset_free(data_reserved);
+ if (ret >= 0)
+ iocb->ki_pos += encoded->len;
+ return ret;
+--
+2.53.0
+
--- /dev/null
+From 9c6d694eb55ebc03717e944215ae8b4df9955e92 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jul 2026 04:29:10 +0000
+Subject: counter: microchip-tcb-capture: Fix DT channel validation
+
+From: Babanpreet Singh <bbnpreetsingh@gmail.com>
+
+[ Upstream commit f1a3a9946aab611dd2200c01ff122f64b033dad2 ]
+
+mchp_tc_probe() reads the devicetree "reg" cell - a u32, per the API
+contract of of_property_read_u32_index() - into a signed int, so the
+bounds check "channel > 2" fails to reject cell values at or above
+0x80000000: reinterpreted as a negative int, they compare below 2 and
+pass validation.
+
+A malformed devicetree can therefore drive a negative channel into the
+ATMEL_TC_REG() offset arithmetic, making the driver access syscon
+regmap offsets outside the TC block's register window, and into the
+"t%d_clk" clock-name formatting, where it truncates clk_name (sized
+for "t0_clk".."t2_clk").
+
+Declare channel as u32, matching the API contract; the unsigned
+comparison then rejects everything except channels 0..2. Adjust the
+format specifier to %u accordingly, which also resolves the W=1
+warning that exposed the gap:
+
+ microchip-tcb-capture.c:520:56: warning: '%d' directive output may
+ be truncated writing between 1 and 11 bytes into a region of size
+ 6 [-Wformat-truncation=]
+ note: directive argument in the range [-2147483648, 2]
+
+No behavior change for well-formed devicetrees: channels 0..2 take
+identical paths before and after.
+
+Fixes: 106b104137fd ("counter: Add microchip TCB capture counter")
+Assisted-by: Claude:claude-fable-5 [gcc W=1]
+Signed-off-by: Babanpreet Singh <bbnpreetsingh@gmail.com>
+Reviewed-by: Joshua Crofts <joshua.crofts1@gmail.com>
+Link: https://lore.kernel.org/r/20260714042910.7-1-bbnpreetsingh@gmail.com
+Signed-off-by: William Breathitt Gray <wbg@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/counter/microchip-tcb-capture.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/counter/microchip-tcb-capture.c b/drivers/counter/microchip-tcb-capture.c
+index 461f57f66631c..fbd1afe178a36 100644
+--- a/drivers/counter/microchip-tcb-capture.c
++++ b/drivers/counter/microchip-tcb-capture.c
+@@ -309,7 +309,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
+ char clk_name[7];
+ struct regmap *regmap;
+ struct clk *clk[3];
+- int channel;
++ u32 channel;
+ int ret, i;
+
+ counter = devm_counter_alloc(&pdev->dev, sizeof(*priv));
+@@ -343,7 +343,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
+
+ priv->channel[i] = channel;
+
+- snprintf(clk_name, sizeof(clk_name), "t%d_clk", channel);
++ snprintf(clk_name, sizeof(clk_name), "t%u_clk", channel);
+
+ clk[i] = of_clk_get_by_name(np->parent, clk_name);
+ if (IS_ERR(clk[i])) {
+--
+2.53.0
+
--- /dev/null
+From 1f8dec0746a763ff605a09a5f978abfb1954dab6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 11:06:00 +0300
+Subject: devlink: fix net namespace reference leak in reload
+
+From: Or Har-Toov <ohartoov@nvidia.com>
+
+[ Upstream commit 1c4dac9bf1d2ac31da63b794bdec697777cbd0fd ]
+
+devlink_nl_reload_doit() calls devlink_netns_get(), which returns a net
+with a held reference. When the requested namespace differs from the
+current one and the reload action is not DRIVER_REINIT, the function
+returns -EOPNOTSUPP without releasing the reference. Add the missing
+put_net() on this error path.
+
+Fixes: 2edd92570441 ("devlink: don't allow to change net namespace for FW_ACTIVATE reload action")
+Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
+Reviewed-by: Jiri Pirko <jiri@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Reviewed-by: Antoine Tenart <atenart@kernel.org>
+Link: https://patch.msgid.link/20260729080600.2427721-1-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/devlink/dev.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/devlink/dev.c b/net/devlink/dev.c
+index 13c73f50da3d1..fc109acd4e844 100644
+--- a/net/devlink/dev.c
++++ b/net/devlink/dev.c
+@@ -579,6 +579,7 @@ int devlink_nl_reload_doit(struct sk_buff *skb, struct genl_info *info)
+ action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) {
+ NL_SET_ERR_MSG_MOD(info->extack,
+ "Changing namespace is only supported for reinit action");
++ put_net(dest_net);
+ return -EOPNOTSUPP;
+ }
+ }
+--
+2.53.0
+
--- /dev/null
+From 832ccf4113810dad4ebb60a53cab7ed017244a79 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jul 2026 10:38:06 +0800
+Subject: drm/bridge: ps8640: propagate AUX transfer register errors
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 20697ecb299cd77b4cf8b28f655e56606b0472d8 ]
+
+ps8640_aux_transfer_msg() programs the AUX address registers, starts the
+AUX transfer, waits for SWAUX_SEND to clear, and reads the AUX status
+register. Several of those regmap operations have return values, but the
+function only checks a stale ret after the status read.
+
+Propagate failures from the address write, transfer start, completion
+poll, and status read. This avoids returning a transfer length when the
+bridge register transaction or AUX completion wait failed.
+
+Fixes: 13afcdd7277e ("drm/bridge: parade-ps8640: Add support for AUX channel")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Link: https://patch.msgid.link/20260723103509.2-ps8640-v2-pengpeng@iscas.ac.cn
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/bridge/parade-ps8640.c | 27 ++++++++++++++++++++------
+ 1 file changed, 21 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
+index 14d4dcf239da8..61ea855e55d87 100644
+--- a/drivers/gpu/drm/bridge/parade-ps8640.c
++++ b/drivers/gpu/drm/bridge/parade-ps8640.c
+@@ -258,8 +258,14 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
+ addr_len[PAGE0_SWAUX_LENGTH - base] = (len == 0) ? SWAUX_NO_PAYLOAD :
+ ((len - 1) & SWAUX_LENGTH_MASK);
+
+- regmap_bulk_write(map, PAGE0_SWAUX_ADDR_7_0, addr_len,
+- ARRAY_SIZE(addr_len));
++ ret = regmap_bulk_write(map, PAGE0_SWAUX_ADDR_7_0, addr_len,
++ ARRAY_SIZE(addr_len));
++ if (ret) {
++ DRM_DEV_ERROR(dev,
++ "failed to write AUX address %#x, len %zu: %d\n",
++ msg->address, len, ret);
++ return ret;
++ }
+
+ if (len && (request == DP_AUX_NATIVE_WRITE ||
+ request == DP_AUX_I2C_WRITE)) {
+@@ -275,13 +281,22 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
+ }
+ }
+
+- regmap_write(map, PAGE0_SWAUX_CTRL, SWAUX_SEND);
++ ret = regmap_write(map, PAGE0_SWAUX_CTRL, SWAUX_SEND);
++ if (ret) {
++ DRM_DEV_ERROR(dev, "failed to start AUX transfer: %d\n", ret);
++ return ret;
++ }
+
+ /* Zero delay loop because i2c transactions are slow already */
+- regmap_read_poll_timeout(map, PAGE0_SWAUX_CTRL, data,
+- !(data & SWAUX_SEND), 0, 50 * 1000);
++ ret = regmap_read_poll_timeout(map, PAGE0_SWAUX_CTRL, data,
++ !(data & SWAUX_SEND), 0, 50 * 1000);
++ if (ret) {
++ DRM_DEV_ERROR(dev, "failed to complete AUX transfer: %d\n",
++ ret);
++ return ret;
++ }
+
+- regmap_read(map, PAGE0_SWAUX_STATUS, &data);
++ ret = regmap_read(map, PAGE0_SWAUX_STATUS, &data);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to read PAGE0_SWAUX_STATUS: %d\n",
+ ret);
+--
+2.53.0
+
--- /dev/null
+From 09810a3f6ddacb2cfe1759de76979bac22a5cf8b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 23:26:30 -0700
+Subject: enic: fix tx_hang_reset use-after-free on device removal
+
+From: Satish Kharat <satishkh@cisco.com>
+
+[ Upstream commit ec680ea4ba1bca92a767fb7e7869758bfdd886e3 ]
+
+enic_remove() cancels the reset and change_mtu_work items but does not
+cancel tx_hang_reset. A TX timeout that fires while the device is being
+removed can schedule enic_tx_hang_reset() so that it runs after
+free_netdev(), resulting in a use-after-free.
+
+cancel_work_sync() alone is not sufficient here: the still-live watchdog
+and notify paths can re-schedule these work items in the window between
+the cancel and unregister_netdev(). Use disable_work_sync(), which
+cancels the work and blocks any subsequent schedule_work() from
+requeuing it, and apply it to the reset and change_mtu_work items as
+well so the same requeue race is closed for all teardown work.
+
+Fixes: 937317c7c109 ("enic: do hang reset only in case of tx timeout")
+Signed-off-by: Satish Kharat <satishkh@cisco.com>
+Link: https://patch.msgid.link/20260728062730.2394873-1-satishkh@cisco.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cisco/enic/enic_main.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
+index a432783756d8c..e474cef720630 100644
+--- a/drivers/net/ethernet/cisco/enic/enic_main.c
++++ b/drivers/net/ethernet/cisco/enic/enic_main.c
+@@ -3141,8 +3141,9 @@ static void enic_remove(struct pci_dev *pdev)
+ if (netdev) {
+ struct enic *enic = netdev_priv(netdev);
+
+- cancel_work_sync(&enic->reset);
+- cancel_work_sync(&enic->change_mtu_work);
++ disable_work_sync(&enic->reset);
++ disable_work_sync(&enic->tx_hang_reset);
++ disable_work_sync(&enic->change_mtu_work);
+ unregister_netdev(netdev);
+ enic_dev_deinit(enic);
+ vnic_dev_close(enic->vdev);
+--
+2.53.0
+
--- /dev/null
+From 63cb1925c4569549cbef27de999074df14cb6d51 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:16:45 +0800
+Subject: hwmon: (ads7828) Fix external VREF regulator handling
+
+From: Qingshuang Fu <fuqingshuang@kylinos.cn>
+
+[ Upstream commit fddb5ceaf901b050ed2a1a7deeecbf97e003435a ]
+
+The driver currently has two issues with the external VREF regulator
+handling in ads7828_probe():
+
+1. All errors from devm_regulator_get_optional() are ignored, causing the
+ driver to incorrectly fall back to internal VREF even for transient
+ errors like -EPROBE_DEFER or genuine failures like -ENOMEM.
+
+2. The external regulator is never enabled. The driver calls
+ regulator_get_voltage() without first calling regulator_enable(),
+ so the VREF pin may remain unpowered if the regulator is not
+ configured as always-on.
+
+Fix both issues by switching to devm_regulator_get_enable_read_voltage(),
+which handles regulator get, enable, and voltage read in one call.
+Only -ENODEV (no regulator specified in device tree) should trigger the
+fallback to internal VREF. All other errors are propagated to the caller.
+
+Fixes: a8ddfea09566 ("hwmon: (ads7828) Accept optional parameters from device tree")
+Signed-off-by: Qingshuang Fu <fuqingshuang@kylinos.cn>
+Link: https://lore.kernel.org/r/20260805061645.1331652-1-fffsqian@163.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ads7828.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
+index 436637264056c..20ef4992f5bb8 100644
+--- a/drivers/hwmon/ads7828.c
++++ b/drivers/hwmon/ads7828.c
+@@ -106,12 +106,11 @@ static int ads7828_probe(struct i2c_client *client)
+ struct ads7828_data *data;
+ struct device *hwmon_dev;
+ unsigned int vref_mv = ADS7828_INT_VREF_MV;
+- unsigned int vref_uv;
++ int vref_uv;
+ bool diff_input = false;
+ bool ext_vref = false;
+ unsigned int regval;
+ enum ads7828_chips chip;
+- struct regulator *reg;
+
+ data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL);
+ if (!data)
+@@ -125,9 +124,11 @@ static int ads7828_probe(struct i2c_client *client)
+ } else if (dev->of_node) {
+ diff_input = of_property_read_bool(dev->of_node,
+ "ti,differential-input");
+- reg = devm_regulator_get_optional(dev, "vref");
+- if (!IS_ERR(reg)) {
+- vref_uv = regulator_get_voltage(reg);
++ vref_uv = devm_regulator_get_enable_read_voltage(dev, "vref");
++ if (vref_uv < 0) {
++ if (vref_uv != -ENODEV)
++ return vref_uv;
++ } else {
+ vref_mv = DIV_ROUND_CLOSEST(vref_uv, 1000);
+ if (vref_mv < ADS7828_EXT_VREF_MV_MIN ||
+ vref_mv > ADS7828_EXT_VREF_MV_MAX)
+--
+2.53.0
+
--- /dev/null
+From fb2a43eb8e0a907cfa44b6b6e519a4ab1efd0205 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 07:19:20 +0000
+Subject: hwmon: (corsair-psu) fix possible out-of-bounds access on missing
+ string termination
+
+From: Wilken Gottwalt <wilken.gottwalt@posteo.net>
+
+[ Upstream commit 36c4d73ce05d1d8896c2669eb0730d35a02a2ec1 ]
+
+In theory it could be possible that the REPLY_SIZE sized buffers for
+holding the vendor and product strings could be end up missing the null
+termination (for example by malicious hardware built on purpose)
+required by the seq_printf() call. That limits the debugfs printf calls
+to a maximum string length of REPLY_SIZE.
+
+Fixes: d115b51e0e567 ("hwmon: add Corsair PSU HID controller driver")
+Signed-off-by: Wilken Gottwalt <wilken.gottwalt@posteo.net>
+Link: https://lore.kernel.org/r/anLj9gPWRoRDbQBV@monster.localdomain
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/corsair-psu.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c
+index 4ab73bcef1d12..61d1b22bc63ec 100644
+--- a/drivers/hwmon/corsair-psu.c
++++ b/drivers/hwmon/corsair-psu.c
+@@ -709,7 +709,7 @@ static int vendor_show(struct seq_file *seqf, void *unused)
+ {
+ struct corsairpsu_data *priv = seqf->private;
+
+- seq_printf(seqf, "%s\n", priv->vendor);
++ seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->vendor);
+
+ return 0;
+ }
+@@ -719,7 +719,7 @@ static int product_show(struct seq_file *seqf, void *unused)
+ {
+ struct corsairpsu_data *priv = seqf->private;
+
+- seq_printf(seqf, "%s\n", priv->product);
++ seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->product);
+
+ return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From eb613b8de08db6dfaadc9ff4e30e052f0a5e98f6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 15:42:42 -0700
+Subject: hwmon: (ltc4282) Avoid overflow in maximum power calculation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit edd11a94335747423569500a194c6eaa915f2963 ]
+
+During device initialization in ltc4282_set_max_limits(), the calculation
+of the maximum power limit can suffer from a 32-bit integer overflow.
+
+static int ltc4282_set_max_limits(struct ltc4282_state *st)
+{
+ ...
+ st->power_max = DIV_ROUND_CLOSEST(st->vsense_max * DECA * MILLI,
+ st->rsense) * st->vfs_out;
+ ...
+}
+
+The result of DIV_ROUND_CLOSEST() evaluates to a 32-bit unsigned integer
+on 32-bit architectures. This result is then multiplied by st->vfs_out,
+which is a 16-bit unsigned integer. According to C promotion rules, since
+both operands are 32-bit or smaller, the multiplication is performed in
+32-bit precision.
+
+If the device is configured with a low sense resistor value via the device
+tree (for example, 100 nano-ohms, resulting in st->rsense = 1) and the
+voltage is high, the division result can reach 343,750,000 and st->vfs_out
+can be 33,280. The product of these values is approximately 11.44 trillion,
+which exceeds the maximum capacity of a 32-bit integer and overflows
+before being stored in st->power_max.
+
+This overflow causes a truncated value to be assigned to st->power_max and
+written to the hardware limit register. An incorrect maximum power limit
+can trigger spurious power-bad faults or alarms, which may lead to the
+shutdown of the monitored power rail.
+
+Avoid the problem by calculating and storing the maximum power using 64-bit
+variables.
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282")
+Cc: Nuno Sa <nuno.sa@analog.com>
+Reviewed-by: Nuno Sá <nuno.sa@analog.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ltc4282.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c
+index e1c0d02b564b7..93e08bde29aa9 100644
+--- a/drivers/hwmon/ltc4282.c
++++ b/drivers/hwmon/ltc4282.c
+@@ -142,7 +142,7 @@ struct ltc4282_state {
+ */
+ struct ltc4282_cache in0_1_cache[LTC4282_CHAN_VGPIO];
+ u32 vsense_max;
+- long power_max;
++ s64 power_max;
+ u32 rsense;
+ u16 vdd;
+ u16 vfs_out;
+@@ -621,13 +621,12 @@ static int ltc4282_read(struct device *dev, enum hwmon_sensor_types type,
+ }
+
+ static int ltc4282_write_power_byte(const struct ltc4282_state *st, u32 reg,
+- long val)
++ s64 val)
+ {
+ u32 power;
+ u64 temp;
+
+- if (val > st->power_max)
+- val = st->power_max;
++ val = clamp(val, 0, st->power_max);
+
+ temp = val * int_pow(U8_MAX, 2) * st->rsense;
+ power = DIV64_U64_ROUND_CLOSEST(temp,
+@@ -637,7 +636,7 @@ static int ltc4282_write_power_byte(const struct ltc4282_state *st, u32 reg,
+ }
+
+ static int ltc4282_write_power_word(const struct ltc4282_state *st, u32 reg,
+- long val)
++ u64 val)
+ {
+ u64 temp = int_pow(U16_MAX, 2) * st->rsense, temp_2;
+ __be16 __raw;
+@@ -1254,7 +1253,8 @@ static int ltc4282_set_max_limits(struct ltc4282_state *st)
+ return ret;
+
+ /* Power is given by ISENSE * Vout. */
+- st->power_max = DIV_ROUND_CLOSEST(st->vsense_max * DECA * MILLI, st->rsense) * st->vfs_out;
++ st->power_max = DIV_ROUND_CLOSEST_ULL((u64)st->vsense_max * DECA * MILLI,
++ st->rsense) * st->vfs_out;
+ ret = ltc4282_write_power_byte(st, LTC4282_POWER_MAX, st->power_max);
+ if (ret)
+ return ret;
+--
+2.53.0
+
--- /dev/null
+From d786a3cac4126469ec120c715d6dc3151c38c5e8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 16:26:05 -0700
+Subject: hwmon: (ltc4282) Clamp negative current limits
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit e253dd5f9f6d875a317895bf43ec9534ed7523cb ]
+
+When a negative value is passed to ltc4282_write_curr(), the signed long
+val is cast directly to u64:
+
+drivers/hwmon/ltc4282.c:ltc4282_write_curr() {
+ /* need to pass it in millivolt */
+ u32 in = DIV_ROUND_CLOSEST_ULL((u64)val * st->rsense, DECA * MICRO);
+ ...
+}
+
+This cast converts negative inputs into large positive values. The
+subsequent division result overflows the u32 in variable, truncating
+to a pseudo-random positive value. When this is passed to
+ltc4282_write_voltage_byte(), it is clamped to the maximum limit instead
+of zero.
+
+Clamp val to 0 and to the maximum supported upper limit before the cast
+and assign the result to a 64-bit temporary variable before the division
+to avoid the underflow and an also possible overflow.
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282")
+Cc: Nuno Sa <nuno.sa@analog.com>
+Reviewed-by: Nuno Sá <nuno.sa@analog.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ltc4282.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c
+index 93e08bde29aa9..0e7449db3158f 100644
+--- a/drivers/hwmon/ltc4282.c
++++ b/drivers/hwmon/ltc4282.c
+@@ -15,6 +15,7 @@
+ #include <linux/hwmon-sysfs.h>
+ #include <linux/i2c.h>
+ #include <linux/math.h>
++#include <linux/math64.h>
+ #include <linux/minmax.h>
+ #include <linux/module.h>
+ #include <linux/mod_devicetable.h>
+@@ -945,8 +946,11 @@ static int ltc4282_curr_reset_hist(struct ltc4282_state *st)
+ static int ltc4282_write_curr(struct ltc4282_state *st, u32 attr,
+ long val)
+ {
++ s32 ulimit = min_t(u64, INT_MAX,
++ div_u64((u64)INT_MAX * DECA * MICRO, st->rsense));
++ u64 val64 = clamp(val, 0, ulimit);
+ /* need to pass it in millivolt */
+- u32 in = DIV_ROUND_CLOSEST_ULL((u64)val * st->rsense, DECA * MICRO);
++ u32 in = DIV_ROUND_CLOSEST_ULL(val64 * st->rsense, DECA * MICRO);
+
+ switch (attr) {
+ case hwmon_curr_max:
+--
+2.53.0
+
--- /dev/null
+From 32ff69a79971fb12637f5867ef4de8ebf635cda4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 17:30:42 -0700
+Subject: hwmon: (ltc4282) Fix parsing adi,current-limit-sense-microvolt
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit 335698fd7f60b6707b21fda725f97f35fa956b07 ]
+
+ltc4282_parse_dt() evaluates the wrong variable when parsing the current
+limit.
+
+When the adi,current-limit-sense-microvolt property is parsed into
+st->vsense_max, the subsequent switch statement evaluates the unrelated
+val variable instead of st->vsense_max:
+
+drivers/hwmon/ltc4282.c:ltc4282_parse_dt() {
+ ...
+ ret = device_property_read_u32(dev, "adi,current-limit-sense-microvolt",
+ &st->vsense_max);
+ if (!ret) {
+ int reg_val;
+
+ switch (val) {
+ case 12500:
+ reg_val = 0;
+ break;
+ ...
+}
+
+Because val holds a small integer representing vin_mode (from 0 to 3), it
+never matches any of the valid current limit cases.
+
+This causes it to always fall through to the default error case, return
+-EINVAL, and aborts probe initialization for any device tree using this
+property.
+
+Validate st->vsense_max instead to fix the problem.
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282")
+Cc: Nuno Sa <nuno.sa@analog.com>
+Reviewed-by: Nuno Sá <nuno.sa@analog.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ltc4282.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c
+index 0e7449db3158f..5f7ab813051c8 100644
+--- a/drivers/hwmon/ltc4282.c
++++ b/drivers/hwmon/ltc4282.c
+@@ -1425,7 +1425,7 @@ static int ltc4282_setup(struct ltc4282_state *st, struct device *dev)
+ if (!ret) {
+ int reg_val;
+
+- switch (val) {
++ switch (st->vsense_max) {
+ case 12500:
+ reg_val = 0;
+ break;
+--
+2.53.0
+
--- /dev/null
+From 6f15db240b39e6e8737de4011417ace1738f3885 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 15:48:42 +0800
+Subject: hwmon: (nzxt-smart2) Check return value of init_device() in probe
+
+From: Qingshuang Fu <fuqingshuang@kylinos.cn>
+
+[ Upstream commit d533882ce1060866a590257f2c77ee23eabef5b8 ]
+
+The init_device() call in nzxt_smart2_hid_probe() can fail because it
+sends HID output reports to the hardware to detect fans and set the
+update interval. If the hardware is not responding or the HID reports
+fail, init_device() returns a negative error code.
+
+However, the return value was ignored, causing the probe to continue
+and register an hwmon device even though the device was never properly
+initialized. This leads to an inconsistent state where the driver
+reports stale data or blocks on wait queues that will never be woken.
+
+The same function's return value is already checked in the
+reset_resume() handler, confirming the author's intent that errors
+should be propagated.
+
+Note that this fix was not possible before commit 59d104b54b0b
+("hwmon: (nzxt-smart2) Stop device IO before calling hid_hw_stop")
+because the out_hw_close error path was missing hid_device_io_stop(),
+which would have opened a use-after-free risk window.
+
+Fixes: 53e68c20aeb1 ("hwmon: add driver for NZXT RGB&Fan Controller/Smart Device v2.")
+Signed-off-by: Qingshuang Fu <fuqingshuang@kylinos.cn>
+Link: https://lore.kernel.org/r/20260804074842.505923-1-fffsqian@163.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/nzxt-smart2.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/nzxt-smart2.c b/drivers/hwmon/nzxt-smart2.c
+index 66c5886f411a6..8ff3ebc1bb4c1 100644
+--- a/drivers/hwmon/nzxt-smart2.c
++++ b/drivers/hwmon/nzxt-smart2.c
+@@ -760,7 +760,11 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev,
+
+ hid_device_io_start(hdev);
+
+- init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS);
++ ret = init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS);
++ if (ret) {
++ dev_err(&hdev->dev, "init_device failed: %d\n", ret);
++ goto out_hw_close;
++ }
+
+ drvdata->hwmon =
+ hwmon_device_register_with_info(&hdev->dev, "nzxtsmart2", drvdata,
+--
+2.53.0
+
--- /dev/null
+From 39949a72bea670fd17987e778cc779f802aad964 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 14:12:31 -0700
+Subject: hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit 0dabe8a56f772f0ece46d2597799f412c277d874 ]
+
+In lm25066_probe(), the PMBus coefficients for current and power are
+scaled based on the shunt resistor value. The calculation evaluates the
+multiplication using 32-bit arithmetic because info->m is an int and
+shunt is a u32:
+
+static int lm25066_probe(struct i2c_client *client) {
+ ...
+ info->m[PSC_CURRENT_IN] = info->m[PSC_CURRENT_IN] * shunt / 1000;
+ info->m[PSC_POWER] = info->m[PSC_POWER] * shunt / 1000;
+ ...
+}
+
+For large coefficients like 26882 (LM25056) or 15076 (LM5066i), a device
+tree shunt-resistor-micro-ohms value exceeding approximately 159,000
+(159 mOhm, which is physically valid for low-current applications) causes
+the intermediate product to exceed UINT_MAX (4,294,967,295). This results
+in a silent wraparound before the division by 1000.
+
+Furthermore, if the wrapped value has the most significant bit set,
+converting it back to the signed int info->m results in negative
+coefficients. This logic error leads to drastically corrupted current and
+power readings, which can cause erratic thermal or power management
+behavior in the system.
+
+Fix the problem by using 64-bit operations for the multiply/divide
+operations. This can still overflow, but only for unreasonably large
+shunt resistor values.
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Fixes: 94ee5fcc240fe ("hwmon: (pmbus/lm25066) Support configurable sense resistor values")
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/pmbus/lm25066.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c
+index c36c124d1a2d8..f0bf3b1533313 100644
+--- a/drivers/hwmon/pmbus/lm25066.c
++++ b/drivers/hwmon/pmbus/lm25066.c
+@@ -14,6 +14,7 @@
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
+ #include <linux/log2.h>
++#include <linux/math.h>
+ #include <linux/of.h>
+ #include "pmbus.h"
+
+@@ -540,8 +541,8 @@ static int lm25066_probe(struct i2c_client *client)
+ if (of_property_read_u32(client->dev.of_node, "shunt-resistor-micro-ohms", &shunt))
+ shunt = 1000;
+
+- info->m[PSC_CURRENT_IN] = info->m[PSC_CURRENT_IN] * shunt / 1000;
+- info->m[PSC_POWER] = info->m[PSC_POWER] * shunt / 1000;
++ info->m[PSC_CURRENT_IN] = DIV_ROUND_CLOSEST_ULL((u64)info->m[PSC_CURRENT_IN] * shunt, 1000);
++ info->m[PSC_POWER] = DIV_ROUND_CLOSEST_ULL((u64)info->m[PSC_POWER] * shunt, 1000);
+
+ #if IS_ENABLED(CONFIG_SENSORS_LM25066_REGULATOR)
+ /* LM25056 doesn't support OPERATION */
+--
+2.53.0
+
--- /dev/null
+From 25f23689466cbbb504002ef387913d04cfb9d09a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 21:35:05 +0300
+Subject: ipvs: avoid out-of-bounds write in ip_vs_nat_icmp
+
+From: Julian Anastasov <ja@ssi.bg>
+
+[ Upstream commit 646922a0379496154e8c8faca4f8e2fd9100cacc ]
+
+Sashiko warns that local attacker can modify the packet
+while it is processed by IPVS. Some places read the
+IP ihl field multiple times which can cause out-of-bounds
+access. One such place is ip_vs_nat_icmp where we
+can write after the validated area.
+
+Fix it by providing ciph argument just like it is done for
+IPv6 and use ciph->len as offset to the embedded transport
+header.
+
+Modify some IPv4 header checks by reading the ihl field
+only once.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Link: https://sashiko.dev/#/patchset/20260722101517.36313-1-ja%40ssi.bg
+Signed-off-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/ip_vs.h | 2 +-
+ net/netfilter/ipvs/ip_vs_core.c | 67 +++++++++++++++++----------------
+ net/netfilter/ipvs/ip_vs_xmit.c | 2 +-
+ 3 files changed, 36 insertions(+), 35 deletions(-)
+
+diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
+index 6935ec09af24d..80110ec025002 100644
+--- a/include/net/ip_vs.h
++++ b/include/net/ip_vs.h
+@@ -1707,7 +1707,7 @@ static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp)
+
+ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct ip_vs_conn *cp, int dir, unsigned int toff,
+- bool has_ports);
++ bool has_ports, struct ip_vs_iphdr *ciph);
+
+ #ifdef CONFIG_IP_VS_IPV6
+ void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
+diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
+index 6207a91e93f3b..586346110cd89 100644
+--- a/net/netfilter/ipvs/ip_vs_core.c
++++ b/net/netfilter/ipvs/ip_vs_core.c
+@@ -747,28 +747,27 @@ static int ip_vs_route_me_harder(struct netns_ipvs *ipvs, int af,
+ */
+ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct ip_vs_conn *cp, int inout, unsigned int toff,
+- bool has_ports)
++ bool has_ports, struct ip_vs_iphdr *ciph)
+ {
+ struct iphdr *iph = ip_hdr(skb);
+ struct icmphdr *icmph = (struct icmphdr *)(skb->data + toff);
+- struct iphdr *ciph = (struct iphdr *)(icmph + 1);
+- unsigned int coff __maybe_unused = toff + sizeof(struct icmphdr);
++ struct iphdr *cih = (struct iphdr *)(icmph + 1);
+
+ if (inout) {
+ iph->saddr = cp->vaddr.ip;
+ ip_send_check(iph);
+- ciph->daddr = cp->vaddr.ip;
+- ip_send_check(ciph);
++ cih->daddr = cp->vaddr.ip;
++ ip_send_check(cih);
+ } else {
+ iph->daddr = cp->daddr.ip;
+ ip_send_check(iph);
+- ciph->saddr = cp->daddr.ip;
+- ip_send_check(ciph);
++ cih->saddr = cp->daddr.ip;
++ ip_send_check(cih);
+ }
+
+ /* the TCP/UDP/SCTP port */
+ if (has_ports) {
+- __be16 *ports = (void *)ciph + ciph->ihl*4;
++ __be16 *ports = (void *)(skb->data + ciph->len);
+
+ if (inout)
+ ports[1] = cp->vport;
+@@ -782,10 +781,10 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ if (inout)
+- IP_VS_DBG_PKT(11, AF_INET, pp, skb, coff,
++ IP_VS_DBG_PKT(11, AF_INET, pp, skb, ciph->off,
+ "Forwarding altered outgoing ICMP");
+ else
+- IP_VS_DBG_PKT(11, AF_INET, pp, skb, coff,
++ IP_VS_DBG_PKT(11, AF_INET, pp, skb, ciph->off,
+ "Forwarding altered incoming ICMP");
+ }
+
+@@ -878,7 +877,7 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
+ ip_vs_nat_icmp_v6(skb, pp, cp, 1, toff, has_ports, ciph);
+ else
+ #endif
+- ip_vs_nat_icmp(skb, pp, cp, 1, toff, has_ports);
++ ip_vs_nat_icmp(skb, pp, cp, 1, toff, has_ports, ciph);
+
+ if (ip_vs_route_me_harder(cp->ipvs, af, skb, hooknum))
+ goto out;
+@@ -914,7 +913,7 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ struct ip_vs_iphdr ciph;
+ struct ip_vs_conn *cp;
+ struct ip_vs_protocol *pp;
+- unsigned int offset, ihl;
++ unsigned int offset;
+ union nf_inet_addr snet;
+
+ *related = 1;
+@@ -927,7 +926,6 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ return NF_ACCEPT;
+ }
+
+- ihl = ipvsh->len;
+ offset = ipvsh->len;
+ ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
+ if (ic == NULL)
+@@ -953,11 +951,15 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+
+ /* Now find the contained IP header */
+ offset += sizeof(_icmph);
++ if (!ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, true, &ciph))
++ return NF_ACCEPT; /* The packet looks wrong, ignore */
++
+ cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+- if (!(cih && cih->version == 4 && cih->ihl >= 5))
++ if (!(cih && cih->version == 4 &&
++ ciph.len - ciph.off >= sizeof(struct iphdr)))
+ return NF_ACCEPT; /* The packet looks wrong, ignore */
+
+- pp = ip_vs_proto_get(cih->protocol);
++ pp = ip_vs_proto_get(ciph.protocol);
+ if (!pp)
+ return NF_ACCEPT;
+
+@@ -968,8 +970,6 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ IP_VS_DBG_PKT(11, AF_INET, pp, skb, offset,
+ "Checking outgoing ICMP for");
+
+- ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, true, &ciph);
+-
+ /* The embedded headers contain source and dest in reverse order */
+ cp = INDIRECT_CALL_1(pp->conn_out_get, ip_vs_conn_out_get_proto,
+ ipvs, AF_INET, skb, &ciph);
+@@ -977,8 +977,8 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ return NF_ACCEPT;
+
+ snet.ip = ipvsh->saddr.ip;
+- return handle_response_icmp(AF_INET, skb, &snet, cp, pp, &ciph, ihl,
+- hooknum);
++ return handle_response_icmp(AF_INET, skb, &snet, cp, pp, &ciph,
++ ipvsh->len, hooknum);
+ }
+
+ #ifdef CONFIG_IP_VS_IPV6
+@@ -1625,10 +1625,12 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ /* Now find the contained IP header */
+ offset += sizeof(_icmph);
+ cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+- if (!(cih && cih->version == 4 && cih->ihl >= 5))
++ if (!cih)
+ return NF_ACCEPT; /* The packet looks wrong, ignore */
+- raddr = (union nf_inet_addr *)&cih->daddr;
+ hlen_ipip = cih->ihl * 4;
++ if (!(cih->version == 4 && hlen_ipip >= sizeof(struct iphdr)))
++ return NF_ACCEPT; /* The packet looks wrong, ignore */
++ raddr = (union nf_inet_addr *)&cih->daddr;
+
+ /* Special case for errors for IPIP/UDP/GRE tunnel packets */
+ tunnel = false;
+@@ -1645,9 +1647,6 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ if (!dest || dest->tun_type != IP_VS_CONN_F_TUNNEL_TYPE_IPIP)
+ return NF_ACCEPT;
+ offset += hlen_ipip;
+- cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+- if (!(cih && cih->version == 4 && cih->ihl >= 5))
+- return NF_ACCEPT; /* The packet looks wrong, ignore */
+ tunnel = true;
+ } else if ((cih->protocol == IPPROTO_UDP || /* Can be UDP encap */
+ cih->protocol == IPPROTO_GRE) && /* Can be GRE encap */
+@@ -1672,21 +1671,25 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ /* Skip IP and UDP/GRE tunnel headers */
+ offset = offset2 + ulen;
+ /* Now we should be at the original IP header */
+- cih = skb_header_pointer(skb, offset, sizeof(_ciph),
+- &_ciph);
+- if (cih && cih->version == 4 && cih->ihl >= 5 &&
+- iproto == IPPROTO_IPIP)
++ if (iproto == IPPROTO_IPIP)
+ tunnel = true;
+ else
+ return NF_ACCEPT;
+ }
+ }
+
+- pd = ip_vs_proto_data_get(ipvs, cih->protocol);
++ if (!ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, !tunnel, &ciph))
++ return NF_ACCEPT;
++ pd = ip_vs_proto_data_get(ipvs, ciph.protocol);
+ if (!pd)
+ return NF_ACCEPT;
+ pp = pd->pp;
+
++ cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
++ if (!(cih && cih->version == 4 &&
++ ciph.len - ciph.off >= sizeof(struct iphdr)))
++ return NF_ACCEPT; /* The packet looks wrong, ignore */
++
+ /* Is the embedded protocol header present? */
+ if (unlikely(cih->frag_off & htons(IP_OFFSET) && !pp->dont_defrag))
+ return NF_ACCEPT;
+@@ -1694,9 +1697,6 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ IP_VS_DBG_PKT(11, AF_INET, pp, skb, offset,
+ "Checking incoming ICMP for");
+
+- offset2 = offset;
+- ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, !tunnel, &ciph);
+-
+ /* The embedded headers contain source and dest in reverse order.
+ * For IPIP/UDP/GRE tunnel this is error for request, not for reply.
+ */
+@@ -1726,11 +1726,12 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ }
+
+ if (tunnel) {
+- unsigned int hlen_orig = cih->ihl * 4;
++ unsigned int hlen_orig = ciph.len - ciph.off;
+ __be32 info = ic->un.gateway;
+ __u8 type = ic->type;
+ __u8 code = ic->code;
+
++ offset2 = offset;
+ /* Update the MTU */
+ if (ic->type == ICMP_DEST_UNREACH &&
+ ic->code == ICMP_FRAG_NEEDED) {
+diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
+index b85420a3a14ce..240378e37741a 100644
+--- a/net/netfilter/ipvs/ip_vs_xmit.c
++++ b/net/netfilter/ipvs/ip_vs_xmit.c
+@@ -1577,7 +1577,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
+ if (skb_cow(skb, rt->dst.dev->hard_header_len))
+ goto tx_error;
+
+- ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports);
++ ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports, ciph);
+
+ /* Another hack: avoid icmp_send in ip_fragment */
+ skb->ignore_df = 1;
+--
+2.53.0
+
--- /dev/null
+From 4a66052a6c966c86cc63f9e7658c5646f79b9408 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 21:35:06 +0300
+Subject: ipvs: return the csum validation for forward hook
+
+From: Julian Anastasov <ja@ssi.bg>
+
+[ Upstream commit 99609cb0aa789c8d071050ce8579989551882cc6 ]
+
+Sashiko notes that playing games with the skb dst and rt
+flags instead of providing hooknum is not a good idea
+when validating the checksums.
+
+Also, skipping checksum validation for FORWARD packets
+risk silent data corruption, even if the only user is
+the FTP-CMD packets coming from the real server.
+
+Sashiko also noticed that by using common checksum
+helper in the previous commit we actually fixed old bug
+where the TCP/UDP checksum for IPv6 on CHECKSUM_COMPLETE
+was not validated correctly.
+
+Fixes: e876b75b9020 ("ipvs: fix the checksum validations")
+Link: https://sashiko.dev/#/patchset/20260722211420.153933-1-pablo%40netfilter.org
+Link: https://sashiko.dev/#/patchset/20260727185024.67534-1-ja%40ssi.bg
+Link: https://sashiko.dev/#/patchset/20260728202520.59179-1-ja%40ssi.bg
+Signed-off-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/ip_vs.h | 19 +++++--------------
+ net/netfilter/ipvs/ip_vs_proto_sctp.c | 2 +-
+ 2 files changed, 6 insertions(+), 15 deletions(-)
+
+diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
+index 80110ec025002..1121845bcc2a6 100644
+--- a/include/net/ip_vs.h
++++ b/include/net/ip_vs.h
+@@ -24,9 +24,7 @@
+ #include <linux/netfilter.h> /* for union nf_inet_addr */
+ #include <linux/ip.h>
+ #include <linux/ipv6.h> /* for struct ipv6hdr */
+-#include <net/route.h>
+ #include <net/ipv6.h>
+-#include <net/ip6_fib.h>
+ #if IS_ENABLED(CONFIG_NF_CONNTRACK)
+ #include <net/netfilter/nf_conntrack.h>
+ #endif
+@@ -1740,30 +1738,23 @@ static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum)
+ return csum_partial(diff, sizeof(diff), oldsum);
+ }
+
+-static inline bool ip_vs_checksum_needed(struct sk_buff *skb, int af)
++static inline bool ip_vs_checksum_needed(struct sk_buff *skb)
+ {
+ /* Checksum unnecessary or already validated? */
+ if (skb_csum_unnecessary(skb))
+ return false;
+- /* LOCAL_OUT ? */
+- if (!skb->dev || skb->dev->flags & IFF_LOOPBACK)
++ /* Locally generated ? */
++ if (!skb->dev)
+ return false;
+- /* !LOCAL_IN (FORWARD) ? */
+- if (af == AF_INET6) {
+- if (!(dst_rt6_info(skb_dst(skb))->rt6i_flags & RTF_LOCAL))
+- return false;
+- } else {
+- if (!(skb_rtable(skb)->rt_flags & RTCF_LOCAL))
+- return false;
+- }
+ return true;
+ }
+
+ static inline bool ip_vs_checksum_common_check(struct sk_buff *skb,
+ int offset, int proto, int af)
+ {
+- if (!ip_vs_checksum_needed(skb, af))
++ if (!ip_vs_checksum_needed(skb))
+ return true;
++ /* Validate csum even for FORWARD */
+ return !nf_checksum(skb, NF_INET_LOCAL_IN, offset, proto, af);
+ }
+
+diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
+index 3dbd3096e1637..c80567c73469b 100644
+--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
++++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
+@@ -193,7 +193,7 @@ sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct sctphdr *sh;
+ __le32 cmp, val;
+
+- if (!ip_vs_checksum_needed(skb, af))
++ if (!ip_vs_checksum_needed(skb))
+ return 1;
+ sh = (struct sctphdr *)(skb->data + sctphoff);
+ cmp = sh->checksum;
+--
+2.53.0
+
--- /dev/null
+From 44eb5f3ba89966232a30ecde4bad6e59d7093c1c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 13:15:08 +0000
+Subject: net/atm: fix slab-out-of-bounds read in vcc_setsockopt()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit d0c80dbb970439bd2eeb0e5effff8c16a5f4e1e3 ]
+
+vcc_setsockopt() contained an ineffective optlen check:
+ if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
+ return -EINVAL;
+
+If __SO_LEVEL_MATCH(optname, level) evaluated to false (e.g. if the caller
+passed a mismatched level), the length check optlen != __SO_SIZE(optname)
+was short-circuited and bypassed. Execution then fell through to switch(optname),
+calling copy_from_sockptr() assuming optval contained sufficient space.
+
+Furthermore, even if level matched, a cgroup BPF setsockopt filter could shrink
+optlen after entry. Because copy_from_sockptr() on kernel pointers uses memcpy(),
+this leads to a KASAN slab-out-of-bounds read when optlen is smaller than the
+expected structure size.
+
+Fix this by using copy_safe_from_sockptr(), which unconditionally validates
+that optlen is at least the expected size before copying. Also change the local
+'value' variable type from 'unsigned long' to 'int' so that SO_SETCLP matches
+its sizeof(int) ABI encoding on 64-bit systems.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: syzbot+53ecc09fb81df10ef4de@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=53ecc09fb81df10ef4de
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260805131508.3227331-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/atm/common.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/net/atm/common.c b/net/atm/common.c
+index 196c36269b34f..413863861bcaa 100644
+--- a/net/atm/common.c
++++ b/net/atm/common.c
+@@ -760,7 +760,7 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
+ sockptr_t optval, unsigned int optlen)
+ {
+ struct atm_vcc *vcc;
+- unsigned long value;
++ int value;
+ int error;
+
+ if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
+@@ -772,8 +772,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
+ {
+ struct atm_qos qos;
+
+- if (copy_from_sockptr(&qos, optval, sizeof(qos)))
+- return -EFAULT;
++ error = copy_safe_from_sockptr(&qos, sizeof(qos), optval,
++ optlen);
++ if (error)
++ return error;
+ error = check_qos(&qos);
+ if (error)
+ return error;
+@@ -786,8 +788,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
+ return 0;
+ }
+ case SO_SETCLP:
+- if (copy_from_sockptr(&value, optval, sizeof(value)))
+- return -EFAULT;
++ error = copy_safe_from_sockptr(&value, sizeof(value), optval,
++ optlen);
++ if (error)
++ return error;
+ if (value)
+ vcc->atm_options |= ATM_ATMOPT_CLP;
+ else
+--
+2.53.0
+
--- /dev/null
+From eef0796e2400996a278249697bd16f8f599919bb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 12:17:10 +0400
+Subject: net: hisilicon: hix5hd2_gmac: remove redundant NAPI delete
+
+From: Jiawen Liu <1298662399@qq.com>
+
+[ Upstream commit f307a7dc32097c11413178fca437a10d20890bc2 ]
+
+hix5hd2_dev_remove() calls netif_napi_del() before unregister_netdev().
+This is not needed because free_netdev() deletes all NAPI instances
+attached to the net_device.
+
+Remove the redundant call and let the networking core tear down the NAPI
+instance during unregister_netdev(). The probe error path still keeps its
+explicit netif_napi_del(), because the device has not been registered
+there.
+
+Fixes: 57c5bc9ad7d7 ("net: hisilicon: add hix5hd2 mac driver")
+Signed-off-by: Jiawen Liu <1298662399@qq.com>
+Link: https://patch.msgid.link/tencent_5FFD37A252B4FEA6A80AD25B17C8E904F005@qq.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hix5hd2_gmac.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+index 1a972b093a424..cc1d04d05e4b3 100644
+--- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
++++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+@@ -1282,7 +1282,6 @@ static void hix5hd2_dev_remove(struct platform_device *pdev)
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct hix5hd2_priv *priv = netdev_priv(ndev);
+
+- netif_napi_del(&priv->napi);
+ unregister_netdev(ndev);
+ mdiobus_unregister(priv->bus);
+ mdiobus_free(priv->bus);
+--
+2.53.0
+
--- /dev/null
+From be5615afc4cda920f79408139c9e104ad86183ed Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jul 2026 17:30:36 +0800
+Subject: net: hns3: fix speed configuration residue after driver reload
+
+From: Jijie Shao <shaojijie@huawei.com>
+
+[ Upstream commit 3860d8748af315bfee6fe669fddc1fc17d3214db ]
+
+After setting a 100G optical port to 40G via ethtool and reloading
+the driver, the port remains at 40G instead of reverting to the
+firmware default speed of 100G.
+
+The commit referenced in Fixes: added two overwrites in
+hclge_init_ae_dev() for non-copper media, so that optical ports
+connected to forced-mode remotes inherit the firmware-preset
+autoneg and speed instead of the hardcoded defaults:
+
+ req_autoneg = mac.autoneg
+ req_speed = mac.speed (when autoneg disabled)
+
+The autoneg overwrite keeps existing behavior:
+hclge_set_autoneg_speed_dup() already uses mac.autoneg (not
+req_autoneg) since it was introduced, so autoneg inheritance from
+firmware was already in place. This part is kept.
+
+The speed overwrite, however, introduces the residue: mac.speed
+reflects whatever was last programmed into the MAC, and after unload
+firmware does not restore the MAC speed to the flash default. So if
+the user changed speed via ethtool in a prior load, mac.speed still
+carries that value on reload and req_speed inherits it.
+
+Fix by dropping the req_speed overwrite only. req_speed keeps the
+firmware default value set in hclge_configure() (cfg.default_speed),
+so a reload reverts the speed to default, matching the expectation
+that a driver reload resets link configuration.
+
+Trade-off: on optical ports whose firmware default speed does not
+match a forced-mode remote, reload now drops the link and the user
+must re-apply ethtool configuration. This is acceptable: a driver
+reload is expected to reset link configuration, not to inherit
+runtime state from before unload. The autoneg inheritance is left
+in place as established behavior; changing it is out of scope for
+this patch and would itself be a user-perceivable behavior change.
+
+Fixes: d9d349c4e8a0 ("net: hns3: differentiate autoneg default values between copper and fiber")
+Signed-off-by: Jijie Shao <shaojijie@huawei.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260724093036.426631-1-shaojijie@huawei.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+index 79858b06c97b0..786aefc3d107e 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+@@ -11930,12 +11930,8 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
+ if (ret)
+ goto err_ptp_uninit;
+
+- if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_COPPER) {
++ if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_COPPER)
+ hdev->hw.mac.req_autoneg = hdev->hw.mac.autoneg;
+- if (hdev->hw.mac.autoneg == AUTONEG_DISABLE &&
+- hdev->hw.mac.speed != SPEED_UNKNOWN)
+- hdev->hw.mac.req_speed = hdev->hw.mac.speed;
+- }
+
+ ret = hclge_set_autoneg_speed_dup(hdev);
+ if (ret) {
+--
+2.53.0
+
--- /dev/null
+From 12ee39e1d8741dace9c1b2257a088e0d8630a378 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 11:04:02 +0300
+Subject: net/mlx5: fw_tracer, return NULL on create error
+
+From: Michael Guralnik <michaelgur@nvidia.com>
+
+[ Upstream commit af39eb111ce6b5eba9c08513b62c4868eb7e7fd5 ]
+
+Tracer creation can fail by returning either NULL or ERR_PTR.
+The return value is stored without a check on the device, and users
+treat ERR_PTR and NULL the same way.
+This also causes a crash in the core dump logic, which is missing the
+ERR_PTR check and ends up dereferencing it, as shown in the trace below.
+
+Switch tracer creation to return NULL on failure only, so callers only
+need a single NULL check.
+
+ Internal error: Oops: 0000000096000006 [#1] SMP
+ Modules linked in: mlx5_ib ib_uverbs ib_core ipv6 mlx5_core
+ CPU: 1 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted 6.19.7 #1 PREEMPT(none)
+ Workqueue: mlx5_health0001:01:00.0 mlx5_fw_reporter_err_work [mlx5_core]
+ pstate: a3400009 (NzCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
+ pc : mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core]
+ lr : mlx5_fw_tracer_trigger_core_dump_general+0x40/0xe0 [mlx5_core]
+ sp : ffff800081cf3c40
+ x29: ffff800081cf3c90 x28: 0000000000000000 x27: 0000000000000000
+ x26: ffff000080018828 x25: 0000000000000000 x24: ffff000080304a05
+ x23: ffff800081cf3d80 x22: ffff0000847e01a0 x21: 0000000000000000
+ x20: ffff0000847e01a0 x19: ffffffffffffffa1 x18: ffff80008310bbf0
+ x17: ffff800080119650 x16: ffff80008010df54 x15: ffff80008010d4ac
+ x14: ffff800079c202e4 x13: ffff80008002fe60 x12: ffff800080119650
+ x11: ffff80008010df54 x10: ffff80008010d4ac x9 : ffff800079c203d8
+ x8 : ffff800081cf3c88 x7 : 0000000000000000 x6 : 0000000000000000
+ x5 : 0000000000000000 x4 : 0000000000000008 x3 : 0000000000000030
+ x2 : 0000000000000008 x1 : 0000000000000000 x0 : 00000000c5c4000e
+ Call trace:
+ mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core] (P)
+ mlx5_fw_reporter_dump+0x30/0x2e0 [mlx5_core]
+ devlink_health_do_dump+0x9c/0x160
+ devlink_health_report+0x1c0/0x288
+ mlx5_fw_reporter_err_work+0xac/0xc0 [mlx5_core]
+ process_one_work+0x15c/0x3d8
+ worker_thread+0x18c/0x320
+ kthread+0x148/0x228
+ ret_from_fork+0x10/0x20
+ Code: b9400000 5ac00800 7a401800 540003ca (3940a260)
+ ---[ end trace 0000000000000000 ]---
+ Kernel panic - not syncing: Oops: Fatal exception
+ SMP: stopping secondary CPUs
+ Kernel Offset: disabled
+ CPU features: 0x000000,00078031,75fce5a1,35fffe67
+ Memory Limit: none
+ ---[ end Kernel panic - not syncing: Oops: Fatal exception ]---
+
+Fixes: fd1483fe1f9f ("net/mlx5: Add support for FW reporter dump")
+Signed-off-by: Michael Guralnik <michaelgur@nvidia.com>
+Reviewed-by: Shay Drori <shayd@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260729080402.2427184-1-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ethernet/mellanox/mlx5/core/diag/fw_tracer.c | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+index 0b82a6a133d6c..74f68b70ad1c1 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+@@ -1025,13 +1025,11 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
+
+ tracer = kvzalloc(sizeof(*tracer), GFP_KERNEL);
+ if (!tracer)
+- return ERR_PTR(-ENOMEM);
++ return NULL;
+
+ tracer->work_queue = create_singlethread_workqueue("mlx5_fw_tracer");
+- if (!tracer->work_queue) {
+- err = -ENOMEM;
++ if (!tracer->work_queue)
+ goto free_tracer;
+- }
+
+ tracer->dev = dev;
+
+@@ -1073,7 +1071,7 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
+ destroy_workqueue(tracer->work_queue);
+ free_tracer:
+ kvfree(tracer);
+- return ERR_PTR(err);
++ return NULL;
+ }
+
+ static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data);
+@@ -1084,7 +1082,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
+ struct mlx5_core_dev *dev;
+ int err;
+
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return 0;
+
+ if (!tracer->str_db.loaded)
+@@ -1134,7 +1132,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
+ /* Stop tracer + Cleanup HW resources */
+ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
+ {
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return;
+
+ mutex_lock(&tracer->state_lock);
+@@ -1163,7 +1161,7 @@ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
+ /* Free software resources (Buffers, etc ..) */
+ void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer)
+ {
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return;
+
+ mlx5_core_dbg(tracer->dev, "FWTracer: Destroy\n");
+@@ -1215,7 +1213,7 @@ int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer)
+ struct mlx5_core_dev *dev;
+ int err;
+
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return 0;
+
+ dev = tracer->dev;
+--
+2.53.0
+
--- /dev/null
+From d40cda53d7f3115b37b88f7d65037f3964c806ce Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 07:43:38 +0300
+Subject: net/mlx5e: TC, Check if flow is PEER before acquiring devcom lock
+
+From: Shay Drory <shayd@nvidia.com>
+
+[ Upstream commit 6ddfba2ea98db21b001e0e5c472499156224650c ]
+
+In case __mlx5e_add_fdb_flow() fails in lower levels, the flow is
+deleted via mlx5e_tc_del_flow(), and mlx5e_tc_del_flow() is acquiring
+ESW devcom lock without condition. In addition, in case of peer_flow,
+__mlx5e_add_fdb_flow() is called while holding ESW devcom comp lock.
+This results in an AA deadlock.
+
+To fix this, introduce a new PEER flag that is set on flows created as
+peer flows (the duplicate flows on peer devices), and check it in
+mlx5e_tc_del_flow() before acquiring ESW devcom lock.
+
+Lockdep splat:
+============================================
+WARNING: possible recursive locking detected
+============================================
+ Possible unsafe locking scenario:
+ CPU0
+ ----
+ lock(&comp->lock_key#2);
+ lock(&comp->lock_key#2);
+ *** DEADLOCK ***
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0x69/0xa0
+ print_deadlock_bug.cold+0xbd/0xca
+ __lock_acquire+0x1671/0x2ec0
+ lock_acquire+0x10e/0x2e0
+ down_read+0x95/0x430
+ mlx5_devcom_for_each_peer_begin+0x4e/0xe0 [mlx5_core]
+ mlx5e_tc_del_flow+0x11d/0xa70 [mlx5_core]
+ mlx5e_flow_put+0x99/0x100 [mlx5_core]
+ __mlx5e_add_fdb_flow+0x409/0xf00 [mlx5_core]
+ mlx5e_configure_flower+0x2a86/0x4100 [mlx5_core]
+ mlx5e_rep_setup_tc_cls_flower+0x12f/0x1b0 [mlx5_core]
+ mlx5e_rep_setup_tc_cb+0x153/0x750 [mlx5_core]
+ tc_setup_cb_add+0x1dc/0x470
+ fl_change+0x2f4d/0x626d [cls_flower]
+ tc_new_tfilter+0x79b/0x2310
+ rtnetlink_rcv_msg+0x778/0xad0
+ do_syscall_64+0x70/0x960
+ entry_SYSCALL_64_after_hwframe+0x4b/0x53
+ </TASK>
+
+Fixes: 04de7dda7394 ("net/mlx5e: Infrastructure for duplicated offloading of TC flows")
+Signed-off-by: Shay Drory <shayd@nvidia.com>
+Reviewed-by: Cosmin Ratiu <cratiu@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260728044338.2271143-1-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h | 1 +
+ drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 4 +++-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
+index efb34de4cb7ad..692ac2f21d94e 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
+@@ -30,6 +30,7 @@ enum {
+ MLX5E_TC_FLOW_FLAG_FAILED = MLX5E_TC_FLOW_BASE + 9,
+ MLX5E_TC_FLOW_FLAG_SAMPLE = MLX5E_TC_FLOW_BASE + 10,
+ MLX5E_TC_FLOW_FLAG_USE_ACT_STATS = MLX5E_TC_FLOW_BASE + 11,
++ MLX5E_TC_FLOW_FLAG_PEER = MLX5E_TC_FLOW_BASE + 12,
+ };
+
+ struct mlx5e_tc_flow_parse_attr {
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+index 8878990254f46..a5ae179310672 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+@@ -2161,7 +2161,8 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
+ if (mlx5e_is_eswitch_flow(flow)) {
+ struct mlx5_devcom_comp_dev *devcom = flow->priv->mdev->priv.eswitch->devcom;
+
+- if (!mlx5_devcom_for_each_peer_begin(devcom)) {
++ if (flow_flag_test(flow, PEER) ||
++ !mlx5_devcom_for_each_peer_begin(devcom)) {
+ mlx5e_tc_del_fdb_flow(priv, flow);
+ return;
+ }
+@@ -4605,6 +4606,7 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f,
+ else
+ in_mdev = priv->mdev;
+
++ flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_PEER);
+ parse_attr = flow->attr->parse_attr;
+ peer_flow = __mlx5e_add_fdb_flow(peer_priv, f, flow_flags,
+ parse_attr->filter_dev,
+--
+2.53.0
+
--- /dev/null
+From bbba96b65172c59c4b73969d8187ee32555a118e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 12:36:18 +0800
+Subject: net/ncsi: fix heap OOB read in NCSI_CMD_SEND_CMD payload length
+
+From: Henry Martin <bsdhenrymartin@gmail.com>
+
+[ Upstream commit afa58b7384913c8773d837acdb07b035690ec5d2 ]
+
+ncsi_send_cmd_nl() takes the number of bytes to copy from the
+attacker-controlled ncsi_pkt_hdr.length field of the in-band packet
+header, while the source buffer is the NCSI_ATTR_DATA netlink
+attribute whose readable size is nla_len() - sizeof(ncsi_pkt_hdr).
+The two length sources are never cross-checked: only
+nla_len() >= sizeof(struct ncsi_pkt_hdr) is enforced.
+
+With hdr->length set larger than the attribute payload (up to 65535
+against at most 2032 readable bytes), ncsi_cmd_handler_oem() copies
+past the end of the netlink attribute buffer with unsafe_memcpy(),
+leaking up to ~64KB of kernel heap memory into the transmitted NCSI
+command packet. The destination skb is sized by the declared payload,
+so the write side does not overflow - this is a pure OOB read /
+information leak, reachable with CAP_NET_ADMIN on systems with a
+registered NCSI device (e.g. OpenBMC on Aspeed BMC SoCs, where
+NET_NCSI=y is standard).
+
+Reject commands whose declared payload extends past the end of the
+data attribute.
+
+The issue was found by the autokbug dynamic kernel fuzzer at Tencent
+Yunding Lab.
+
+Fixes: 9771b8ccdfa6 ("net/ncsi: Extend NC-SI Netlink interface to allow user space to send NC-SI command")
+Reported-by: Henry Martin <bsdhenrymartin@gmail.com>
+Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>
+Link: https://patch.msgid.link/20260803043618.3210301-1-bsdhenrymartin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ncsi/ncsi-netlink.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/net/ncsi/ncsi-netlink.c b/net/ncsi/ncsi-netlink.c
+index 2f872d064396d..8cc538358f6a3 100644
+--- a/net/ncsi/ncsi-netlink.c
++++ b/net/ncsi/ncsi-netlink.c
+@@ -461,6 +461,10 @@ static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info)
+ nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN;
+ nca.info = info;
+ nca.payload = ntohs(hdr->length);
++ if (nca.payload > len - sizeof(*hdr)) {
++ ret = -EINVAL;
++ goto out_netlink;
++ }
+ nca.data = data + sizeof(*hdr);
+
+ ret = ncsi_xmit_cmd(&nca);
+--
+2.53.0
+
--- /dev/null
+From f8b4f08db0c680fbc67b7b4209c6f507f8da3da5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 18:20:06 -0400
+Subject: net/openvswitch: check Ethernet header length in key_extract()
+
+From: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+
+[ Upstream commit cf6f8b29befb92173659bcef6a441d274947bfae ]
+
+When a packet arrives on an ARPHRD_NONE device (e.g. TUN),
+ovs_flow_key_extract() trusts the user-provided skb->protocol field: if
+it is ETH_P_TEB, the packet is classified as MAC_PROTO_ETHERNET and
+key_extract() is called without ensuring the skb has ETH_HLEN (14) bytes
+of linear data. key_extract() unconditionally pulls 2 * ETH_ALEN bytes
+for MAC addresses and parse_ethertype() pulls 2 more, either of which
+triggers a kernel BUG in __skb_pull() when the linear area is too small.
+
+ kernel BUG at include/linux/skbuff.h:2848!
+ RIP: 0010:key_extract+0xa7e/0xd90 net/openvswitch/flow.c:933
+ ovs_flow_key_extract+0x419/0xa70
+ ovs_vport_receive+0x222/0x390
+ netdev_frame_hook+0x3e0/0x630
+ tun_get_user+0x2d0c/0x38e0
+
+Fixed by calling check_header() in key_extract() before accessing the
+Ethernet header.
+
+Fixes: 217ac77a3c25 ("openvswitch: allow L3 netdev ports")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Reviewed-by: Eelco Chaudron <echaudro@redhat.com>
+Signed-off-by: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
+Link: https://patch.msgid.link/20260730222006.118652-1-blbllhy@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/flow.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
+index b80bd3a907739..52e261ce91e8e 100644
+--- a/net/openvswitch/flow.c
++++ b/net/openvswitch/flow.c
+@@ -893,8 +893,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ * Ethernet header
+ * @key: output flow key
+ *
+- * The caller must ensure that skb->len >= ETH_HLEN.
+- *
+ * Initializes @skb header fields as follows:
+ *
+ * - skb->mac_header: the L2 header.
+@@ -914,8 +912,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ */
+ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+ {
+- struct ethhdr *eth;
+-
+ /* Flags are always used as part of stats */
+ key->tp.flags = 0;
+
+@@ -930,6 +926,13 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+ skb_reset_network_header(skb);
+ key->eth.type = skb->protocol;
+ } else {
++ struct ethhdr *eth;
++ int err;
++
++ err = check_header(skb, ETH_HLEN);
++ if (unlikely(err))
++ return err;
++
+ eth = eth_hdr(skb);
+ ether_addr_copy(key->eth.src, eth->h_source);
+ ether_addr_copy(key->eth.dst, eth->h_dest);
+--
+2.53.0
+
--- /dev/null
+From a9f480441ad7481fbf3775bb5d66002f7b5fcdce Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 22:19:06 +0800
+Subject: net: prestera: validate firmware header length
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 8ae344eb540af3f457179b52bc6061416752485c ]
+
+prestera_fw_hdr_parse() reads the firmware header before checking
+that the firmware image contains that header.
+
+Reject images shorter than struct prestera_fw_header before decoding the
+magic and version fields.
+
+Fixes: 4c2703dfd7fabb ("net: marvell: prestera: Add PCI interface support")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Acked-by: Elad Nachman <enachman@marvell.com>
+Link: https://patch.msgid.link/20260731141500.1-prestera-v2-pengpeng@iscas.ac.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/marvell/prestera/prestera_pci.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/marvell/prestera/prestera_pci.c b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+index 35857dc19542f..5db2c9e5e077d 100644
+--- a/drivers/net/ethernet/marvell/prestera/prestera_pci.c
++++ b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+@@ -684,6 +684,9 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw)
+ struct prestera_fw_header *hdr;
+ u32 magic;
+
++ if (fw->bin->size < sizeof(*hdr))
++ return -EINVAL;
++
+ hdr = (struct prestera_fw_header *)fw->bin->data;
+
+ magic = be32_to_cpu(hdr->magic_number);
+--
+2.53.0
+
--- /dev/null
+From 36425ae87025956c1a7d109e6208592bf701706a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 15:20:48 +0000
+Subject: net: remove WARN_ON_ONCE() from sk_mc_loop()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit b8a39a09ae4eaae04309e1e38ed6a1101d967496 ]
+
+sk_mc_loop() can be called for sockets that are neither AF_INET
+nor AF_INET6 (e.g. AF_PACKET sockets when sending packets via raw/packet
+socket over virtual devices such as VRF or ipvlan).
+
+In such cases, sk_family is not AF_INET/AF_INET6 and sk_mc_loop() falls
+through the switch statement and triggers WARN_ON_ONCE(1).
+
+Non-INET sockets do not support IP_MULTICAST_LOOP or IPV6_MULTICAST_LOOP
+options, so loopback should default to true without generating a warning.
+
+Fixes: f60e5990d9c1 ("ipv6: protect skb->sk accesses from recursive dereference inside the stack")
+Reported-by: syzbot+22c3218a6fa219e47321@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/6a72024c.13623e66.bdc14.0019.GAE@google.com/T/#u
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260804152048.2134341-1-edumazet@google.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/sock.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/net/core/sock.c b/net/core/sock.c
+index 4a09e780406fe..e8b03cf3a428c 100644
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -773,7 +773,6 @@ bool sk_mc_loop(const struct sock *sk)
+ return inet6_test_bit(MC6_LOOP, sk);
+ #endif
+ }
+- WARN_ON_ONCE(1);
+ return true;
+ }
+ EXPORT_SYMBOL(sk_mc_loop);
+--
+2.53.0
+
--- /dev/null
+From 64e91994f52a60753479ee4dea674bc7b5755d51 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 1 Aug 2026 08:56:32 -0400
+Subject: net/sched: cls_api: Always acquire rtnl_lock when destroying locked
+ classifiers
+
+From: Jamal Hadi Salim <jhs@mojatatu.com>
+
+[ Upstream commit a347304b2ca1a5377d5bd2d8a72e4b4f12afe648 ]
+
+Another challenge with unlocked filters.
+There is a short window in tc_new_tfilter where a tcf_proto can be found
+and briefly referenced by a totally unrelated, unlocked classifier's request
+and cause a race.
+
+Feng created a poc which created this race with two threads, one creating a
+u32 filter and other a flower filter in the same chain/prio:
+
+1. Both threads enter tc_new_tfilter, both find the chain empty, both
+ drop filter_chain_lock
+2. u32 finishes tcf_proto_create("u32") first, calls
+ tcf_chain_tp_insert_unique() -> inserts u32_tp into the chain
+3. flower finishes tcf_proto_create("flower") later, calls
+ tcf_chain_tp_insert_unique() -> tcf_chain_tp_find() now sees u32_tp
+ already there, takes a reference on it, destroys flower's own tp_new
+ and returns u32_tp to the caller.
+
+Flower then hits the kind mismatch check (because it requested for kind
+"flower" but tp->ops->kind is "u32") and goes through the errout path
+which calls tcf_proto_put() on u32_tp. If the u32 thread has already
+gone through its own errout (its change() call failed on the PoC's empty
+options) and dropped its create and insert refs, flower's put is the
+last one and drops u32_tp's refcnt to zero.
+
+At this point tp->ops->destroy() runs in a context that never took
+rtnl_lock. When that happens, it might cause a UAF like the following
+(illustrated by the PoC):
+
+[ +0.000710] BUG: KASAN: slab-use-after-free in u32_init (net/sched/cls_u32.c:393)
+[ +0.000281] Read of size 8 at addr ffff888120022f00 by task poc_feng_xue/524
+
+ Call Trace:
+ u32_init (net/sched/cls_u32.c:393)
+ tc_new_tfilter (net/sched/cls_api.c:2378)
+
+ Allocated by task 526:
+ u32_init (net/sched/cls_u32.c:378)
+ tc_new_tfilter (net/sched/cls_api.c:2378)
+
+ Freed by task 522:
+ kfree
+ u32_destroy (net/sched/cls_u32.c:662)
+ tcf_proto_destroy (net/sched/cls_api.c:446)
+ tcf_proto_put (net/sched/cls_api.c:459)
+ tc_new_tfilter (net/sched/cls_api.c:2459)
+
+Fix this by having tcf_proto_destroy() take rtnl_lock around
+tp->ops->destroy() for locked classifiers whenever rtnl is not held.
+
+To explain why I used a temp variable "not_lockless" I'd like to point to a
+semi-related note on rtnl_held vs TCF_PROTO_OPS_DOIT_UNLOCKED (adding here
+for future cleanup if deemed necessary):
+The rtnl_held parameter and the TCF_PROTO_OPS_DOIT_UNLOCKED flag are
+redundant sources of truth for whether rtnl_lock is held. Among the nine
+classifier destroy(..rtnl_held..) callbacks, only flower consults the
+rtnl_held parameter which it propagates to tc_setup_cb_destroy()
+and tc_setup_cb_call(). The other eight (u32, flow, bpf, cgroup, route, basic,
+fw, mall) ignore it entirely;-> those that call tc_setup_cb_destroy()
+(u32, bpf, mall) hardcode true always instead of forwarding the parameter.
+
+A future cleanup should remove the rtnl_held parameter from the destroy callback
+signature entirely and have callers rely solely on their knowledge whether
+they are running in an unlocked context.
+
+Fixes: 12db03b65c2b ("net: sched: extend proto ops to support unlocked classifiers")
+Reported-by: Feng Xue <feng.xue@outlook.com>
+Tested-by: Victor Nogueira <victor@mojatatu.com>
+Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260801125632.360365-1-jhs@mojatatu.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_api.c | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index c5aeff709ca66..51a09d5553102 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -443,7 +443,22 @@ static void tcf_chain_put(struct tcf_chain *chain);
+ static void tcf_proto_destroy(struct tcf_proto *tp, bool rtnl_held,
+ bool sig_destroy, struct netlink_ext_ack *extack)
+ {
+- tp->ops->destroy(tp, rtnl_held, extack);
++ /* A locked classifier's destroy callback (e.g. u32_destroy) uses
++ * rtnl_dereference() and mutates shared structures (e.g. the
++ * tc_u_common hash list) that are only safe under rtnl_lock. When an
++ * unlocked classifier's request (e.g. flower on ingress) loses the
++ * tcf_chain_tp_insert_unique() race and ends up dropping the last
++ * reference on a locked classifier's proto, destroy() would run
++ * without rtnl held. Take it here in that case.
++ */
++ bool not_lockless = !rtnl_held &&
++ !(tp->ops->flags & TCF_PROTO_OPS_DOIT_UNLOCKED);
++
++ if (not_lockless)
++ rtnl_lock();
++ tp->ops->destroy(tp, rtnl_held || not_lockless, extack);
++ if (not_lockless)
++ rtnl_unlock();
+ tcf_proto_count_usesw(tp, false);
+ if (sig_destroy)
+ tcf_proto_signal_destroyed(tp->chain, tp);
+--
+2.53.0
+
--- /dev/null
+From 838c70142b181c6adb74f7939a48fa49b5b8d156 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 05:44:11 -0400
+Subject: net/sched: cls_route: fix fastmap use-after-free on filter
+
+From: Jamal Hadi Salim <jhs@mojatatu.com>
+
+[ Upstream commit 47d7f7051253bdc02b1d245d87e38f16d31a74df ]
+
+The route4 classifier maintains a 16-slot fastmap cache that stores raw
+struct route4_filter pointers indexed by (id, iif). The reader
+(route4_classify) populates this cache via route4_set_fastmap() for every
+classified packet that hits a filter. The writer (route4_delete,
+route4_change) clears the cache via route4_reset_fastmap() before
+RCU-deferred kfree of the filter.
+
+This creates a UAF race:
+ 1. Reader walks the RCU-protected bucket chain, finds filter f
+ 2. Writer unlinks f, calls route4_reset_fastmap(), then tcf_queue_work()
+ 3. Reader calls route4_set_fastmap() and writes f into the cache
+ *after* the writer's reset, caching a pointer about to be freed
+ 4. After the RCU grace period, kfree(f) executes
+ 5. Next classified packet on the same (id, iif) tuple hits the stale
+ fastmap entry and reads f->res from freed memory
+
+Reproduced with an mdelay(100) accelerator in route4_set_fastmap() and a
+concurrent add/delete stress test (provided by both zdi and Santosh).
+Both triggered KASAN slab-use-after-free reports in the route4 fastmap
+paths.
+
+Fix:
+Introduce a per-filter boolean dying flag to suppress stale fastmap
+republishing by in-flight readers.
+
+Fixes: 1109c00547fc ("net: sched: RCU cls_route")
+Reported-by: zdi-disclosures@trendmicro.com
+Reported-by: Santosh Kalluri <santosh.kalluri129@gmail.com>
+Suggested-by: Paolo Abeni <pabeni@redhat.com>
+Tested-by: Victor Nogueira <victor@mojatatu.com>
+Tested-by: Santosh Kalluri <santosh.kalluri129@gmail.com>
+Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260729094411.46257-1-jhs@mojatatu.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_route.c | 35 ++++++++++++++++++++++++++---------
+ 1 file changed, 26 insertions(+), 9 deletions(-)
+
+diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
+index b9c58c040c305..38469cdcb22d6 100644
+--- a/net/sched/cls_route.c
++++ b/net/sched/cls_route.c
+@@ -52,6 +52,7 @@ struct route4_filter {
+ struct tcf_result res;
+ struct tcf_exts exts;
+ u32 handle;
++ bool dying;
+ struct route4_bucket *bkt;
+ struct tcf_proto *tp;
+ struct rcu_work rwork;
+@@ -66,9 +67,11 @@ static inline int route4_fastmap_hash(u32 id, int iif)
+
+ static DEFINE_SPINLOCK(fastmap_lock);
+ static void
+-route4_reset_fastmap(struct route4_head *head)
++route4_reset_fastmap(struct route4_head *head, struct route4_filter *f)
+ {
+ spin_lock_bh(&fastmap_lock);
++ if (f)
++ f->dying = true;
+ memset(head->fastmap, 0, sizeof(head->fastmap));
+ spin_unlock_bh(&fastmap_lock);
+ }
+@@ -81,9 +84,11 @@ route4_set_fastmap(struct route4_head *head, u32 id, int iif,
+
+ /* fastmap updates must look atomic to aling id, iff, filter */
+ spin_lock_bh(&fastmap_lock);
+- head->fastmap[h].id = id;
+- head->fastmap[h].iif = iif;
+- head->fastmap[h].filter = f;
++ if (f == ROUTE4_FAILURE || !f->dying) {
++ head->fastmap[h].id = id;
++ head->fastmap[h].iif = iif;
++ head->fastmap[h].filter = f;
++ }
+ spin_unlock_bh(&fastmap_lock);
+ }
+
+@@ -297,6 +302,13 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
+ next = rtnl_dereference(f->next);
+ RCU_INIT_POINTER(b->ht[h2], next);
+ tcf_unbind_filter(tp, &f->res);
++ /* Mark the filter dying under fastmap_lock so
++ * any in-flight reader that still holds it
++ * will skip the republish in route4_set_fastmap().
++ */
++ spin_lock_bh(&fastmap_lock);
++ f->dying = true;
++ spin_unlock_bh(&fastmap_lock);
+ if (tcf_exts_get_net(&f->exts))
+ route4_queue_work(f);
+ else
+@@ -307,6 +319,11 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
+ kfree_rcu(b, rcu);
+ }
+ }
++
++ /* All filters are unlinked and marked dying, so no in-flight
++ * reader can republish a stale entry after this reset.
++ */
++ route4_reset_fastmap(head, NULL);
+ kfree_rcu(head, rcu);
+ }
+
+@@ -334,11 +351,11 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,
+ /* unlink it */
+ RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
+
+- /* Remove any fastmap lookups that might ref filter
+- * notice we unlink'd the filter so we can't get it
+- * back in the fastmap.
++ /* Clear any fastmap entries that may ref this filter and
++ * mark it dying so in-flight readers can't republish it
++ * after the reset.
+ */
+- route4_reset_fastmap(head);
++ route4_reset_fastmap(head, f);
+
+ /* Delete it */
+ tcf_unbind_filter(tp, &f->res);
+@@ -558,7 +575,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
+ }
+ }
+
+- route4_reset_fastmap(head);
++ route4_reset_fastmap(head, fold);
+ *arg = f;
+ if (fold) {
+ tcf_unbind_filter(tp, &fold->res);
+--
+2.53.0
+
--- /dev/null
+From 8355e9ad33518ce0b79c83b05c20e23d357587ea Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 21:14:16 +0200
+Subject: net/sched: sch_cake: drop WARN_ON(1) for malformed packets in ACK
+ filter
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Toke Høiland-Jørgensen <toke@toke.dk>
+
+[ Upstream commit 2a33516f9ef59ad11844d4fc152f889449b5daf3 ]
+
+The sch_cake ACK filter parses packets to find the TCP header and filter
+duplicated ACKs if the flow is backlogged. The parsing code contains a
+WARN_ON(1) which can be triggered by a malformed IP header in certain
+cases. Depending on the system configuration, this leads either to
+either spamming dmesg with warnings, or a panic if panic_on_warn is set.
+
+The code already correctly skips the offending packet in the branch that
+triggers the warning, so the WARN_ON itself doesn't really serve any
+purpose. So just drop it altogether to avoid the inconvenient side
+effects.
+
+Fixes: 8b7138814f29 ("sch_cake: Add optional ACK filter")
+Reported-by: Zhiling Zou <zhilinz@nebusec.ai>
+Reported-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
+Link: https://patch.msgid.link/20260729191417.45665-1-toke@toke.dk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_cake.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c
+index 2f33739036bb1..43908ec231696 100644
+--- a/net/sched/sch_cake.c
++++ b/net/sched/sch_cake.c
+@@ -1265,7 +1265,6 @@ static struct sk_buff *cake_ack_filter(struct cake_sched_data *q,
+
+ seglen = ntohs(ipv6h_check->payload_len);
+ } else {
+- WARN_ON(1); /* shouldn't happen */
+ continue;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 0427380ab1515e4e31419c3cf965c2b5a51bb4f1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:01:53 +0200
+Subject: net/smc: fix qentry overwrite for CONFIRM_LINK and ADD_LINK_CONT in
+ smc_llc_event_handler()
+
+From: Mahanta Jambigi <mjambigi@linux.ibm.com>
+
+[ Upstream commit 976245094925bab9bc39366b2e9ab44ffcde61d0 ]
+
+The SMC_LLC_CONFIRM_LINK / SMC_LLC_ADD_LINK_CONT branch in
+smc_llc_event_handler() stores an incoming qentry into the local LLC flow
+without first checking whether a qentry is already pending. If a malicious or
+buggy peer sends a second CONFIRM_LINK or ADD_LINK_CONT request while a flow is
+active and flow->qentry is already set, smc_llc_flow_qentry_set() overwrites the
+pointer without freeing the previous allocation, leaking one kmalloc-96 object
+per spurious message.
+
+The sibling SMC_LLC_DELETE_LINK branch already has the correct !flow->qentry
+guard. Apply the same guard to the CONFIRM_LINK/ADD_LINK_CONT branch so that a
+duplicate message when qentry is already occupied falls through to break and is
+freed by the kfree(qentry) at the out: label, rather than silently leaking the
+existing allocation.
+
+The response direction (smc_llc_rx_response()) is unaffected: it already guards
+with flow->qentry at the equivalent site and drops duplicate responses
+correctly.
+
+Fixes: 0fb0b02bd6fd ("net/smc: adapt SMC client code to use the LLC flow")
+Signed-off-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
+Reviewed-by: Hidayath Khan <hidayath@linux.ibm.com>
+Reviewed-by: Sidraya Jayagond <sidraya@linux.ibm.com>
+Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
+Link: https://patch.msgid.link/20260729130153.970800-1-mjambigi@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/smc_llc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c
+index 018ce8133b026..149d63cff667e 100644
+--- a/net/smc/smc_llc.c
++++ b/net/smc/smc_llc.c
+@@ -1918,7 +1918,8 @@ static void smc_llc_event_handler(struct smc_llc_qentry *qentry)
+ return;
+ case SMC_LLC_CONFIRM_LINK:
+ case SMC_LLC_ADD_LINK_CONT:
+- if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) {
++ if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE &&
++ !lgr->llc_flow_lcl.qentry) {
+ /* a flow is waiting for this message */
+ smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry);
+ wake_up(&lgr->llc_msg_waiter);
+--
+2.53.0
+
--- /dev/null
+From 2d9d7284200dfa2b9a76e8a092c9b575255ccffb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 09:07:01 +0200
+Subject: net/smc: fix TOCTOU race between smc_listen_out() and listener close
+
+From: Sidraya Jayagond <sidraya@linux.ibm.com>
+
+[ Upstream commit 185a4caeecabc150106deda1da170b09f2ad803f ]
+
+smc_listen_out() reads lsmc->sk.sk_state without the listener lock,
+then acquires lock_sock_nested() only after the check passes. This
+opens a window where smc_close_active() can transition the listener
+to SMC_CLOSED, call smc_close_cleanup_listen() to drain the accept
+queue, and release the lock, all between the lockless read and the
+delayed lock acquisition:
+
+ smc_listen_work (smc_hs_wq) smc_close_active()
+ ------------------------------- -------------------------
+ release_sock(child)
+ if (sk_state == SMC_LISTEN) TRUE
+ lock_sock(listener)
+ sk_state = SMC_CLOSED
+ smc_close_cleanup_listen()
+ release_sock(listener)
+ flush_work(tcp_listen_work)
+ lock_sock_nested(listener)
+ smc_accept_enqueue(listener, child) /* child enqueued on dead listener */
+
+smc_close_active() flushes only tcp_listen_work. Work items already
+dispatched onto smc_hs_wq for the CLC handshake continue running
+unguarded. smc_accept_enqueue() takes a sock_hold() on the child that
+is never released, so the child smc_sock, its clcsock, and the
+reference all leak. A remote peer that opens TCP connections while the
+server calls close() can exhaust kernel memory.
+
+Move lock_sock_nested() to before the sk_state check so that the test
+and the enqueue are atomic under the listener lock.
+
+Fixes: fd57770dd198 ("net/smc: wait for pending work before clcsock release_sock")
+Reviewed-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
+Signed-off-by: Sidraya Jayagond <sidraya@linux.ibm.com>
+Reviewed-by: Breno Leitao <leitao@debian.org>
+Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
+Link: https://patch.msgid.link/20260803070701.126339-1-sidraya@linux.ibm.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/af_smc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
+index 8d740f588a771..8e95839161aa1 100644
+--- a/net/smc/af_smc.c
++++ b/net/smc/af_smc.c
+@@ -1933,11 +1933,12 @@ static void smc_listen_out(struct smc_sock *new_smc)
+ atomic_dec(&lsmc->queued_smc_hs);
+
+ release_sock(newsmcsk); /* lock in smc_listen_work() */
++ lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
+ if (lsmc->sk.sk_state == SMC_LISTEN) {
+- lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
+ smc_accept_enqueue(&lsmc->sk, newsmcsk);
+ release_sock(&lsmc->sk);
+ } else { /* no longer listening */
++ release_sock(&lsmc->sk);
+ smc_close_non_accepted(newsmcsk);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From f835e31bec55bd97eec618d3f5d7b51115e218b0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 14:38:50 +0000
+Subject: net: thunderbolt: Tear down DMA paths before stopping the rings
+
+From: Fan XinRan <shinjiangjiang@gmail.com>
+
+[ Upstream commit 68bf02b6b4ad3f748c6db71fd77b6c0402d252f4 ]
+
+tbnet_tear_down() stops both rings and frees their frame buffers before
+calling tb_xdomain_disable_paths(). tb_ring_stop() zeroes the ring's
+descriptor base and tbnet_free_buffers() unmaps and frees the pages the
+frames sit in, so by the time __tb_path_deactivate_hop() polls the hop's
+'pending' bit, anything still in flight has nowhere to drain to.
+
+The teardown sequence has been in this order since the driver was added.
+The setup path has not: commit ff7cd07f3064 ("net: thunderbolt: Enable
+DMA paths only after rings are enabled") moved the path enable to the end
+of tbnet_connected_work() and documented why:
+
+ /* Both logins successful so enable the rings, high-speed DMA
+ * paths and start the network device queue.
+ *
+ * Note we enable the DMA paths last to make sure we have primed
+ * the Rx ring before any incoming packets are allowed to
+ * arrive.
+ */
+
+Teardown was never updated to match, so the rings and the paths now come
+down in the same order they go up instead of in reverse.
+
+On an ASMedia ASM4242 host router the 'pending' bit then never clears:
+every teardown burns the full 500 ms timeout and
+__tb_path_deactivate_hop() returns -ETIMEDOUT. Raising the timeout to
+5 s does not help, so the hop is not slow to drain, it never drains
+at all.
+
+The failure is invisible above the thunderbolt core.
+__tb_path_deactivate_hops() is void and only calls tb_port_warn();
+tb_path_deactivate(), tb_tunnel_deactivate() and
+__tb_disconnect_xdomain_paths() are void as well, and
+tb_disconnect_xdomain_paths() ends in an unconditional "return 0". So
+tb_xdomain_disable_paths() reports success and the netdev_warn() below
+it never fires. Repeated teardowns eventually take the XDomain control
+channel down, after which the peer node is gone and only a power cycle
+brings the controller back.
+
+Deactivating the paths first fixes it. Measured with kretprobes on a
+stock v6.17 tree with no other patches applied, on a link that was up
+and had just carried traffic:
+
+ before: __tb_path_deactivate_hop() returns 0 for the first hop, then
+ -ETIMEDOUT for the second 500335 us later
+ after: 0 for both, 525 us apart
+
+Alternating the two orderings ABBA over three load levels, four
+teardowns per arm: every teardown failed before the change (21 of 21
+that ran), none failed after (0 of 24). The before arms ran short
+because the link died partway through. The same split shows up when
+the interface is enslaved to a bond instead of just brought down, which
+is how I ran into this in the first place. Throughput and latency after
+the change are unchanged.
+
+Hosts whose routers drain the hop despite the stale descriptor base see
+no functional difference, since the paths end up deactivated either way.
+
+Fixes: e69b6c02b4c3 ("net: Add support for networking over Thunderbolt cable")
+Signed-off-by: Fan XinRan <shinjiangjiang@gmail.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Link: https://patch.msgid.link/20260803-b4-tbnet-teardown-v2-1-27de6a13ca2d@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/thunderbolt/main.c | 20 +++++++++++++++-----
+ 1 file changed, 15 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c
+index 960839a651e51..ceaba08cd378a 100644
+--- a/drivers/net/thunderbolt/main.c
++++ b/drivers/net/thunderbolt/main.c
+@@ -389,11 +389,16 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)
+ break;
+ }
+
+- tb_ring_stop(net->rx_ring.ring);
+- tb_ring_stop(net->tx_ring.ring);
+- tbnet_free_buffers(&net->rx_ring);
+- tbnet_free_buffers(&net->tx_ring);
+-
++ /* Tear the paths down before stopping the rings. This mirrors
++ * tbnet_connected_work(), which enables the paths last so the
++ * Rx ring is primed before packets can arrive. Stopping a
++ * ring zeroes its descriptor base and tbnet_free_buffers()
++ * unmaps and frees the frame buffers, leaving anything still
++ * in flight with nowhere to drain to;
++ * __tb_path_deactivate_hop() then waits for the hop's
++ * 'pending' bit, which on some host routers never clears in
++ * that state.
++ */
+ ret = tb_xdomain_disable_paths(net->xd,
+ net->local_transmit_path,
+ net->tx_ring.ring->hop,
+@@ -402,6 +407,11 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)
+ if (ret)
+ netdev_warn(net->dev, "failed to disable DMA paths\n");
+
++ tb_ring_stop(net->rx_ring.ring);
++ tb_ring_stop(net->tx_ring.ring);
++ tbnet_free_buffers(&net->rx_ring);
++ tbnet_free_buffers(&net->tx_ring);
++
+ tb_xdomain_release_in_hopid(net->xd, net->remote_transmit_path);
+ net->remote_transmit_path = 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From e150589a970d2808d2190209e0c52aee3a7696b5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 20:38:50 +0200
+Subject: netfilter: ipset: switch ext_size to atomic64_t
+
+From: Jozsef Kadlecsik <kadlec@netfilter.org>
+
+[ Upstream commit 712a6f545c359b427daa9a5a782e30d2f8331e25 ]
+
+The hash types do not acquire set->lock, they use 'region locking' where
+only part of the hash table is locked. Parallel inserts and deletes are
+possible and CPUs can race on ->ext_size update. Switch to atomic64_t.
+
+This leaves another bug unresolved: there still can be a race on
+comment extension re-init. This will be handled in a later commit
+when converting to rhashtable backend.
+
+Fixes: f66ee0410b1c ("netfilter: ipset: Fix "INFO: rcu detected stall in hash_xxx" reports")
+Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/netfilter/ipset/ip_set.h | 2 +-
+ net/netfilter/ipset/ip_set_bitmap_gen.h | 4 ++--
+ net/netfilter/ipset/ip_set_core.c | 6 +++---
+ net/netfilter/ipset/ip_set_hash_gen.h | 2 +-
+ net/netfilter/ipset/ip_set_list_set.c | 4 ++--
+ 5 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
+index b98331572ad29..cadae9b2578f1 100644
+--- a/include/linux/netfilter/ipset/ip_set.h
++++ b/include/linux/netfilter/ipset/ip_set.h
+@@ -273,7 +273,7 @@ struct ip_set {
+ /* Number of elements (vs timeout) */
+ u32 elements;
+ /* Size of the dynamic extensions (vs timeout) */
+- size_t ext_size;
++ atomic64_t ext_size;
+ /* Element data size */
+ size_t dsize;
+ /* Offsets to extensions in elements */
+diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h
+index cb48a2b9cb9fd..cf8468bf987db 100644
+--- a/net/netfilter/ipset/ip_set_bitmap_gen.h
++++ b/net/netfilter/ipset/ip_set_bitmap_gen.h
+@@ -77,7 +77,7 @@ mtype_flush(struct ip_set *set)
+ mtype_ext_cleanup(set);
+ bitmap_zero(map->members, map->elements);
+ set->elements = 0;
+- set->ext_size = 0;
++ atomic64_set(&set->ext_size, 0);
+ }
+
+ /* Calculate the actual memory size of the set data */
+@@ -93,7 +93,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
+ {
+ const struct mtype *map = set->data;
+ struct nlattr *nested;
+- size_t memsize = mtype_memsize(map, set->dsize) + set->ext_size;
++ size_t memsize = mtype_memsize(map, set->dsize) + atomic64_read(&set->ext_size);
+
+ nested = nla_nest_start(skb, IPSET_ATTR_DATA);
+ if (!nested)
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index f51a1af31513c..29bf5ee74fe36 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -350,7 +350,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
+ size_t len = ext->comment ? strlen(ext->comment) : 0;
+
+ if (unlikely(c)) {
+- set->ext_size -= sizeof(*c) + strlen(c->str) + 1;
++ atomic64_sub(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
+ rcu_assign_pointer(comment->c, NULL);
+ kfree_rcu(c, rcu);
+ }
+@@ -362,7 +362,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
+ if (unlikely(!c))
+ return;
+ strscpy(c->str, ext->comment, len + 1);
+- set->ext_size += sizeof(*c) + strlen(c->str) + 1;
++ atomic64_add(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
+ rcu_assign_pointer(comment->c, c);
+ }
+ EXPORT_SYMBOL_GPL(ip_set_init_comment);
+@@ -392,7 +392,7 @@ ip_set_comment_free(struct ip_set *set, void *ptr)
+ c = rcu_dereference_protected(comment->c, 1);
+ if (unlikely(!c))
+ return;
+- set->ext_size -= sizeof(*c) + strlen(c->str) + 1;
++ atomic64_sub(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
+ rcu_assign_pointer(comment->c, NULL);
+ kfree_rcu(c, rcu);
+ }
+diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
+index 4c1082e38e3d1..81d7f601ed06a 100644
+--- a/net/netfilter/ipset/ip_set_hash_gen.h
++++ b/net/netfilter/ipset/ip_set_hash_gen.h
+@@ -1289,7 +1289,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
+ rcu_read_lock_bh();
+ t = rcu_dereference_bh(h->table);
+ mtype_ext_size(set, &elements, &ext_size);
+- memsize = mtype_ahash_memsize(h, t) + ext_size + set->ext_size;
++ memsize = mtype_ahash_memsize(h, t) + ext_size + atomic64_read(&set->ext_size);
+ htable_bits = t->htable_bits;
+ rcu_read_unlock_bh();
+
+diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
+index 83e1fdcc752d6..9d6ab69ca1a37 100644
+--- a/net/netfilter/ipset/ip_set_list_set.c
++++ b/net/netfilter/ipset/ip_set_list_set.c
+@@ -421,7 +421,7 @@ list_set_flush(struct ip_set *set)
+ list_for_each_entry_safe(e, n, &map->members, list)
+ list_set_del(set, e);
+ set->elements = 0;
+- set->ext_size = 0;
++ atomic64_set(&set->ext_size, 0);
+ }
+
+ static void
+@@ -455,7 +455,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
+ {
+ const struct list_set *map = set->data;
+ struct nlattr *nested;
+- size_t memsize = list_set_memsize(map, set->dsize) + set->ext_size;
++ size_t memsize = list_set_memsize(map, set->dsize) + atomic64_read(&set->ext_size);
+
+ nested = nla_nest_start(skb, IPSET_ATTR_DATA);
+ if (!nested)
+--
+2.53.0
+
--- /dev/null
+From 5f96b7d574fd9c09b49512dd098211ef3aeb436b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 30 Jun 2026 14:31:00 -0400
+Subject: NFS: Pin the 'struct nfs_server' during a FREE_STATEID call
+
+From: Anna Schumaker <anna.schumaker@hammerspace.com>
+
+[ Upstream commit cf616096a0f3a2b60f7d68b6b39674a6867ded9c ]
+
+Dan Aloni reports that he was able to hit a use-after-free bug if a
+FREE_STATEID operation gets delayed for whatever reason. Fix this by
+bumping the refcount of the 'struct nfs_server' object for the duration
+of the FREE_STATEID so it doesn't get cleaned up from underneath us
+while operations are still in flight.
+
+Reported-by: Dan Aloni <dan.aloni@vastdata.com>
+Fixes: 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call")
+Tested-by: Dan Aloni <dan.aloni@vastdata.com>
+Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/nfs4proc.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index 840789e182ef3..facd4e28770be 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -10585,6 +10585,7 @@ static void nfs41_free_stateid_release(void *calldata)
+ struct nfs_free_stateid_data *data = calldata;
+ struct nfs_client *clp = data->server->nfs_client;
+
++ nfs_sb_deactive(data->server->super);
+ nfs_put_client(clp);
+ kfree(calldata);
+ }
+@@ -10626,6 +10627,10 @@ static int nfs41_free_stateid(struct nfs_server *server,
+
+ if (!refcount_inc_not_zero(&clp->cl_count))
+ return -EIO;
++ if (!nfs_sb_active(server->super)) {
++ nfs_put_client(clp);
++ return -EIO;
++ }
+
+ nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
+ &task_setup.rpc_client, &msg);
+--
+2.53.0
+
--- /dev/null
+From b448d20c7ea930a4ab80846136ccfbfad91b6db7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 17:00:30 +0000
+Subject: pds_core: cancel pending PCI reset work on AER recovery
+
+From: Nikhil P. Rao <nikhil.rao@amd.com>
+
+[ Upstream commit 57d635329d799b79096155cdf47ee0013d6780d1 ]
+
+pdsc_check_pci_health() queues pci_reset_work when it sees a broken PCI
+connection, and nothing cancels it. When the PCI core starts AER
+recovery, pdsc_pci_error_detected() runs pdsc_reset_prepare() and
+recovers the device, but a pci_reset_work queued just before is left
+pending. If it runs after recovery released the device lock, it resets a
+device the driver now considers healthy, bouncing the link for no reason.
+
+Cancel pci_reset_work in pdsc_pci_error_detected() after
+pdsc_reset_prepare(), which has already stopped the health thread so it
+cannot requeue the work. cancel_work_sync() is safe under the device
+lock here because pdsc_pci_reset_thread() uses pci_try_reset_function(),
+which returns instead of blocking on the lock. Only PFs initialize
+pci_reset_work, so guard the cancel with !is_virtfn.
+
+Fixes: 81665adf25d2 ("pds_core: Fix pdsc_check_pci_health function to use work thread")
+Reported-by: sashiko-bot <sashiko-bot@kernel.org>
+Closes: https://sashiko.dev/#/patchset/20260714180223.1642792-2-nikhil.rao%40amd.com?part=1
+Signed-off-by: Nikhil P. Rao <nikhil.rao@amd.com>
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Link: https://patch.msgid.link/20260727170030.361116-1-nikhil.rao@amd.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/amd/pds_core/main.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c
+index 2329396ec3e25..9526223a72978 100644
+--- a/drivers/net/ethernet/amd/pds_core/main.c
++++ b/drivers/net/ethernet/amd/pds_core/main.c
+@@ -550,7 +550,11 @@ static pci_ers_result_t pdsc_pci_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t error)
+ {
+ if (error == pci_channel_io_frozen) {
++ struct pdsc *pdsc = pci_get_drvdata(pdev);
++
+ pdsc_reset_prepare(pdev);
++ if (!pdev->is_virtfn)
++ cancel_work_sync(&pdsc->pci_reset_work);
+ return PCI_ERS_RESULT_NEED_RESET;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From d7214c5db97de33d0312a0657fefd5e0352ccc6f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 16:45:48 +0000
+Subject: pds_core: keep the health thread stopped during reset
+
+From: Nikhil P. Rao <nikhil.rao@amd.com>
+
+[ Upstream commit cd09971dcc1c499ae0879010a00e9dba87abdc4f ]
+
+Commit d9407ff11809 ("pds_core: Prevent health thread from running
+during reset/remove") stops the health thread with cancel_work_sync()
+before a reset, but a devcmd timeout during pdsc_fw_down() re-queues
+health_work, so pdsc_health_thread() runs again mid-reset and double
+allocates the core DMA queues via pdsc_fw_up().
+
+Only the reset path is affected: on remove PDSC_S_STOPPING_DRIVER gates
+the health thread and the workqueue is destroyed.
+
+Use disable_work_sync() to cancel health_work and block further
+queue_work() on it, and enable_work() in pdsc_restart_health_thread() to
+re-allow it after the reset.
+
+disable_work_sync() keeps a disable depth, so every disable must be
+matched by one enable. pdsc_reset_prepare() stops the health thread and
+pdsc_reset_done() restarts it. On the AER path pdsc_pci_error_detected()
+calls pdsc_reset_prepare(), then pdsc_pci_error_resume() re-inits via
+pci_reset_function_locked() (pds_core has no .slot_reset handler), which
+runs the pair again - stopping the thread twice but restarting it once.
+Gate the disable and enable on a health_stopped flag so each fires at
+most once per stopped/running transition.
+
+Fixes: d9407ff11809 ("pds_core: Prevent health thread from running during reset/remove")
+Reported-by: sashiko-bot <sashiko-bot@kernel.org>
+Closes: https://sashiko.dev/#/patchset/20260629200358.2626129-1-nikhil.rao%40amd.com?part=2
+Signed-off-by: Nikhil P. Rao <nikhil.rao@amd.com>
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Link: https://patch.msgid.link/20260727164548.359562-1-nikhil.rao@amd.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/amd/pds_core/core.h | 1 +
+ drivers/net/ethernet/amd/pds_core/main.c | 10 ++++++++--
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h
+index becd3104473c2..4dbfe2373b3ac 100644
+--- a/drivers/net/ethernet/amd/pds_core/core.h
++++ b/drivers/net/ethernet/amd/pds_core/core.h
+@@ -170,6 +170,7 @@ struct pdsc {
+ struct timer_list wdtimer;
+ unsigned int wdtimer_period;
+ struct work_struct health_work;
++ bool health_stopped;
+ struct devlink_health_reporter *fw_reporter;
+ u32 fw_recoveries;
+
+diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c
+index c78b17d230a84..2329396ec3e25 100644
+--- a/drivers/net/ethernet/amd/pds_core/main.c
++++ b/drivers/net/ethernet/amd/pds_core/main.c
+@@ -464,8 +464,10 @@ static void pdsc_stop_health_thread(struct pdsc *pdsc)
+ return;
+
+ timer_shutdown_sync(&pdsc->wdtimer);
+- if (pdsc->health_work.func)
+- cancel_work_sync(&pdsc->health_work);
++ if (pdsc->health_work.func && !pdsc->health_stopped) {
++ disable_work_sync(&pdsc->health_work);
++ pdsc->health_stopped = true;
++ }
+ }
+
+ static void pdsc_restart_health_thread(struct pdsc *pdsc)
+@@ -473,6 +475,10 @@ static void pdsc_restart_health_thread(struct pdsc *pdsc)
+ if (pdsc->pdev->is_virtfn)
+ return;
+
++ if (pdsc->health_stopped) {
++ enable_work(&pdsc->health_work);
++ pdsc->health_stopped = false;
++ }
+ timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0);
+ mod_timer(&pdsc->wdtimer, jiffies + 1);
+ }
+--
+2.53.0
+
--- /dev/null
+From c20093e513b188043cfddb54cf1b19c7f46c5167 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 12:29:48 +0000
+Subject: Revert "net: thunderbolt: Enable end-to-end flow control also in
+ transmit"
+
+From: Fan Ye <fy15309206903@gmail.com>
+
+[ Upstream commit 1881f2efbf7f78dc0a79a387b29fde6ff56d3731 ]
+
+This reverts commit a8065af3346ebd7c76ebc113451fb3ba94cf7769.
+
+Per the USB4 spec, a Transmit Descriptor Ring with E2E flow control
+disabled does not require any credits to be available before the Host
+Interface Adapter Layer transmits a tunneled packet from it. Once E2E is
+enabled on that ring the controller must first obtain end-to-end
+credits.
+
+The ASMedia ASM4242 USB4 host router (PCI 1b21:2425) never delivers
+those credits. The controller does accept the configuration: reading the
+ring OPTIONS register back right after tb_ring_start() returns exactly
+what was written, including RING_FLAG_E2E_FLOW_CONTROL (bit 28) and the
+E2E HopID field. No credit ever arrives though, so the Tx ring's
+hardware consumer index never advances and the link carries no traffic
+at all.
+
+Measured on two hosts connected point to point, onboard ASM4242 on MSI
+X870E and X870, v6.17, stock drivers/net/thunderbolt/main.c with only
+this revert applied on top:
+
+ before: 100% packet loss to the peer; thunderbolt0 is up and the
+ XDomain handshake completes ("new host found"), but iperf3
+ fails with "No route to host" once the neighbour entry
+ expires
+ after: 0% packet loss, 0.28 ms RTT; iperf3 4.21 Gb/s one way and
+ 5.17 Gb/s the other (5 runs each, stddev <= 0.02), 1
+ retransmit in 10 s
+
+An instrumented build additionally showed a frozen-Tx-consumer watchdog
+firing ~30k times in a 10 s window before this change.
+
+Rx-side E2E is not touched by this revert, so peers that do return
+credits keep receive-side flow control.
+
+ASMedia does not look like an isolated case. The out-of-tree
+thunderbolt-ibverbs project disables native E2E on AMD NHI by default,
+noting that "Strix Halo has reproduced TX completion wedges with
+multiple native E2E rings active" -- the same failure mode, on a
+different vendor. Since the driver has no way to tell in advance which
+host router returns the credits, going back to the previous behaviour
+looks safer than adding a quirk per affected part; Tx-side E2E can be
+reintroduced as an opt-in for controllers that are known to implement
+the credit return.
+
+Note that the reverted commit was not fixing a reported problem, it was
+derived from the spec wording alone, so this revert is not expected to
+regress a known workload. Cc'ing the original author in case there was
+one.
+
+Fixes: a8065af3346e ("net: thunderbolt: Enable end-to-end flow control also in transmit")
+Cc: zhangjianrong <zhangjianrong5@huawei.com>
+Signed-off-by: Fan Ye <fy15309206903@gmail.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Link: https://patch.msgid.link/20260727123002.25225-1-fy15309206903@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/thunderbolt/main.c | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c
+index 5d7d11d75b0b8..960839a651e51 100644
+--- a/drivers/net/thunderbolt/main.c
++++ b/drivers/net/thunderbolt/main.c
+@@ -928,12 +928,8 @@ static int tbnet_open(struct net_device *dev)
+
+ netif_carrier_off(dev);
+
+- flags = RING_FLAG_FRAME;
+- /* Only enable full E2E if the other end supports it too */
+- if (tbnet_e2e && net->svc->prtcstns & TBNET_E2E)
+- flags |= RING_FLAG_E2E;
+-
+- ring = tb_ring_alloc_tx(xd->tb->nhi, -1, TBNET_RING_SIZE, flags);
++ ring = tb_ring_alloc_tx(xd->tb->nhi, -1, TBNET_RING_SIZE,
++ RING_FLAG_FRAME);
+ if (!ring) {
+ netdev_err(dev, "failed to allocate Tx ring\n");
+ return -ENOMEM;
+@@ -952,6 +948,11 @@ static int tbnet_open(struct net_device *dev)
+ sof_mask = BIT(TBIP_PDF_FRAME_START);
+ eof_mask = BIT(TBIP_PDF_FRAME_END);
+
++ flags = RING_FLAG_FRAME;
++ /* Only enable full E2E if the other end supports it too */
++ if (tbnet_e2e && net->svc->prtcstns & TBNET_E2E)
++ flags |= RING_FLAG_E2E;
++
+ ring = tb_ring_alloc_rx(xd->tb->nhi, -1, TBNET_RING_SIZE, flags,
+ net->tx_ring.ring->hop, sof_mask,
+ eof_mask, tbnet_start_poll, net);
+--
+2.53.0
+
--- /dev/null
+From 518cad2e31e88bf9af01a051848b761626d77be6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 11:18:40 -0400
+Subject: sctp: clear control chunk transport if it is being removed
+
+From: Xin Long <lucien.xin@gmail.com>
+
+[ Upstream commit c9158ceaf27780ef64534ad72f44ffde3f8ccc49 ]
+
+sctp_make_heartbeat_ack() caches the destination transport in
+chunk->transport without taking a reference. When src_out_of_asoc_ok is
+enabled, the HEARTBEAT ACK may remain queued on control_chunk_list instead
+of being transmitted immediately.
+
+If the peer transport is removed while the chunk is still queued,
+sctp_assoc_rm_peer() drops the transport and schedules it for RCU freeing,
+but only clears cached transport pointers in out_chunk_list. The queued
+control chunk therefore retains a dangling transport pointer.
+
+Once an ASCONF_ACK clears the suppression and the queued control chunk is
+transmitted, SCTP dereferences the stale transport pointer, leading to a
+use-after-free.
+
+Fix this by also clearing chunk->transport for queued control chunks in
+control_chunk_list when removing the transport.
+
+Fixes: 8a07eb0a50ae ("sctp: Add ASCONF operation on the single-homed host")
+Reported-by: Daniele Linguaglossa <danielelinguaglossa@gmail.com>
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/7e1168cb722132152a29d47e5eafaeac4a3bf6f3.1785943120.git.lucien.xin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/associola.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/net/sctp/associola.c b/net/sctp/associola.c
+index 44f06c5f1f256..ebdc48be47813 100644
+--- a/net/sctp/associola.c
++++ b/net/sctp/associola.c
+@@ -573,6 +573,10 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
+ if (ch->transport == peer)
+ ch->transport = NULL;
+
++ list_for_each_entry(ch, &asoc->outqueue.control_chunk_list, list)
++ if (ch->transport == peer)
++ ch->transport = NULL;
++
+ asoc->peer.transport_count--;
+
+ sctp_ulpevent_notify_peer_addr_change(peer, SCTP_ADDR_REMOVED, 0);
+--
+2.53.0
+
--- /dev/null
+From cdcadca44dbfabc328f32087de184c92f166c53b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 10:55:14 +0800
+Subject: sctp: fix addip_serial increment on ASCONF_ACK allocation failure
+
+From: Qing Luo <luoqing@kylinos.cn>
+
+[ Upstream commit aa2e13ae8d3cbe2c15ef4f7e971b2de0832794aa ]
+
+In sctp_process_asconf(), when sctp_make_asconf_ack() fails to allocate
+the ASCONF_ACK chunk due to memory pressure, the code jumps to the
+done label where asoc->peer.addip_serial is unconditionally incremented.
+
+This leaves the peer's ASCONF (serial N) unacknowledged while the local
+endpoint now expects serial N+1. When the peer retransmits serial N, it
+falls into the serial < addip_serial + 1 branch ,
+which attempts to look up a cached ACK for serial N. No cached ACK
+exists since the allocation failed, so the retransmission is silently
+discarded. The peer eventually times out and ABORTs the association.
+
+Move the addip_serial increment inside the if (asconf_ack) block so that
+the serial number is only advanced when the ASCONF_ACK is successfully
+created and cached. This way, on allocation failure, the serial number
+is unchanged and the peer's retransmitted ASCONF will be correctly
+re-processed.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Qing Luo <luoqing@kylinos.cn>
+Acked-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/20260804025514.241767-1-l1138897701@163.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/sm_make_chunk.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
+index 27a7739a7d424..b6eb79ef6a55d 100644
+--- a/net/sctp/sm_make_chunk.c
++++ b/net/sctp/sm_make_chunk.c
+@@ -3354,12 +3354,11 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
+ goto done;
+ }
+ done:
+- asoc->peer.addip_serial++;
+-
+ /* If we are sending a new ASCONF_ACK hold a reference to it in assoc
+ * after freeing the reference to old asconf ack if any.
+ */
+ if (asconf_ack) {
++ asoc->peer.addip_serial++;
+ sctp_chunk_hold(asconf_ack);
+ list_add_tail(&asconf_ack->transmitted_list,
+ &asoc->asconf_ack_list);
+--
+2.53.0
+
--- /dev/null
+From ef4fb802705b6b0b3209e543dd57b40010a1fb40 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 21:46:35 +0200
+Subject: selftests/ftrace: refactor eprobes test to fix argument checks
+
+From: Martin Kaiser <martin@kaiser.cx>
+
+[ Upstream commit 6e3abef2a27e7402a94111c9eff85d887e64a309 ]
+
+The add/remove eprobe test installs an eprobe for the openat syscall and
+runs ls. It checks the filenames that were opened by ls against a
+whitelist and a blacklist.
+
+Commit 206b25c09080 ("tracing: eprobe: read the complete FILTER_PTR_STRING
+pointer") fixed access to some string fields in eprobes. This triggers
+test failures as the blacklist does not allow relative paths for the
+openat parameters.
+
+What makes this test unstable is the fact that the openat calls vary a
+lot between different systems.
+
+Refactor the test to make it more robust. "cd <directory>" will issue a
+chdir syscall with the target directory as parameter. Set an eprobe on
+the sys_enter_chdir event and filter for the exact directory name. Allow
+(fault) as fallback.
+
+Link: https://lore.kernel.org/all/20260804194705.760893-1-martin@kaiser.cx/
+
+Fixes: 206b25c09080 ("tracing: eprobe: read the complete FILTER_PTR_STRING pointer")
+Reported-by: kernel test robot <oliver.sang@intel.com>
+Closes: https://lore.kernel.org/oe-lkp/202607151010.b68428e1-lkp@intel.com
+Signed-off-by: Martin Kaiser <martin@kaiser.cx>
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ftrace/test.d/dynevent/add_remove_eprobe.tc | 16 +++++-----------
+ 1 file changed, 5 insertions(+), 11 deletions(-)
+
+diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
+index c300eb0202620..e2322693d0c32 100644
+--- a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
++++ b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
+@@ -1,16 +1,16 @@
+ #!/bin/sh
+ # SPDX-License-Identifier: GPL-2.0
+ # description: Generic dynamic event - add/remove eprobe events
+-# requires: dynamic_events events/syscalls/sys_enter_openat "<attached-group>.<attached-event> [<args>]":README
++# requires: dynamic_events events/syscalls/sys_enter_chdir "<attached-group>.<attached-event> [<args>]":README
+
+ echo 0 > events/enable
+
+ clear_dynamic_events
+
+ SYSTEM="syscalls"
+-EVENT="sys_enter_openat"
++EVENT="sys_enter_chdir"
+ FIELD="filename"
+-EPROBE="eprobe_open"
++EPROBE="eprobe_chdir"
+ OPTIONS="file=+0(\$filename):ustring"
+ echo "e:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
+
+@@ -18,20 +18,14 @@ grep -q "$EPROBE" dynamic_events
+ test -d events/eprobes/$EPROBE
+
+ echo 1 > events/eprobes/$EPROBE/enable
+-ls
++cd /sys/kernel/tracing
+ echo 0 > events/eprobes/$EPROBE/enable
+
+-content=`grep '^ *ls-' trace | grep 'file='`
+-nocontent=`grep '^ *ls-' trace | grep 'file=' | grep -v -e '"/' -e '"."' -e '(fault)' ` || true
+-
++content=`grep -e 'file="/sys/kernel/tracing"\|(fault)' trace`
+ if [ -z "$content" ]; then
+ exit_fail
+ fi
+
+-if [ ! -z "$nocontent" ]; then
+- exit_fail
+-fi
+-
+ echo "-:$EPROBE" >> dynamic_events
+
+ ! grep -q "$EPROBE" dynamic_events
+--
+2.53.0
+
drm-amd-display-add-av-mute-wait-frames-to-dce110_se.patch
drm-amd-display-check-for-tg-ops-in-dce110_set_avmut.patch
s390-zcrypt-fix-missing-mem-scrub-at-clear-key-impor.patch
+nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch
+arm64-dts-broadcom-bcm2712-remove-non-functional-el2.patch
+arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch
+arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch
+drm-bridge-ps8640-propagate-aux-transfer-register-er.patch
+net-hns3-fix-speed-configuration-residue-after-drive.patch
+revert-net-thunderbolt-enable-end-to-end-flow-contro.patch
+bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch
+enic-fix-tx_hang_reset-use-after-free-on-device-remo.patch
+net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch
+pds_core-keep-the-health-thread-stopped-during-reset.patch
+pds_core-cancel-pending-pci-reset-work-on-aer-recove.patch
+netfilter-ipset-switch-ext_size-to-atomic64_t.patch
+ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch
+ipvs-return-the-csum-validation-for-forward-hook.patch
+watchdog-bd96801_wdt-fix-timeout-for-enabled-wdg.patch
+btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch
+bpf-preserve-pointer-state-for-commuted-arithmetic.patch
+net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch
+net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch
+net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch
+devlink-fix-net-namespace-reference-leak-in-reload.patch
+net-mlx5-fw_tracer-return-null-on-create-error.patch
+counter-microchip-tcb-capture-fix-dt-channel-validat.patch
+bpf-tcp-make-mem-flags-configurable-through-bpf_iter.patch
+bpf-tcp-make-sure-iter-batch-always-contains-a-full-.patch
+bpf-tcp-get-rid-of-st_bucket_done.patch
+bpf-tcp-use-bpf_tcp_iter_batch_item-for-bpf_tcp_iter.patch
+bpf-tcp-avoid-socket-skips-and-repeats-during-iterat.patch
+bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch
+vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch
+vdpa-mlx5-fix-buffer-length-in-create_direct_keys.patch
+tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch
+xsk-require-at-least-16-bytes-of-tx-metadata.patch
+udp-fix-potential-use-after-free-in-tunnel-segmentat.patch
+net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch
+net-openvswitch-check-ethernet-header-length-in-key_.patch
+net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch
+hwmon-nzxt-smart2-check-return-value-of-init_device-.patch
+hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch
+selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch
+bnxt_en-move-rss-table-fill-outside-__bnxt_hwrm_vnic.patch
+bnxt_en-determine-and-store-default-rx-ring-in-vnic-.patch
+bnxt_en-refresh-vnic-default-ring-on-queue-restart-i.patch
+bnxt_en-fix-ptp-pps-setting-bug.patch
+sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch
+tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch
+net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch
+net-prestera-validate-firmware-header-length.patch
+net-remove-warn_on_once-from-sk_mc_loop.patch
+net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch
+net-thunderbolt-tear-down-dma-paths-before-stopping-.patch
+ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch
+net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch
+sctp-clear-control-chunk-transport-if-it-is-being-re.patch
+tls-don-t-abort-the-connection-on-signal-interrupted.patch
+hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch
+hwmon-ads7828-fix-external-vref-regulator-handling.patch
+hwmon-ltc4282-avoid-overflow-in-maximum-power-calcul.patch
+hwmon-ltc4282-clamp-negative-current-limits.patch
+hwmon-ltc4282-fix-parsing-adi-current-limit-sense-mi.patch
--- /dev/null
+From cddddf06cb080f0040e0f289d29fcb155a4a4744 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jul 2026 20:08:06 -0700
+Subject: tcp: do not change rcv_ssthresh in tcp_measure_rcv_mss()
+
+From: Nathan Gao <zcgao@amazon.com>
+
+[ Upstream commit 0e125ecfe20c077625cf0be8d750d5c3abc0dce9 ]
+
+Commit f5da7c45188e ("tcp: adjust rcvq_space after updating scaling
+ratio") replaced the direct window_clamp update in tcp_measure_rcv_mss()
+with a call to tcp_set_window_clamp(), a helper that implements the
+TCP_WINDOW_CLAMP setsockopt. As a side effect, the helper also shrinks
+rcv_ssthresh via __tcp_adjust_rcv_ssthresh().
+
+As a result, each scaling_ratio decrease detected by
+tcp_measure_rcv_mss() also cuts rcv_ssthresh. Elsewhere in TCP,
+rcv_ssthresh is usually cut under memory pressure and grows via
+tcp_grow_window().
+
+Flows whose segment sizes vary keep scaling_ratio oscillating, which
+leads to an unstable rcv_ssthresh: a dip of rcv_ssthresh only recovers
+via tcp_grow_window(), keeping the advertised window at a relatively
+low level even after the ratio itself has recovered, and can even stall
+the sender.
+
+Observed on a customer's proxy gateway after upgrading from kernel 6.1
+to 6.12: in the worst case, rcv_ssthresh was cut in half by a
+scaling_ratio dip. P99 latency jumped from <10ms on 6.1 to ~100ms on
+6.12, and almost returned to the 6.1 level with this patch applied.
+
+Restore the plain WRITE_ONCE() update of window_clamp, as introduced
+in commit a2cbb1603943 ("tcp: Update window clamping condition"), and
+keep the rcvq_space.space adjustment. Now rcv_ssthresh is decoupled from
+scaling_ratio changes in tcp_measure_rcv_mss().
+
+Fixes: f5da7c45188e ("tcp: adjust rcvq_space after updating scaling ratio")
+Signed-off-by: Nathan Gao <zcgao@amazon.com>
+Link: https://patch.msgid.link/20260725030806.28135-1-zcgao@amazon.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_input.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
+index e57917aefd508..2fb68455679a8 100644
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -247,7 +247,7 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb)
+ struct tcp_sock *tp = tcp_sk(sk);
+
+ val = tcp_win_from_space(sk, sk->sk_rcvbuf);
+- tcp_set_window_clamp(sk, val);
++ WRITE_ONCE(tp->window_clamp, val);
+
+ if (tp->window_clamp < tp->rcvq_space.space)
+ tp->rcvq_space.space = tp->window_clamp;
+--
+2.53.0
+
--- /dev/null
+From 8745835bc1b74aa07d0199ef3d21c486b6da09ab Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 14:17:38 +0800
+Subject: tcp: fix TFO max_qlen accounting across reuseport migration
+
+From: Jiayuan Chen <jiayuan.chen@linux.dev>
+
+[ Upstream commit a0ab2ba83e35159d81cec830a92e885ecf8139be ]
+
+A listener's TCP_FASTOPEN max_qlen stops being accurate and lets through
+far more pending Fast Open requests than it was configured for.
+
+This only shows up with SO_REUSEPORT listener migration, where closing a
+listener hands its still-pending TFO children over to a surviving one.
+
+fastopenq.qlen is charged in tcp_fastopen_create_child() when the child
+is created and uncharged in reqsk_fastopen_remove() when the handshake
+completes. The uncharge follows rsk_listener of the request the child
+points at, and inet_reqsk_clone() has repointed the child at a new
+request owned by the new listener, so the ++ and the -- land on two
+different sockets. The new listener's qlen drifts negative and its
+limit no longer binds.
+
+Charge the new listener during migration, like reqsk_queue_migrated()
+already does for queue->young and queue->qlen.
+
+Fixes: 54b92e841937 ("tcp: Migrate TCP_ESTABLISHED/TCP_SYN_RECV sockets in accept queues.")
+Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260803061739.134737-1-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/inet_connection_sock.c | 20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
+index 5ff45bc854422..91dcdb7567ace 100644
+--- a/net/ipv4/inet_connection_sock.c
++++ b/net/ipv4/inet_connection_sock.c
+@@ -987,11 +987,23 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req,
+
+ nreq->rsk_listener = sk;
+
+- /* We need not acquire fastopenq->lock
+- * because the child socket is locked in inet_csk_listen_stop().
+- */
+- if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener)
++ if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener) {
++ struct fastopen_queue *fastopenq;
++
++ /* reqsk_fastopen_remove() will uncharge nreq->rsk_listener,
++ * that is @sk, so charge it here. Unlike the listener
++ * being closed, @sk is live and needs its lock.
++ */
++ fastopenq = &inet_csk(sk)->icsk_accept_queue.fastopenq;
++ spin_lock_bh(&fastopenq->lock);
++ fastopenq->qlen++;
++ spin_unlock_bh(&fastopenq->lock);
++
++ /* We need not acquire fastopenq->lock
++ * because the child socket is locked in inet_csk_listen_stop().
++ */
+ rcu_assign_pointer(tcp_sk(nreq->sk)->fastopen_rsk, nreq);
++ }
+
+ return nreq;
+ }
+--
+2.53.0
+
--- /dev/null
+From eeed188adcc1abaa2277217059a79b95f9b207c3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 08:22:48 +0200
+Subject: tls: don't abort the connection on signal-interrupted sends
+
+From: Maximilian Immanuel Brandtner <maxbr@linux.ibm.com>
+
+[ Upstream commit af0e5cdd031f4f4a8f6d4160bfbda4f36872b0ed ]
+
+When a signal interrupts a blocking send, tls_tx_records() treats the
+resulting -ERESTARTSYS as a transmission failure and marks the socket
+errored via tls_err_abort() with the raw error code. Later syscalls
+return the kernel-internal errno 512 (ERESTARTSYS) to userspace, as the
+signal it stems from is no longer pending during syscall exit and thus
+never translated.
+
+An interrupted send is not a connection error: the partially sent record
+stays queued and is resent later. Interrupt error codes are therefore
+excluded from the abort in the same way as -EAGAIN.
+
+Fixes: b341ca51d267 ("tls: Fix tls_sw_sendmsg error handling")
+Signed-off-by: Maximilian Immanuel Brandtner <maxbr@linux.ibm.com>
+Link: https://patch.msgid.link/20260805063109.1772314-1-maxbr@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tls/tls_sw.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
+index 2b875369d5232..137a7914c3044 100644
+--- a/net/tls/tls_sw.c
++++ b/net/tls/tls_sw.c
+@@ -458,7 +458,7 @@ int tls_tx_records(struct sock *sk, int flags)
+ }
+
+ tx_err:
+- if (rc < 0 && rc != -EAGAIN)
++ if (rc < 0 && rc != -EAGAIN && rc != -EINTR && rc != -ERESTARTSYS)
+ tls_err_abort(sk, rc);
+
+ return rc;
+--
+2.53.0
+
--- /dev/null
+From 73c2b0537a3cf7795645a0026f10b90ffad884f5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 17:35:54 +0800
+Subject: udp: fix potential use-after-free in tunnel segmentation
+
+From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+
+[ Upstream commit d0f86fb36eb260abd10007b62c9dcc1028e03e61 ]
+
+__skb_udp_tunnel_segment() gets the UDP header before ensuring the
+tunnel header is in the skb head. If the pull reallocates skb->head,
+the saved UDP header pointer is no longer valid.
+
+Get the UDP header after the pull to avoid a potential use-after-free.
+
+Fixes: dbef491ebe7f ("udp: Use uh->len instead of skb->len to compute checksum in segmentation")
+Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+Reviewed-by: Antoine Tenart <atenart@kernel.org>
+Link: https://patch.msgid.link/20260730093554.68127-1-xuanqiang.luo@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/udp_offload.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
+index 99688014901ed..04246d1f8b3e7 100644
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -22,17 +22,19 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
+ int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
+ bool remcsum, need_csum, offload_csum, gso_partial;
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+- struct udphdr *uh = udp_hdr(skb);
+ u16 mac_offset = skb->mac_header;
+ __be16 protocol = skb->protocol;
+ u16 mac_len = skb->mac_len;
+ int udp_offset, outer_hlen;
++ struct udphdr *uh;
+ __wsum partial;
+ bool need_ipsec;
+
+ if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
+ goto out;
+
++ uh = udp_hdr(skb);
++
+ /* Adjust partial header checksum to negate old length.
+ * We cannot rely on the value contained in uh->len as it is
+ * possible that the actual value exceeds the boundaries of the
+--
+2.53.0
+
--- /dev/null
+From f521737662e751a84c1220161011c413eecf026b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 6 Jul 2026 16:15:37 +0200
+Subject: vdpa/mlx5: Fix buffer length in create_direct_keys()
+
+From: Christian Borntraeger <borntraeger@linux.ibm.com>
+
+[ Upstream commit 727e1f569855df83579edbd73dcb4a0723543a12 ]
+
+We have seen in our CI the following KASAN message:
+BUG: KASAN: slab-out-of-bounds in cmd_exec+0x550/0xca0 [mlx5_core]
+Read of size 272 at addr 0000000176795020 by task qemu-system-s39/82764
+[...]
+[<000011388ab3a7a0>] cmd_exec+0x550/0xca0 [mlx5_core]
+[<000011388ab3b61c>] mlx5_cmd_exec_cb+0x25c/0x4f0 [mlx5_core]
+[<000011388b21e82e>] mlx5_vdpa_exec_async_cmds+0x22e/0x5e0 [mlx5_vdpa]
+[<000011388b21fd44>] create_direct_keys+0x954/0xef0 [mlx5_vdpa]
+[...]
+The buggy address is located 4128 bytes inside of
+allocated 4384-byte region [0000000176794000, 0000000176795120)
+
+So in essence we read 16 bytes beyond 4384-byte allocation.
+create_direct_keys calculates the pointer and length for in and out
+buffers.
+The size calculation for in includes the entire structure
+size (out + in + mtt[]) but the pointer passed to cmd_exec points only
+to the 'in' field, skipping the 'out' field.
+
+This causes mlx5_copy_to_msg() to read beyond the allocated buffer
+by sizeof(out) bytes when copying command data.
+
+Properly calculate the input size to match the pointer and allocation size.
+
+Fixes: 0071b138d44a ("vdpa/mlx5: Create direct MKEYs in parallel")
+Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
+Tested-by: Dragos Tatulea <dtatulea@nvidia.com>
+Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Message-ID: <20260706141537.3510294-1-borntraeger@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vdpa/mlx5/core/mr.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c
+index c7a20278bc3ca..27abbe69b55cd 100644
+--- a/drivers/vdpa/mlx5/core/mr.c
++++ b/drivers/vdpa/mlx5/core/mr.c
+@@ -234,7 +234,8 @@ static int create_direct_keys(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *
+ cmds[i].out = cmd_mem->out;
+ cmds[i].outlen = sizeof(cmd_mem->out);
+ cmds[i].in = cmd_mem->in;
+- cmds[i].inlen = struct_size(cmd_mem, mtt, mttcount);
++ cmds[i].inlen = struct_size(cmd_mem, mtt, mttcount) -
++ offsetof(struct mlx5_create_mkey_mem, in);
+
+ fill_create_direct_mr(mvdev, dmr, cmd_mem);
+
+--
+2.53.0
+
--- /dev/null
+From cfc7f69b3756b93dcef4b1ceef8f776b4f9282eb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Jun 2026 15:02:02 -0700
+Subject: vhost/vdpa: reject overflowing PA map page counts on 32-bit
+
+From: Yousef Alhouseen <alhouseenyousef@gmail.com>
+
+[ Upstream commit 0619aaa34c0c2a2dcb07f0e9c8a34e7efb8c4cdf ]
+
+vhost_vdpa_pa_map() adds the IOVA page offset to the user-controlled map
+size before computing the number of pages to pin. On 32-bit systems,
+where unsigned long is narrower than u64, that addition can overflow and
+the code can pin and map fewer pages than the requested IOTLB range.
+
+Reject sizes that overflow the unsigned long page-count calculation.
+
+Fixes: 22af48cf91aa ("vdpa: factor out vhost_vdpa_pa_map() and vhost_vdpa_pa_unmap()")
+Acked-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Message-ID: <CAMuQ4bX-iDvcUOPPY+NLz95tkRJYwWqvzAr=U48uNaub_HZLGw@mail.gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vhost/vdpa.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
+index 2464c9de67712..a47fdcb61bf36 100644
+--- a/drivers/vhost/vdpa.c
++++ b/drivers/vhost/vdpa.c
+@@ -1102,6 +1102,7 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
+ unsigned int gup_flags = FOLL_LONGTERM;
+ unsigned long npages, cur_base, map_pfn, last_pfn = 0;
+ unsigned long lock_limit, sz2pin, nchunks, i;
++ unsigned long page_offset;
+ u64 start = iova;
+ long pinned;
+ int ret = 0;
+@@ -1114,7 +1115,13 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
+ if (perm & VHOST_ACCESS_WO)
+ gup_flags |= FOLL_WRITE;
+
+- npages = PFN_UP(size + (iova & ~PAGE_MASK));
++ page_offset = iova & ~PAGE_MASK;
++ if (size > ULONG_MAX - page_offset) {
++ ret = -EINVAL;
++ goto free;
++ }
++
++ npages = PFN_UP(size + page_offset);
+ if (!npages) {
+ ret = -EINVAL;
+ goto free;
+--
+2.53.0
+
--- /dev/null
+From 2dd8b4d1f264b9bcd20d171b5b46a015c112b2f3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:36:28 +0300
+Subject: watchdog: bd96801_wdt: Fix timeout for enabled WDG
+
+From: Matti Vaittinen <mazziesaccount@gmail.com>
+
+[ Upstream commit 1246aa2b6ccc8944676bd24ff3e37cc56b93b51b ]
+
+When watchdog is enabled at the probe time, the bd96801 driver retrieves
+the timeout configuration from the registers to set-up the heart-beat
+values.
+
+As Sashiko pointed out at
+https://lore.kernel.org/all/20260722085819.495211F000E9@smtp.kernel.org/
+the timeout values are incorrectly computed in driver, resulting wrong
+heartbeat. This leads to devere problems if watchdog was enabled at probe
+time.
+
+According to the data-sheet, the "too fast" ping limit is configured as
+multiple of FASTNG_MIN. Furthermore, the "too slow" ping limit is
+configured as multiples of "too fast" timeout. The FASTNG_MIN is set to
+11, meaning 1.1 mS and "too fast" and "too slow" limits are computed from
+this. Hence, converting the limits to mS should be done by dividing by 10,
+not by dividing by USEC_PER_MSEC.
+
+Fix this by dividing the timeout values with correct scaling factor.
+
+While at it, fix whitespace problem (double empty line).
+
+Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>
+Fixes: 09dad69757b6 ("watchdog: ROHM BD96801 PMIC WDG driver")
+Link: https://lore.kernel.org/r/amxskHmQbi9v-8_l@mva-rohm
+[groeck: Added reference to whitespace change to description]
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/watchdog/bd96801_wdt.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/watchdog/bd96801_wdt.c b/drivers/watchdog/bd96801_wdt.c
+index 12b74fd2bc052..a25b7cf1488b2 100644
+--- a/drivers/watchdog/bd96801_wdt.c
++++ b/drivers/watchdog/bd96801_wdt.c
+@@ -169,7 +169,6 @@ static int bd96801_set_wdt_mode(struct wdtbd96801 *w, unsigned int hw_margin,
+ int fastng, slowng, type, ret, reg, mask;
+ struct device *dev = w->dev;
+
+-
+ if (hw_margin_min * 1000 > FASTNG_MAX_US) {
+ dev_err(dev, "Unsupported fast timeout %u uS [max %u]\n",
+ hw_margin_min * 1000, FASTNG_MAX_US);
+@@ -258,10 +257,10 @@ static int bd96801_set_heartbeat_from_hw(struct wdtbd96801 *w,
+ fast = FASTNG_MIN << sel;
+
+ sel = (val & BD96801_WD_RATIO_MASK) + 1;
+- w->wdt.max_hw_heartbeat_ms = (fast << sel) / USEC_PER_MSEC;
++ w->wdt.max_hw_heartbeat_ms = (fast << sel) / 10;
+
+ if ((conf_reg & BD96801_WD_TYPE_MASK) == BD96801_WD_TYPE_WIN)
+- w->wdt.min_hw_heartbeat_ms = fast / USEC_PER_MSEC;
++ w->wdt.min_hw_heartbeat_ms = fast / 10;
+
+ return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From a387a9a36e20bee53f038ba56377a4b76fa180bc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 09:19:54 -0700
+Subject: xsk: require at least 16 bytes of TX metadata
+
+From: Stanislav Fomichev <sdf.kernel@gmail.com>
+
+[ Upstream commit 1bb30b181d9f0484e141f8411e15ed906d5c6780 ]
+
+AF_XDP accepts a TX metadata length as small as eight bytes, but every
+supported request needs the flags plus at least one eight-byte request
+field. Such short metadata also lets the kernel read beyond the registered
+area.
+
+Require 16 bytes rather than sizeof(struct xsk_tx_metadata) to preserve
+compatibility with applications that do not use launch-time metadata.
+
+Fixes: 341ac980eab9 ("xsk: Support tx_metadata_len")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Reported-by: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Link: https://lore.kernel.org/netdev/20260720155210.34229-1-blbllhy@gmail.com/
+Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
+Link: https://patch.msgid.link/20260727161959.885642-2-sdf@fomichev.me
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/xdp/xdp_umem.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c
+index 9ec7bd948acc7..81ffda5501078 100644
+--- a/net/xdp/xdp_umem.c
++++ b/net/xdp/xdp_umem.c
+@@ -209,6 +209,8 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
+ if (mr->flags & XDP_UMEM_TX_METADATA_LEN) {
+ if (mr->tx_metadata_len >= 256 || mr->tx_metadata_len % 8)
+ return -EINVAL;
++ if (mr->tx_metadata_len < 16)
++ return -EINVAL;
+ umem->tx_metadata_len = mr->tx_metadata_len;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From e103ae3ce08a81e9f370eed76a64937c46035332 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 25 Jul 2026 14:57:22 -0700
+Subject: ARM: dts: BCM5301X: fix PCIe controller 2 second interrupt
+
+From: Rosen Penev <rosenp@gmail.com>
+
+[ Upstream commit bab4d538f8485e0d48538fcb82b285df3779278e ]
+
+PCIe controller 2 has interrupts 0-4 mapping to GIC SPI 138-142. The
+mapping for interrupt 1 was incorrectly set to 138 due to a copy-paste
+error. Fix it to 139.
+
+Assisted-by: opencode:big-pickle
+Signed-off-by: Rosen Penev <rosenp@gmail.com>
+Link: https://lore.kernel.org/r/20260725215722.9323-1-rosenp@gmail.com
+Fixes: 3b3e35b279be ("ARM: dts: BCM5301X: Relicense AXI interrupts code to the GPL 2.0+ / MIT")
+Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/boot/dts/broadcom/bcm-ns.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/broadcom/bcm-ns.dtsi b/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
+index d0d5f7e52a917..f08d0a27de0b4 100644
+--- a/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
+@@ -138,7 +138,7 @@ axi@18000000 {
+
+ /* PCIe Controller 2 */
+ <0x00014000 0 &gic GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
+- <0x00014000 1 &gic GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00014000 1 &gic GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 2 &gic GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 3 &gic GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 4 &gic GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+--
+2.53.0
+
--- /dev/null
+From 4500feb8c4badefb3b7d7405c51046d084fd1f87 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 24 May 2026 23:38:46 -0400
+Subject: ARM: npcm: Fix OF node refcount leaks in SMP setup
+
+From: Yuho Choi <dbgh9129@gmail.com>
+
+[ Upstream commit 8eb052f48331474c2789d07b7f11165c323bd2f9 ]
+
+npcm7xx_smp_boot_secondary() and npcm7xx_smp_prepare_cpus() look up
+the GCR and SCU nodes with of_find_compatible_node(). The returned
+nodes are used for of_iomap(), but the node references are never
+released.
+
+of_iomap() does not consume the device node reference, and iounmap()
+only releases the MMIO mapping. Drop each node reference after the
+corresponding mapping attempt.
+
+Fixes: 7bffa14c9aed ("arm: npcm: add basic support for Nuvoton BMCs")
+Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
+Reviewed-by: Avi Fishman <avifishman70@gmail.com>
+Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/mach-npcm/platsmp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arm/mach-npcm/platsmp.c b/arch/arm/mach-npcm/platsmp.c
+index 41891d3aa1247..4c1fc9983746c 100644
+--- a/arch/arm/mach-npcm/platsmp.c
++++ b/arch/arm/mach-npcm/platsmp.c
+@@ -32,6 +32,7 @@ static int npcm7xx_smp_boot_secondary(unsigned int cpu,
+ goto out;
+ }
+ gcr_base = of_iomap(gcr_np, 0);
++ of_node_put(gcr_np);
+ if (!gcr_base) {
+ pr_err("could not iomap gcr");
+ ret = -ENOMEM;
+@@ -60,6 +61,7 @@ static void __init npcm7xx_smp_prepare_cpus(unsigned int max_cpus)
+ return;
+ }
+ scu_base = of_iomap(scu_np, 0);
++ of_node_put(scu_np);
+ if (!scu_base) {
+ pr_err("could not iomap scu");
+ return;
+--
+2.53.0
+
--- /dev/null
+From 17e2b92983b06e1a1448635e9a75164a4ef5cb5c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 21:45:27 +0100
+Subject: arm64: dts: broadcom: bcm2712: Remove non-functional EL2 virtual
+ timer
+
+From: Daniel Drake <dan@reactivated.net>
+
+[ Upstream commit 75952cfc7752c52a2b692b59d34ce160d3edabb2 ]
+
+Commit d87773de9efe1 ("clocksource/drivers/arm_arch_timer: Default to EL2
+virtual timer when running VHE") causes boot to hang on Raspberry Pi 5.
+The newly-selected EL2 virtual timer does not generate any interrupts,
+even though the GIC_DIST_ENABLE_SET flag has been confirmed set via
+readback.
+
+It is highly unusual that this timer interrupt is non-operational because
+this is a standard GIC interrupt corresponding to a standard Cortex-A76
+CPU timer. However, Broadcom have confirmed for this SoC:
+
+> the interrupt line was never connected in the first place as this was
+> not identified as being a requirement
+
+Remove the corresponding DeviceTree entry.
+
+Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Closes: https://lore.kernel.org/all/ea15cce1-b393-43f6-8d58-3d6f90f0c0cd@samsung.com/
+Fixes: faa3381267d0 ("arm64: dts: broadcom: Add minimal support for Raspberry Pi 5")
+Signed-off-by: Daniel Drake <dan@reactivated.net>
+Link: https://lore.kernel.org/r/20260716-bcm2712-el2-v2-1-e708f7fb42fa@reactivated.net
+Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+index d771694787b28..45a382f75b5ec 100644
+--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+@@ -651,8 +651,6 @@ IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
+ IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_LOW)>,
+- <GIC_PPI 12 (GIC_CPU_MASK_SIMPLE(4) |
+ IRQ_TYPE_LEVEL_LOW)>;
+ };
+
+--
+2.53.0
+
--- /dev/null
+From 76f8ef835980d62931cab55379a8488d334ae727 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Apr 2026 02:38:51 +0530
+Subject: arm64: dts: qcom: purwa: Fix GPU IOMMU property
+
+From: Akhil P Oommen <akhilpo@oss.qualcomm.com>
+
+[ Upstream commit 4cd774c1feb3f720265c512174c5c3312eca1be2 ]
+
+Purwa's GPU does not support SID 1, which is typically used for
+LPAC-related traffic. Remove SID 1 from the GPU node's iommus property to
+accurately describe the hardware. This fixes the splat below, seen with
+some versions of Gunyah hypervisor:
+
+ Internal error: synchronous external abort: 0000000096000010 [#1] SMP
+ CPU: 0 UID: 0 PID: 80 Comm: kworker/u33:2 Tainted: G M
+ Tainted: [M]=MACHINE_CHECK
+ Hardware name: Qualcomm Technologies, Inc. Purwa IoT EVK (DT)
+ Workqueue: events_unbound deferred_probe_work_func
+ pstate: 21400005 (nzCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
+ pc : arm_smmu_write_s2cr+0x9c/0xbc
+ lr : arm_smmu_master_install_s2crs+0x78/0xa4
+ sp : ffff80008039b570
+ x29: ffff80008039b570 x28: 0000000000000000 x27: ffffaddd62f1ab78
+ x26: ffff00080a4ff280 x25: 0000000000000018 x24: ffff00080b896480
+ x23: ffff00080ba9b7a0 x22: ffff00080bb05160 x21: 0000000000000000
+ x20: 0000000000000000 x19: 0000000000000001 x18: 00000000ffffffff
+ x17: 0000000000000000 x16: 0000000000000000 x15: ffff80008039b1d0
+ x14: ffff80010039b37d x13: 00746c7561662d74 x12: 0000000000000000
+ x11: ffff00080b7fbd98 x10: ffffffffffffffc0 x9 : ffffffffffffffff
+ x8 : 0000000000000228 x7 : 0000000000000e87 x6 : 0000000000000000
+ x5 : 0000000000000000 x4 : ffff00080a4ff280 x3 : 0000000000000000
+ x2 : ffff800082a40c04 x1 : 0000000000000000 x0 : ffff800082a40000
+ Call trace:
+ arm_smmu_write_s2cr+0x9c/0xbc (P)
+ arm_smmu_master_install_s2crs+0x78/0xa4
+ arm_smmu_attach_dev+0xb0/0x1d8
+ __iommu_device_set_domain+0x84/0x11c
+ __iommu_group_set_domain_internal+0x60/0x120
+ __iommu_attach_group+0x88/0x9c
+ iommu_attach_device+0x6c/0xa0
+ msm_iommu_new.part.0+0x84/0xe4 [msm]
+ msm_iommu_gpu_new+0x3c/0x104 [msm]
+ adreno_iommu_create_vm+0x24/0xc8 [msm]
+ a6xx_create_vm+0x48/0x78 [msm]
+ msm_gpu_init+0x2d8/0x508 [msm]
+ adreno_gpu_init+0x208/0x324 [msm]
+ a6xx_gpu_init+0x604/0x8cc [msm]
+ adreno_bind+0xb4/0x124 [msm]
+ component_bind_all+0x114/0x23c
+ msm_drm_init+0x1b0/0x1ec [msm]
+ msm_drm_bind+0x30/0x3c [msm]
+ try_to_bring_up_aggregate_device+0x164/0x1d0
+ __component_add+0xa4/0x16c
+ component_add+0x14/0x20
+ msm_dp_display_probe_tail+0x4c/0xac [msm]
+ msm_dp_auxbus_done_probe+0x14/0x20 [msm]
+ dp_aux_ep_probe+0x4c/0xf4 [drm_dp_aux_bus]
+ really_probe+0xbc/0x29c
+ __driver_probe_device+0x78/0x12c
+ driver_probe_device+0x3c/0x15c
+ __device_attach_driver+0xb8/0x134
+ bus_for_each_drv+0x88/0xe8
+ __device_attach+0xa0/0x190
+ device_initial_probe+0x50/0x54
+ bus_probe_device+0x38/0xa4
+ deferred_probe_work_func+0x88/0xc0
+ process_one_work+0x148/0x28c
+ worker_thread+0x2cc/0x3d4
+ kthread+0x12c/0x204
+ ret_from_fork+0x10/0x20
+ ---[ end trace 0000000000000000 ]---
+
+Fixes: 1aa0b4e36436 ("arm64: dts: qcom: x1p42100: Add GPU support")
+Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Link: https://lore.kernel.org/r/20260410-purwa-gpu-dt-fix-v1-1-4637892156cf@oss.qualcomm.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/purwa.dtsi | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/qcom/purwa.dtsi b/arch/arm64/boot/dts/qcom/purwa.dtsi
+index 2cecd2dd0de8c..a02b39f98f0b2 100644
+--- a/arch/arm64/boot/dts/qcom/purwa.dtsi
++++ b/arch/arm64/boot/dts/qcom/purwa.dtsi
+@@ -33,6 +33,8 @@ &gmu {
+ &gpu {
+ compatible = "qcom,adreno-43030c00", "qcom,adreno";
+
++ iommus = <&adreno_smmu 0 0x0>;
++
+ nvmem-cells = <&gpu_speed_bin>;
+ nvmem-cell-names = "speed_bin";
+
+--
+2.53.0
+
--- /dev/null
+From 807dad9bdf0b161d92887feb27f705ed28503ec2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 23 Sep 2025 14:01:55 +0300
+Subject: arm64: dts: qcom: rename x1e80100 to hamoa
+
+From: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+
+[ Upstream commit 8c0b058ab5983a4be6690a76be9b0294853e8e55 ]
+
+The X1E80100 and several other similar names (X1E78100, X1E001DE) all
+belong to the platform now known as 'hamoa'. Follow the example of
+'lemans' and rename the x1e80100.dtsi to hamoa.dtsi and
+x1e80100-pmics.dtsi to hamoa-pmics.dtsi.
+
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Link: https://lore.kernel.org/r/20250923-rename-dts-v1-2-21888b68c781@oss.qualcomm.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Stable-dep-of: 4cd774c1feb3 ("arm64: dts: qcom: purwa: Fix GPU IOMMU property")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi | 4 ++--
+ .../boot/dts/qcom/{x1e80100-pmics.dtsi => hamoa-pmics.dtsi} | 0
+ arch/arm64/boot/dts/qcom/{x1e80100.dtsi => hamoa.dtsi} | 0
+ arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi | 2 +-
+ arch/arm64/boot/dts/qcom/x1-crd.dtsi | 2 +-
+ arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi | 2 +-
+ arch/arm64/boot/dts/qcom/x1e001de-devkit.dts | 4 ++--
+ arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi | 4 ++--
+ arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts | 4 ++--
+ arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts | 2 +-
+ arch/arm64/boot/dts/qcom/x1e80100-crd.dts | 2 +-
+ .../boot/dts/qcom/x1e80100-dell-inspiron-14-plus-7441.dts | 2 +-
+ arch/arm64/boot/dts/qcom/x1e80100-dell-latitude-7455.dts | 2 +-
+ arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts | 4 ++--
+ arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts | 4 ++--
+ arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts | 4 ++--
+ arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi | 4 ++--
+ arch/arm64/boot/dts/qcom/x1e80100-qcp.dts | 4 ++--
+ arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts | 2 +-
+ arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts | 2 +-
+ arch/arm64/boot/dts/qcom/x1p42100.dtsi | 4 ++--
+ 21 files changed, 29 insertions(+), 29 deletions(-)
+ rename arch/arm64/boot/dts/qcom/{x1e80100-pmics.dtsi => hamoa-pmics.dtsi} (100%)
+ rename arch/arm64/boot/dts/qcom/{x1e80100.dtsi => hamoa.dtsi} (100%)
+
+diff --git a/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi b/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi
+index 1aead50b8920b..4de7c0abb25a1 100644
+--- a/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi
++++ b/arch/arm64/boot/dts/qcom/hamoa-iot-som.dtsi
+@@ -3,8 +3,8 @@
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+-#include "x1e80100.dtsi"
+-#include "x1e80100-pmics.dtsi"
++#include "hamoa.dtsi"
++#include "hamoa-pmics.dtsi"
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+diff --git a/arch/arm64/boot/dts/qcom/x1e80100-pmics.dtsi b/arch/arm64/boot/dts/qcom/hamoa-pmics.dtsi
+similarity index 100%
+rename from arch/arm64/boot/dts/qcom/x1e80100-pmics.dtsi
+rename to arch/arm64/boot/dts/qcom/hamoa-pmics.dtsi
+diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi
+similarity index 100%
+rename from arch/arm64/boot/dts/qcom/x1e80100.dtsi
+rename to arch/arm64/boot/dts/qcom/hamoa.dtsi
+diff --git a/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi b/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi
+index ee3c8c5e2c50c..69eccad1a09c2 100644
+--- a/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi
++++ b/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi
+@@ -11,7 +11,7 @@
+ #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+ #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+-#include "x1e80100-pmics.dtsi"
++#include "hamoa-pmics.dtsi"
+
+ / {
+ model = "ASUS Zenbook A14";
+diff --git a/arch/arm64/boot/dts/qcom/x1-crd.dtsi b/arch/arm64/boot/dts/qcom/x1-crd.dtsi
+index 3c9455fede5c0..5e324f35547a4 100644
+--- a/arch/arm64/boot/dts/qcom/x1-crd.dtsi
++++ b/arch/arm64/boot/dts/qcom/x1-crd.dtsi
+@@ -9,7 +9,7 @@
+ #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+ #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+-#include "x1e80100-pmics.dtsi"
++#include "hamoa-pmics.dtsi"
+
+ / {
+ model = "Qualcomm Technologies, Inc. X1E80100 CRD";
+diff --git a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi
+index 5b5a10a31a253..aee3fafbe7fcc 100644
+--- a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi
++++ b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi
+@@ -12,7 +12,7 @@
+ #include <dt-bindings/leds/common.h>
+ #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+-#include "x1e80100-pmics.dtsi"
++#include "hamoa-pmics.dtsi"
+
+ / {
+ chassis-type = "laptop";
+diff --git a/arch/arm64/boot/dts/qcom/x1e001de-devkit.dts b/arch/arm64/boot/dts/qcom/x1e001de-devkit.dts
+index bfc649d4b643c..701f35af7d5cd 100644
+--- a/arch/arm64/boot/dts/qcom/x1e001de-devkit.dts
++++ b/arch/arm64/boot/dts/qcom/x1e001de-devkit.dts
+@@ -8,8 +8,8 @@
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+-#include "x1e80100.dtsi"
+-#include "x1e80100-pmics.dtsi"
++#include "hamoa.dtsi"
++#include "hamoa-pmics.dtsi"
+
+ / {
+ model = "Qualcomm Technologies, Inc. X1E001DE Snapdragon Devkit for Windows";
+diff --git a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi
+index 654cbce9d6ecb..169726984d3b0 100644
+--- a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi
++++ b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi
+@@ -12,8 +12,8 @@
+ #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+ #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+-#include "x1e80100.dtsi"
+-#include "x1e80100-pmics.dtsi"
++#include "hamoa.dtsi"
++#include "hamoa-pmics.dtsi"
+
+ / {
+ model = "Lenovo ThinkPad T14s Gen 6";
+diff --git a/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts b/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts
+index 0113d856b3ad4..f2960953e608f 100644
+--- a/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts
++++ b/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts
+@@ -11,8 +11,8 @@
+ #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+ #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+
+-#include "x1e80100.dtsi"
+-#include "x1e80100-pmics.dtsi"
++#include "hamoa.dtsi"
++#include "hamoa-pmics.dtsi"
+
+ / {
+ model = "ASUS Vivobook S 15";
+diff --git a/arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts b/arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts
+index 0d0bcc50207d7..c3cd04c9703d3 100644
+--- a/arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts
++++ b/arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts
+@@ -6,7 +6,7 @@
+
+ /dts-v1/;
+
+-#include "x1e80100.dtsi"
++#include "hamoa.dtsi"
+ #include "x1-asus-zenbook-a14.dtsi"
+
+ / {
+diff --git a/arch/arm64/boot/dts/qcom/x1e80100-crd.dts b/arch/arm64/boot/dts/qcom/x1e80100-crd.dts
+index dfc378e1a056a..429deffcf3e9d 100644
+--- a/arch/arm64/boot/dts/qcom/x1e80100-crd.dts
++++ b/arch/arm64/boot/dts/qcom/x1e80100-crd.dts
+@@ -5,7 +5,7 @@
+
+ /dts-v1/;
+
+-#include "x1e80100.dtsi"
++#include "hamoa.dtsi"
+ #include "x1-crd.dtsi"
+
+ / {
+diff --git a/arch/arm64/boot/dts/qcom/x1e80100-dell-inspiron-14-plus-7441.dts b/arch/arm64/boot/dts/qcom/x1e80100-dell-inspiron-14-plus-7441.dts
+index cf2a7c2628881..75e10d97c3867 100644
+--- a/arch/arm64/boot/dts/qcom/x1e80100-dell-inspiron-14-plus-7441.dts
++++ b/arch/arm64/boot/dts/qcom/x1e80100-dell-inspiron-14-plus-7441.dts
+@@ -4,7 +4,7 @@
+ */
+ /dts-v1/;
+
+-#include "x1e80100.dtsi"
++#include "hamoa.dtsi"
+ #include "x1-dell-thena.dtsi"
+
+ / {
+diff --git a/arch/arm64/boot/dts/qcom/x1e80100-dell-latitude-7455.dts b/arch/arm64/boot/dts/qcom/x1e80100-dell-latitude-7455.dts
+index 32ad9679550ef..a8ff7ef258a13 100644
+--- a/arch/arm64/boot/dts/qcom/x1e80100-dell-latitude-7455.dts
++++ b/arch/arm64/boot/dts/qcom/x1e80100-dell-latitude-7455.dts
+@@ -4,7 +4,7 @@
+ */
+ /dts-v1/;
+
+-#include "x1e80100.dtsi"
++#include "hamoa.dtsi"
+ #include "x1-dell-thena.dtsi"
+
+ / {
+diff --git a/arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts b/arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts
+index 58f8caaa72580..c1f49cba61fc4 100644
+--- a/arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts
++++ b/arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts
+@@ -12,8 +12,8 @@
+ #include <dt-bindings/leds/common.h>
+ #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+-#include "x1e80100.dtsi"
+-#include "x1e80100-pmics.dtsi"
++#include "hamoa.dtsi"
++#include "hamoa-pmics.dtsi"
+
+ / {
+ model = "Dell XPS 13 9345";
+diff --git a/arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts b/arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts
+index e5a839d458402..b79e59e1c413a 100644
+--- a/arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts
++++ b/arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts
+@@ -6,8 +6,8 @@
+
+ /dts-v1/;
+
+-#include "x1e80100.dtsi"
+-#include "x1e80100-pmics.dtsi"
++#include "hamoa.dtsi"
++#include "hamoa-pmics.dtsi"
+ #include "x1-hp-omnibook-x14.dtsi"
+
+ / {
+diff --git a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts
+index e0642fe8343f6..56e4d13cca111 100644
+--- a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts
++++ b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts
+@@ -9,8 +9,8 @@
+ #include <dt-bindings/input/gpio-keys.h>
+ #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+-#include "x1e80100.dtsi"
+-#include "x1e80100-pmics.dtsi"
++#include "hamoa.dtsi"
++#include "hamoa-pmics.dtsi"
+
+ / {
+ model = "Lenovo Yoga Slim 7x";
+diff --git a/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi b/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi
+index ed468b93ba50e..3b319f65dde1e 100644
+--- a/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi
++++ b/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi
+@@ -9,8 +9,8 @@
+ #include <dt-bindings/leds/common.h>
+ #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+-#include "x1e80100.dtsi"
+-#include "x1e80100-pmics.dtsi"
++#include "hamoa.dtsi"
++#include "hamoa-pmics.dtsi"
+
+ / {
+ aliases {
+diff --git a/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts
+index 4a9b6d791e7f4..5a121fc449401 100644
+--- a/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts
++++ b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts
+@@ -8,8 +8,8 @@
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+-#include "x1e80100.dtsi"
+-#include "x1e80100-pmics.dtsi"
++#include "hamoa.dtsi"
++#include "hamoa-pmics.dtsi"
+
+ / {
+ model = "Qualcomm Technologies, Inc. X1E80100 QCP";
+diff --git a/arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts b/arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts
+index 6696cab2de3ec..47ab0c5b30341 100644
+--- a/arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts
++++ b/arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts
+@@ -3,7 +3,7 @@
+ /dts-v1/;
+
+ #include "x1p42100.dtsi"
+-#include "x1e80100-pmics.dtsi"
++#include "hamoa-pmics.dtsi"
+ #include "x1-hp-omnibook-x14.dtsi"
+ /delete-node/ &pmc8380_6;
+ /delete-node/ &pmc8380_6_thermal;
+diff --git a/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts b/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts
+index 1ac46cdc43861..f7d372d2e9612 100644
+--- a/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts
++++ b/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts
+@@ -14,7 +14,7 @@
+ #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+ #include "x1p42100.dtsi"
+-#include "x1e80100-pmics.dtsi"
++#include "hamoa-pmics.dtsi"
+
+ /delete-node/ &pmc8380_6;
+ /delete-node/ &pmc8380_6_thermal;
+diff --git a/arch/arm64/boot/dts/qcom/x1p42100.dtsi b/arch/arm64/boot/dts/qcom/x1p42100.dtsi
+index 10d26958d3c66..2cecd2dd0de8c 100644
+--- a/arch/arm64/boot/dts/qcom/x1p42100.dtsi
++++ b/arch/arm64/boot/dts/qcom/x1p42100.dtsi
+@@ -3,8 +3,8 @@
+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+-/* X1P42100 is heavily based on X1E80100, with some meaningful differences */
+-#include "x1e80100.dtsi"
++/* X1P42100 is heavily based on hamoa, with some meaningful differences */
++#include "hamoa.dtsi"
+
+ /delete-node/ &bwmon_cluster0;
+ /delete-node/ &cluster_pd2;
+--
+2.53.0
+
--- /dev/null
+From 161ad2851d1c0a69ea962ce11d1d4e4eec2544fc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Oct 2025 20:20:15 +0200
+Subject: arm64: dts: qcom: rename x1p42100 to purwa
+
+From: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+
+[ Upstream commit ef659a5bd91bed7fae2c2a150f8ecca06599ac03 ]
+
+Follow the example of other platforms and rename X1P42100 to purwa.dtsi.
+
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Link: https://lore.kernel.org/r/20251030-rename-dts-2-v1-3-80c0b81c4d77@oss.qualcomm.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Stable-dep-of: 4cd774c1feb3 ("arm64: dts: qcom: purwa: Fix GPU IOMMU property")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/{x1p42100.dtsi => purwa.dtsi} | 0
+ arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dtsi | 2 +-
+ arch/arm64/boot/dts/qcom/x1p42100-crd.dts | 2 +-
+ arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts | 2 +-
+ arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts | 2 +-
+ 5 files changed, 4 insertions(+), 4 deletions(-)
+ rename arch/arm64/boot/dts/qcom/{x1p42100.dtsi => purwa.dtsi} (100%)
+
+diff --git a/arch/arm64/boot/dts/qcom/x1p42100.dtsi b/arch/arm64/boot/dts/qcom/purwa.dtsi
+similarity index 100%
+rename from arch/arm64/boot/dts/qcom/x1p42100.dtsi
+rename to arch/arm64/boot/dts/qcom/purwa.dtsi
+diff --git a/arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dtsi b/arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dtsi
+index 7ccb2076bab66..22470a97e1e39 100644
+--- a/arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dtsi
++++ b/arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dtsi
+@@ -6,7 +6,7 @@
+
+ /dts-v1/;
+
+-#include "x1p42100.dtsi"
++#include "purwa.dtsi"
+ #include "x1-asus-zenbook-a14.dtsi"
+
+ /delete-node/ &pmc8380_6;
+diff --git a/arch/arm64/boot/dts/qcom/x1p42100-crd.dts b/arch/arm64/boot/dts/qcom/x1p42100-crd.dts
+index cf999c2cf8d4e..7ed4116b95904 100644
+--- a/arch/arm64/boot/dts/qcom/x1p42100-crd.dts
++++ b/arch/arm64/boot/dts/qcom/x1p42100-crd.dts
+@@ -5,7 +5,7 @@
+
+ /dts-v1/;
+
+-#include "x1p42100.dtsi"
++#include "purwa.dtsi"
+ #include "x1-crd.dtsi"
+
+ /delete-node/ &pmc8380_6;
+diff --git a/arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts b/arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts
+index 47ab0c5b30341..0f338e457abda 100644
+--- a/arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts
++++ b/arch/arm64/boot/dts/qcom/x1p42100-hp-omnibook-x14.dts
+@@ -2,7 +2,7 @@
+
+ /dts-v1/;
+
+-#include "x1p42100.dtsi"
++#include "purwa.dtsi"
+ #include "hamoa-pmics.dtsi"
+ #include "x1-hp-omnibook-x14.dtsi"
+ /delete-node/ &pmc8380_6;
+diff --git a/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts b/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts
+index f7d372d2e9612..3186e79e862de 100644
+--- a/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts
++++ b/arch/arm64/boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts
+@@ -13,7 +13,7 @@
+ #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+ #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+-#include "x1p42100.dtsi"
++#include "purwa.dtsi"
+ #include "hamoa-pmics.dtsi"
+
+ /delete-node/ &pmc8380_6;
+--
+2.53.0
+
--- /dev/null
+From 15d4f31b0ddff9eb4816a2093625418b4558247b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 27 Sep 2025 15:21:36 +0200
+Subject: arm64: dts: qcom: Rework X1-based Asus Zenbook A14's displays
+
+From: Aleksandrs Vinarskis <alex@vinarskis.com>
+
+[ Upstream commit 462b39931cab3415ffc47863a58372399e600f4f ]
+
+The laptop comes in two variants:
+
+* UX3407RA, higher end, FHD+ OLED or WOXGA+ OLED panels
+* UX3407QA, lower end, FHD+ OLED or FHD+ LCD panels
+
+Even though all three panels work with "edp-panel", unfortunately the
+brightness adjustmenet of LCD panel is PWM based, requiring a dedicated
+device-tree. Convert "x1p42100-asus-zenbook-a14.dts" into ".dtsi" to
+allow for this split, introduce new LCD variant. Leave current variant
+without postfix and with the unchanged model name, as some distros
+(eg. Ubuntu) rely on this for automatic device-tree detection during
+kernel installation/upgrade.
+
+As dedicated device-tree is required, update compatibles of OLED
+variants to correct ones. Keep "edp-panel" as fallback, since it is
+enough to make the panels work.
+
+While at it moving .dts, .dtsi around, drop 'model' from the top level
+x1-asus-zenbook-a14.dtsi as well.
+
+Co-developed-by: Jens Glathe <jens.glathe@oldschoolsolutions.biz>
+Signed-off-by: Jens Glathe <jens.glathe@oldschoolsolutions.biz>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Signed-off-by: Aleksandrs Vinarskis <alex@vinarskis.com>
+Link: https://lore.kernel.org/r/20250927-zenbook-improvements-v3-2-d46c7368dc70@vinarskis.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Stable-dep-of: 4cd774c1feb3 ("arm64: dts: qcom: purwa: Fix GPU IOMMU property")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/Makefile | 2 +
+ .../boot/dts/qcom/x1-asus-zenbook-a14.dtsi | 7 +-
+ .../dts/qcom/x1e80100-asus-zenbook-a14.dts | 8 +
+ .../qcom/x1p42100-asus-zenbook-a14-lcd.dts | 62 ++++++++
+ .../dts/qcom/x1p42100-asus-zenbook-a14.dts | 133 +----------------
+ .../dts/qcom/x1p42100-asus-zenbook-a14.dtsi | 138 ++++++++++++++++++
+ 6 files changed, 218 insertions(+), 132 deletions(-)
+ create mode 100644 arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14-lcd.dts
+ create mode 100644 arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dtsi
+
+diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
+index 296688f7cb265..dffdb219f33dc 100644
+--- a/arch/arm64/boot/dts/qcom/Makefile
++++ b/arch/arm64/boot/dts/qcom/Makefile
+@@ -344,6 +344,8 @@ x1e80100-qcp-el2-dtbs := x1e80100-qcp.dtb x1-el2.dtbo
+ dtb-$(CONFIG_ARCH_QCOM) += x1e80100-qcp.dtb x1e80100-qcp-el2.dtb
+ x1p42100-asus-zenbook-a14-el2-dtbs := x1p42100-asus-zenbook-a14.dtb x1-el2.dtbo
+ dtb-$(CONFIG_ARCH_QCOM) += x1p42100-asus-zenbook-a14.dtb x1p42100-asus-zenbook-a14-el2.dtb
++x1p42100-asus-zenbook-a14-lcd-el2-dtbs := x1p42100-asus-zenbook-a14-lcd.dtb x1-el2.dtbo
++dtb-$(CONFIG_ARCH_QCOM) += x1p42100-asus-zenbook-a14-lcd.dtb x1p42100-asus-zenbook-a14-lcd-el2.dtb
+ x1p42100-crd-el2-dtbs := x1p42100-crd.dtb x1-el2.dtbo
+ dtb-$(CONFIG_ARCH_QCOM) += x1p42100-crd.dtb x1p42100-crd-el2.dtb
+ x1p42100-hp-omnibook-x14-el2-dtbs := x1p42100-hp-omnibook-x14.dtb x1-el2.dtbo
+diff --git a/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi b/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi
+index 69eccad1a09c2..8e5c5575a5320 100644
+--- a/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi
++++ b/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi
+@@ -14,7 +14,6 @@
+ #include "hamoa-pmics.dtsi"
+
+ / {
+- model = "ASUS Zenbook A14";
+ chassis-type = "laptop";
+
+ aliases {
+@@ -1005,14 +1004,10 @@ &mdss_dp3 {
+ status = "okay";
+
+ aux-bus {
+- panel {
++ panel: panel {
+ compatible = "edp-panel";
+- enable-gpios = <&pmc8380_3_gpios 4 GPIO_ACTIVE_HIGH>;
+ power-supply = <&vreg_edp_3p3>;
+
+- pinctrl-0 = <&edp_bl_en>;
+- pinctrl-names = "default";
+-
+ port {
+ edp_panel_in: endpoint {
+ remote-endpoint = <&mdss_dp3_out>;
+diff --git a/arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts b/arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts
+index c3cd04c9703d3..49b12a0a7cb1e 100644
+--- a/arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts
++++ b/arch/arm64/boot/dts/qcom/x1e80100-asus-zenbook-a14.dts
+@@ -22,6 +22,14 @@ &gpu_zap_shader {
+ firmware-name = "qcom/x1e80100/ASUSTeK/zenbook-a14/qcdxkmsuc8380.mbn";
+ };
+
++&panel {
++ compatible = "samsung,atna40cu11", "samsung,atna33xc20";
++ enable-gpios = <&pmc8380_3_gpios 4 GPIO_ACTIVE_HIGH>;
++
++ pinctrl-0 = <&edp_bl_en>;
++ pinctrl-names = "default";
++};
++
+ &remoteproc_adsp {
+ firmware-name = "qcom/x1e80100/ASUSTeK/zenbook-a14/qcadsp8380.mbn",
+ "qcom/x1e80100/ASUSTeK/zenbook-a14/adsp_dtbs.elf";
+diff --git a/arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14-lcd.dts b/arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14-lcd.dts
+new file mode 100644
+index 0000000000000..be756069131d7
+--- /dev/null
++++ b/arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14-lcd.dts
+@@ -0,0 +1,62 @@
++// SPDX-License-Identifier: BSD-3-Clause
++/*
++ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2025 Aleksandrs Vinarskis <alex@vinarskis.com>
++ */
++
++/dts-v1/;
++
++#include "x1p42100-asus-zenbook-a14.dtsi"
++
++/ {
++ model = "ASUS Zenbook A14 (UX3407QA, LCD)";
++ compatible = "asus,zenbook-a14-ux3407qa-lcd", "asus,zenbook-a14-ux3407qa", "qcom,x1p42100";
++
++ backlight: backlight {
++ compatible = "pwm-backlight";
++ pwms = <&pmk8550_pwm 0 416667>;
++ enable-gpios = <&pmc8380_3_gpios 4 GPIO_ACTIVE_HIGH>;
++ power-supply = <&vreg_edp_bl>;
++
++ pinctrl-0 = <&edp_bl_en>, <&edp_bl_pwm>;
++ pinctrl-names = "default";
++ };
++
++ vreg_edp_bl: regulator-edp-bl {
++ compatible = "regulator-fixed";
++
++ regulator-name = "VBL9";
++ regulator-min-microvolt = <3600000>;
++ regulator-max-microvolt = <3600000>;
++
++ gpio = <&pmc8380_3_gpios 10 GPIO_ACTIVE_HIGH>;
++ enable-active-high;
++
++ pinctrl-0 = <&edp_bl_reg_en>;
++ pinctrl-names = "default";
++
++ regulator-boot-on;
++ };
++};
++
++&panel {
++ backlight = <&backlight>;
++};
++
++&pmc8380_3_gpios {
++ edp_bl_reg_en: edp-bl-reg-en-state {
++ pins = "gpio10";
++ function = "normal";
++ };
++};
++
++&pmk8550_gpios {
++ edp_bl_pwm: edp-bl-pwm-state {
++ pins = "gpio5";
++ function = "func3";
++ };
++};
++
++&pmk8550_pwm {
++ status = "okay";
++};
+diff --git a/arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dts b/arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dts
+index bd75ff898601a..68cd318d69073 100644
+--- a/arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dts
++++ b/arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dts
+@@ -6,136 +6,17 @@
+
+ /dts-v1/;
+
+-#include "x1p42100.dtsi"
+-#include "x1-asus-zenbook-a14.dtsi"
+-
+-/delete-node/ &pmc8380_6;
+-/delete-node/ &pmc8380_6_thermal;
++#include "x1p42100-asus-zenbook-a14.dtsi"
+
+ / {
+ model = "ASUS Zenbook A14 (UX3407QA)";
+- compatible = "asus,zenbook-a14-ux3407qa", "qcom,x1p42100";
+-
+- wcn6855-pmu {
+- compatible = "qcom,wcn6855-pmu";
+-
+- vddaon-supply = <&vreg_wcn_0p95>;
+- vddio-supply = <&vreg_wcn_1p9>;
+- vddpcie1p3-supply = <&vreg_wcn_1p9>;
+- vddpcie1p9-supply = <&vreg_wcn_1p9>;
+- vddpmu-supply = <&vreg_wcn_0p95>;
+- vddpmucx-supply = <&vreg_wcn_0p95>;
+- vddpmumx-supply = <&vreg_wcn_0p95>;
+- vddrfa0p95-supply = <&vreg_wcn_0p95>;
+- vddrfa1p3-supply = <&vreg_wcn_1p9>;
+- vddrfa1p9-supply = <&vreg_wcn_1p9>;
+-
+- bt-enable-gpios = <&tlmm 116 GPIO_ACTIVE_HIGH>;
+- wlan-enable-gpios = <&tlmm 117 GPIO_ACTIVE_HIGH>;
+-
+- pinctrl-0 = <&wcn_bt_en>, <&wcn_wlan_en>;
+- pinctrl-names = "default";
+-
+- regulators {
+- vreg_pmu_rfa_cmn_0p8: ldo0 {
+- regulator-name = "vreg_pmu_rfa_cmn_0p8";
+- };
+-
+- vreg_pmu_aon_0p8: ldo1 {
+- regulator-name = "vreg_pmu_aon_0p8";
+- };
+-
+- vreg_pmu_wlcx_0p8: ldo2 {
+- regulator-name = "vreg_pmu_wlcx_0p8";
+- };
+-
+- vreg_pmu_wlmx_0p8: ldo3 {
+- regulator-name = "vreg_pmu_wlmx_0p8";
+- };
+-
+- vreg_pmu_btcmx_0p8: ldo4 {
+- regulator-name = "vreg_pmu_btcmx_0p8";
+- };
+-
+- vreg_pmu_pcie_1p8: ldo5 {
+- regulator-name = "vreg_pmu_pcie_1p8";
+- };
+-
+- vreg_pmu_pcie_0p9: ldo6 {
+- regulator-name = "vreg_pmu_pcie_0p9";
+- };
+-
+- vreg_pmu_rfa_0p8: ldo7 {
+- regulator-name = "vreg_pmu_rfa_0p8";
+- };
+-
+- vreg_pmu_rfa_1p2: ldo8 {
+- regulator-name = "vreg_pmu_rfa_1p2";
+- };
+-
+- vreg_pmu_rfa_1p7: ldo9 {
+- regulator-name = "vreg_pmu_rfa_1p7";
+- };
+- };
+- };
++ compatible = "asus,zenbook-a14-ux3407qa-oled", "asus,zenbook-a14-ux3407qa", "qcom,x1p42100";
+ };
+
+-&gpu {
+- status = "okay";
+-};
+-
+-&gpu_zap_shader {
+- firmware-name = "qcom/x1p42100/ASUSTeK/zenbook-a14/qcdxkmsucpurwa.mbn";
+-};
+-
+-&pcie4_port0 {
+- wifi@0 {
+- compatible = "pci17cb,1103";
+- reg = <0x10000 0x0 0x0 0x0 0x0>;
+-
+- vddaon-supply = <&vreg_pmu_aon_0p8>;
+- vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>;
+- vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>;
+- vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>;
+- vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>;
+- vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>;
+- vddrfacmn-supply = <&vreg_pmu_rfa_cmn_0p8>;
+- vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+- vddwlmx-supply = <&vreg_pmu_wlmx_0p8>;
+-
+- qcom,calibration-variant = "UX3407Q";
+- };
+-};
+-
+-&remoteproc_adsp {
+- firmware-name = "qcom/x1p42100/ASUSTeK/zenbook-a14/qcadsp8380.mbn",
+- "qcom/x1p42100/ASUSTeK/zenbook-a14/adsp_dtbs.elf";
+-
+- status = "okay";
+-};
+-
+-&remoteproc_cdsp {
+- firmware-name = "qcom/x1p42100/ASUSTeK/zenbook-a14/qccdsp8380.mbn",
+- "qcom/x1p42100/ASUSTeK/zenbook-a14/cdsp_dtbs.elf";
+-
+- status = "okay";
+-};
+-
+-&uart14 {
+- status = "okay";
+-
+- bluetooth {
+- compatible = "qcom,wcn6855-bt";
+-
+- vddaon-supply = <&vreg_pmu_aon_0p8>;
+- vddbtcmx-supply = <&vreg_pmu_btcmx_0p8>;
+- vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>;
+- vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>;
+- vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>;
+- vddrfacmn-supply = <&vreg_pmu_rfa_cmn_0p8>;
+- vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+- vddwlmx-supply = <&vreg_pmu_wlmx_0p8>;
++&panel {
++ compatible = "samsung,atna40ct06", "samsung,atna33xc20";
++ enable-gpios = <&pmc8380_3_gpios 4 GPIO_ACTIVE_HIGH>;
+
+- max-speed = <3000000>;
+- };
++ pinctrl-0 = <&edp_bl_en>;
++ pinctrl-names = "default";
+ };
+diff --git a/arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dtsi b/arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dtsi
+new file mode 100644
+index 0000000000000..7ccb2076bab66
+--- /dev/null
++++ b/arch/arm64/boot/dts/qcom/x1p42100-asus-zenbook-a14.dtsi
+@@ -0,0 +1,138 @@
++// SPDX-License-Identifier: BSD-3-Clause
++/*
++ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2025 Aleksandrs Vinarskis <alex@vinarskis.com>
++ */
++
++/dts-v1/;
++
++#include "x1p42100.dtsi"
++#include "x1-asus-zenbook-a14.dtsi"
++
++/delete-node/ &pmc8380_6;
++/delete-node/ &pmc8380_6_thermal;
++
++/ {
++ wcn6855-pmu {
++ compatible = "qcom,wcn6855-pmu";
++
++ vddaon-supply = <&vreg_wcn_0p95>;
++ vddio-supply = <&vreg_wcn_1p9>;
++ vddpcie1p3-supply = <&vreg_wcn_1p9>;
++ vddpcie1p9-supply = <&vreg_wcn_1p9>;
++ vddpmu-supply = <&vreg_wcn_0p95>;
++ vddpmucx-supply = <&vreg_wcn_0p95>;
++ vddpmumx-supply = <&vreg_wcn_0p95>;
++ vddrfa0p95-supply = <&vreg_wcn_0p95>;
++ vddrfa1p3-supply = <&vreg_wcn_1p9>;
++ vddrfa1p9-supply = <&vreg_wcn_1p9>;
++
++ bt-enable-gpios = <&tlmm 116 GPIO_ACTIVE_HIGH>;
++ wlan-enable-gpios = <&tlmm 117 GPIO_ACTIVE_HIGH>;
++
++ pinctrl-0 = <&wcn_bt_en>, <&wcn_wlan_en>;
++ pinctrl-names = "default";
++
++ regulators {
++ vreg_pmu_rfa_cmn_0p8: ldo0 {
++ regulator-name = "vreg_pmu_rfa_cmn_0p8";
++ };
++
++ vreg_pmu_aon_0p8: ldo1 {
++ regulator-name = "vreg_pmu_aon_0p8";
++ };
++
++ vreg_pmu_wlcx_0p8: ldo2 {
++ regulator-name = "vreg_pmu_wlcx_0p8";
++ };
++
++ vreg_pmu_wlmx_0p8: ldo3 {
++ regulator-name = "vreg_pmu_wlmx_0p8";
++ };
++
++ vreg_pmu_btcmx_0p8: ldo4 {
++ regulator-name = "vreg_pmu_btcmx_0p8";
++ };
++
++ vreg_pmu_pcie_1p8: ldo5 {
++ regulator-name = "vreg_pmu_pcie_1p8";
++ };
++
++ vreg_pmu_pcie_0p9: ldo6 {
++ regulator-name = "vreg_pmu_pcie_0p9";
++ };
++
++ vreg_pmu_rfa_0p8: ldo7 {
++ regulator-name = "vreg_pmu_rfa_0p8";
++ };
++
++ vreg_pmu_rfa_1p2: ldo8 {
++ regulator-name = "vreg_pmu_rfa_1p2";
++ };
++
++ vreg_pmu_rfa_1p7: ldo9 {
++ regulator-name = "vreg_pmu_rfa_1p7";
++ };
++ };
++ };
++};
++
++&gpu {
++ status = "okay";
++};
++
++&gpu_zap_shader {
++ firmware-name = "qcom/x1p42100/ASUSTeK/zenbook-a14/qcdxkmsucpurwa.mbn";
++};
++
++&pcie4_port0 {
++ wifi@0 {
++ compatible = "pci17cb,1103";
++ reg = <0x10000 0x0 0x0 0x0 0x0>;
++
++ vddaon-supply = <&vreg_pmu_aon_0p8>;
++ vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>;
++ vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>;
++ vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>;
++ vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>;
++ vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>;
++ vddrfacmn-supply = <&vreg_pmu_rfa_cmn_0p8>;
++ vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
++ vddwlmx-supply = <&vreg_pmu_wlmx_0p8>;
++
++ qcom,calibration-variant = "UX3407Q";
++ };
++};
++
++&remoteproc_adsp {
++ firmware-name = "qcom/x1p42100/ASUSTeK/zenbook-a14/qcadsp8380.mbn",
++ "qcom/x1p42100/ASUSTeK/zenbook-a14/adsp_dtbs.elf";
++
++ status = "okay";
++};
++
++&remoteproc_cdsp {
++ firmware-name = "qcom/x1p42100/ASUSTeK/zenbook-a14/qccdsp8380.mbn",
++ "qcom/x1p42100/ASUSTeK/zenbook-a14/cdsp_dtbs.elf";
++
++ status = "okay";
++};
++
++&uart14 {
++ status = "okay";
++
++ bluetooth {
++ compatible = "qcom,wcn6855-bt";
++
++ vddaon-supply = <&vreg_pmu_aon_0p8>;
++ vddbtcmx-supply = <&vreg_pmu_btcmx_0p8>;
++ vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>;
++ vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>;
++ vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>;
++ vddrfacmn-supply = <&vreg_pmu_rfa_cmn_0p8>;
++ vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
++ vddwlmx-supply = <&vreg_pmu_wlmx_0p8>;
++
++ max-speed = <3000000>;
++ };
++};
+--
+2.53.0
+
--- /dev/null
+From e305238465c6ecc7471b7f9a7eff6f0b2aa0f313 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Apr 2026 01:27:12 +0300
+Subject: arm64: dts: qcom: sdm850-lenovo-yoga-c630: lower PSCI cluster idle
+
+From: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+
+[ Upstream commit 07db10de262f4150e24fd631a7a6c428f7bf80c9 ]
+
+With the default PSCI suspend value for cluster idle state Lenovo Yoga
+C630 isn't stable enough. For example it might reset if display device
+isn't probed early enough. Drop the bit 0x4000 from the PSCI suspend
+value to make C630 work in stable way. The bit was found by
+expertimenting with the cluster idle PSCI value. Most likely it results
+in the less deep sleep and more energy beign spent in the suspend state,
+but it's better than the non-stable system behaviour.
+
+Fixes: a1ade6cac5a2 ("arm64: dts: qcom: sdm845: Switch PSCI cpu idle states from PC to OSI")
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Reviewed-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
+Link: https://lore.kernel.org/r/20260429-c630-fix-idle-v2-1-ac867dad6f21@oss.qualcomm.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
+index 90efbb7e3799b..bead957cf83b4 100644
+--- a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
++++ b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
+@@ -347,6 +347,10 @@ &cdsp_pas {
+ status = "okay";
+ };
+
++&cluster_sleep_0 {
++ arm,psci-suspend-param = <0x41008244>;
++};
++
+ &gcc {
+ protected-clocks = <GCC_QSPI_CORE_CLK>,
+ <GCC_QSPI_CORE_CLK_SRC>,
+--
+2.53.0
+
--- /dev/null
+From d0ce29b412f31047d778be95b9f5c38b0367420f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 14:06:28 +0800
+Subject: ata: pata_sl82c105: fix bridge revision use-after-free
+
+From: Hongyan Xu <getshell@seu.edu.cn>
+
+[ Upstream commit 7700a31039cdc6715cb6cce7e7a664ee4e945f67 ]
+
+pci_get_slot() returns a referenced PCI device. Commit 44c10138fd4b
+("PCI: Change all drivers to use pci_device->revision") replaced a
+configuration-space read with direct access to the cached revision field,
+but left that access after pci_dev_put(). The bridge may therefore be freed
+before its revision is read.
+
+Read the revision before dropping the reference.
+
+Fixes: 44c10138fd4b ("PCI: Change all drivers to use pci_device->revision")
+Signed-off-by: Hongyan Xu <getshell@seu.edu.cn>
+Reviewed-by: Niklas Cassel <cassel@kernel.org>
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ata/pata_sl82c105.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
+index 2d24c6b3e9d9f..25bce3fe2a101 100644
+--- a/drivers/ata/pata_sl82c105.c
++++ b/drivers/ata/pata_sl82c105.c
+@@ -264,6 +264,7 @@ static struct ata_port_operations sl82c105_port_ops = {
+ static int sl82c105_bridge_revision(struct pci_dev *pdev)
+ {
+ struct pci_dev *bridge;
++ u8 revision;
+
+ /*
+ * The bridge should be part of the same device, but function 0.
+@@ -285,8 +286,9 @@ static int sl82c105_bridge_revision(struct pci_dev *pdev)
+ /*
+ * We need to find function 0's revision, not function 1
+ */
++ revision = bridge->revision;
+ pci_dev_put(bridge);
+- return bridge->revision;
++ return revision;
+ }
+
+ static void sl82c105_fixup(struct pci_dev *pdev)
+--
+2.53.0
+
--- /dev/null
+From 84dd0c16507dfba6d7c95eec452568121e7f6d25 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 15:10:22 +0530
+Subject: bnge: Fix resource leak in bnge_init_nic() error path
+
+From: Bhargava Marreddy <bhargava.marreddy@broadcom.com>
+
+[ Upstream commit bfec39ff1484b4e9f7d93bc4580fdb634bbc7d19 ]
+
+If bnge_init_chip() fails, bnge_init_nic() jumps to err_free_ring_grps
+and returns immediately, skipping cleanup for RX ring pair buffers.
+
+Remove the early return so execution falls through to
+err_free_rx_ring_pair_bufs to properly free resources on error.
+
+Fixes: 23df6aebf803 ("bng_en: Allocate stat contexts")
+Signed-off-by: Bhargava Marreddy <bhargava.marreddy@broadcom.com>
+Reviewed-by: Dharmender Garg <dharmender.garg@broadcom.com>
+Reviewed-by: Rajashekar Hudumula <rajashekar.hudumula@broadcom.com>
+Link: https://patch.msgid.link/20260805094022.15487-1-bhargava.marreddy@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnge/bnge_netdev.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
+index 832eeb960bd2d..02be751f3d8fc 100644
+--- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
++++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
+@@ -2154,8 +2154,6 @@ static int bnge_init_nic(struct bnge_net *bn)
+
+ err_free_ring_grps:
+ bnge_free_ring_grps(bn);
+- return rc;
+-
+ err_free_rx_ring_pair_bufs:
+ bnge_free_rx_ring_pair_bufs(bn);
+ return rc;
+--
+2.53.0
+
--- /dev/null
+From 694e49b1f0eabf7010d99842845d02cb75d65d3f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 1 Aug 2026 03:09:20 -0700
+Subject: bnge: use int for bnge_fix_rings_count() return value
+
+From: Alok Tiwari <alok.a.tiwari@oracle.com>
+
+[ Upstream commit 2cbd8a4e5e09aa232a1f8d56ce3d070b18ab2b10 ]
+
+bnge_fix_rings_count() returns 0 on success or a negative errno on failure
+However, bnge_adjust_rings() stores its return value in a u16 variable,
+causing negative error codes such as -ENOMEM to be converted to a large
+positive value.
+
+Use an int for the return code variable so that error values are
+preserved and propagated correctly.
+
+Fixes: 627c67f038d2 ("bng_en: Add resource management support")
+Signed-off-by: Alok Tiwari <alok.a.tiwari@oracle.com>
+Reviewed-by: Bhargava Marreddy <bhargava.marreddy@broadcom.com>
+Link: https://patch.msgid.link/20260801100923.1498570-1-alok.a.tiwari@oracle.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnge/bnge_resc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_resc.c b/drivers/net/ethernet/broadcom/bnge/bnge_resc.c
+index 62ebe03a0dcf3..39cc392bd8c4b 100644
+--- a/drivers/net/ethernet/broadcom/bnge/bnge_resc.c
++++ b/drivers/net/ethernet/broadcom/bnge/bnge_resc.c
+@@ -151,7 +151,8 @@ static int bnge_adjust_rings(struct bnge_dev *bd, u16 *rx,
+ u16 tx_chunks = bnge_num_tx_to_cp(bd, *tx);
+
+ if (tx_chunks != *tx) {
+- u16 tx_saved = tx_chunks, rc;
++ u16 tx_saved = tx_chunks;
++ int rc;
+
+ rc = bnge_fix_rings_count(rx, &tx_chunks, max_nq, sh);
+ if (rc)
+--
+2.53.0
+
--- /dev/null
+From ee3c78709260609d7601337ef841a8ebd8da23ef Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:01:31 -0700
+Subject: bnxt: fix memory leak in bnxt_queue_mem_alloc error cases
+
+From: Will Chen <will.chen.tty@gmail.com>
+
+[ Upstream commit d1000fd7995e51deec872d154e0a40d82f7a539f ]
+
+There is a small memory leak in bnxt_queue_mem_alloc:
+when bnxt_alloc_rx_agg_bmap() succeeds
+but bnxt_alloc_one_tpa_info() later fails,
+the rx_agg_bmap allocated by bnxt_alloc_rx_agg_bmap()
+is not freed in the fallthrough cleanup cases.
+
+Free the rx_agg_bmap in the err_free_rx_agg_ring case
+and initialize clone->rx_agg_bmap = NULL earlier in the function
+to allow for safe fallthrough.
+
+Fixes: bd649c5cc958 ("bnxt_en: handle tpa_info in queue API implementation")
+Signed-off-by: Will Chen <will.chen.tty@gmail.com>
+Reviewed-by: Joe Damato <joe@dama.to>
+Reviewed-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260729220132.1256924-1-will.chen.tty@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 52b356f4966ab..d90775c0ce0b5 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -16017,6 +16017,7 @@ static int bnxt_queue_mem_alloc(struct net_device *dev,
+ clone->rx_next_cons = 0;
+ clone->need_head_pool = false;
+ clone->rx_page_size = qcfg->rx_page_size;
++ clone->rx_agg_bmap = NULL;
+
+ rc = bnxt_alloc_rx_page_pool(bp, clone, rxr->page_pool->p.nid);
+ if (rc)
+@@ -16069,6 +16070,8 @@ static int bnxt_queue_mem_alloc(struct net_device *dev,
+ bnxt_free_one_tpa_info(bp, clone);
+ err_free_rx_agg_ring:
+ bnxt_free_ring(bp, &clone->rx_agg_ring_struct.ring_mem);
++ kfree(clone->rx_agg_bmap);
++ clone->rx_agg_bmap = NULL;
+ err_free_rx_ring:
+ bnxt_free_ring(bp, &clone->rx_ring_struct.ring_mem);
+ err_rxq_info_unreg:
+--
+2.53.0
+
--- /dev/null
+From 2a5bdd8f758b2323345ebbcafc622a8476a1ebc3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:34 -0700
+Subject: bnxt_en: Determine and store default RX ring in vnic structure
+
+From: Shravya KN <shravya.k-n@broadcom.com>
+
+[ Upstream commit 53f01cd594e223aabb538d5288e60111523c96f2 ]
+
+Each VNIC has a default RX ring. The purpose of the default RX ring
+is to provide a destination for any packets that cannot be parsed by
+the RSS logic. Up until now, the default RX ring is always Ring 0.
+
+We neglected to take care of this default RX ring when adding the
+queue restart feature. If ring 0 (default ring) is re-started, it
+may now have a new FW ring ID after freeing the old one and
+allocating a new one. The VNIC now may have a stale default ring
+and it may generate an internal exception. This exception may
+appear in dmesg:
+
+FW reported unknown error type 10
+
+The best way to resolve this issue is to use a more appropriate
+ring for the default ring instead of always ring 0. Ring 0 may not
+even be in the RSS table, especially on a new RSS context.
+
+This patch adds the logic to determine and store the proper default
+RX ring for a VNIC. For an RSS VNIC, the default ring is the lowest
+ring number in the RSS table. The next patch will add proper logic
+to update the VNIC if the default ring changes after queue restart.
+
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Shravya KN <shravya.k-n@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-3-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 0b137529a899 ("bnxt_en: Refresh VNIC default ring on queue restart if needed")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 33 +++++++++++++++--------
+ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
+ 2 files changed, 23 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index fba5b7f27ce7b..df5fd228d84ae 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -6593,25 +6593,36 @@ int bnxt_get_nr_rss_ctxs(struct bnxt *bp, int rx_rings)
+ static void bnxt_fill_hw_rss_tbl(struct bnxt *bp, struct bnxt_vnic_info *vnic)
+ {
+ bool no_rss = !(vnic->flags & BNXT_VNIC_RSS_FLAG);
+- u16 i, j;
++ u16 i, j, min_j = bp->rx_nr_rings - 1;
+
+ if (!vnic->rss_table)
+- return;
++ goto skip_rss_tbl;
+
+ /* Fill the RSS indirection table with ring group ids */
+ for (i = 0, j = 0; i < HW_HASH_INDEX_SIZE; i++) {
+ if (!no_rss)
+ j = bp->rss_indir_tbl[i];
++ min_j = min(j, min_j);
+ vnic->rss_table[i] = cpu_to_le16(vnic->fw_grp_ids[j]);
+ }
++
++skip_rss_tbl:
++ if (vnic->rss_table && !no_rss)
++ vnic->default_rx_ring = min_j;
++ else if (vnic->flags & BNXT_VNIC_RFS_FLAG)
++ vnic->default_rx_ring = vnic->vnic_id - 1;
++ else if ((vnic->vnic_id == 1) && BNXT_CHIP_TYPE_NITRO_A0(bp))
++ vnic->default_rx_ring = bp->rx_nr_rings - 1;
++ else
++ vnic->default_rx_ring = 0;
+ }
+
+ static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp,
+ struct bnxt_vnic_info *vnic)
+ {
++ u16 tbl_size, i, min_j = bp->rx_nr_rings - 1;
+ __le16 *ring_tbl = vnic->rss_table;
+ struct bnxt_rx_ring_info *rxr;
+- u16 tbl_size, i;
+
+ tbl_size = bnxt_get_rxfh_indir_size(bp->dev);
+
+@@ -6624,6 +6635,7 @@ static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp,
+ j = ethtool_rxfh_context_indir(vnic->rss_ctx)[i];
+ else
+ j = bp->rss_indir_tbl[i];
++ min_j = min(j, min_j);
+ rxr = &bp->rx_ring[j];
+
+ ring_id = rxr->rx_ring_struct.fw_ring_id;
+@@ -6631,6 +6643,7 @@ static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp,
+ ring_id = bnxt_cp_ring_for_rx(bp, rxr);
+ *ring_tbl++ = cpu_to_le16(ring_id);
+ }
++ vnic->default_rx_ring = min_j;
+ }
+
+ static void
+@@ -6827,8 +6840,9 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, struct bnxt_vnic_info *vnic)
+ return rc;
+
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
+- struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0];
++ struct bnxt_rx_ring_info *rxr;
+
++ rxr = &bp->rx_ring[vnic->default_rx_ring];
+ req->default_rx_ring_id =
+ cpu_to_le16(rxr->rx_ring_struct.fw_ring_id);
+ req->default_cmpl_ring_id =
+@@ -6861,13 +6875,7 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, struct bnxt_vnic_info *vnic)
+ req->cos_rule = cpu_to_le16(0xffff);
+ }
+
+- if (vnic->flags & BNXT_VNIC_RSS_FLAG)
+- ring = 0;
+- else if (vnic->flags & BNXT_VNIC_RFS_FLAG)
+- ring = vnic->vnic_id - 1;
+- else if ((vnic->vnic_id == 1) && BNXT_CHIP_TYPE_NITRO_A0(bp))
+- ring = bp->rx_nr_rings - 1;
+-
++ ring = vnic->default_rx_ring;
+ grp_idx = bp->rx_ring[ring].bnapi->index;
+ req->dflt_ring_grp = cpu_to_le16(bp->grp_info[grp_idx].fw_grp_id);
+ req->lb_rule = cpu_to_le16(0xffff);
+@@ -11027,6 +11035,9 @@ static int bnxt_setup_nitroa0_vnic(struct bnxt *bp)
+ return rc;
+ }
+
++ /* Setup the proper default RX ring */
++ bnxt_fill_hw_rss_tbl(bp, vnic);
++
+ rc = bnxt_hwrm_vnic_cfg(bp, vnic);
+ if (rc) {
+ netdev_err(bp->dev, "Cannot allocate special vnic for NS2 A0: %x\n",
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+index 3ca989da0eb02..9d9ad2be3239b 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+@@ -1318,6 +1318,7 @@ struct bnxt_vnic_info {
+ #define BNXT_VNIC_RSSCTX_FLAG 0x40
+ struct ethtool_rxfh_context *rss_ctx;
+ u32 vnic_id;
++ u16 default_rx_ring;
+ };
+
+ struct bnxt_rss_ctx {
+--
+2.53.0
+
--- /dev/null
+From aee1e001495da03a388d6b2cdfea5aa1f5007383 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:36 -0700
+Subject: bnxt_en: Disable EOP for TPA on all chips to prevent data corruption
+
+From: Michael Chan <michael.chan@broadcom.com>
+
+[ Upstream commit c3faf548a00f4c17100cc9204746975fa46a73b9 ]
+
+EOP (End of frame padding) on the AGG ring may cause overlapping of
+zero padding at the end of one segment with the next segment's data.
+If Relaxed Ordering (RO) is enabled, the zero padding may overwrite
+valid data in the next segment and corrupt the data. Older chips
+(P5 and older) do not automatically disable RO when EOP is enabled.
+On some ARM systems, data corruption was reported on 57508 (P5)
+chips with RO enabled.
+
+Always disable EOP on all chips on the AGG rings when TPA is enabled
+to fix the data corruption.
+
+Fixes: bfcd8d791ec1 ("bnxt_en: Add fast path logic for TPA on 57500 chips.")
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-5-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 0d6b6866154ab..83ddf753b8c99 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -4506,11 +4506,14 @@ static void bnxt_init_one_rx_agg_ring_rxbd(struct bnxt *bp,
+ type = ((u32)rxr->rx_page_size << RX_BD_LEN_SHIFT) |
+ RX_BD_TYPE_RX_AGG_BD;
+
+- /* On P7, setting EOP will cause the chip to disable
+- * Relaxed Ordering (RO) for TPA data. Disable EOP for
+- * potentially higher performance with RO.
++ /* Disable EOP if TPA is enabled to prevent overlapping zero
++ * padding with the next segment's data. On P7_PLUS, EOP will
++ * automatically disable Relaxed Ordering (RO) to prevent
++ * potential data corruption (and may degrade performance). On
++ * older chips, RO will not be automatically disabled and may
++ * cause corruption.
+ */
+- if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
++ if (!(bp->flags & BNXT_FLAG_TPA))
+ type |= RX_BD_FLAGS_AGG_EOP;
+
+ bnxt_init_rxbd_pages(ring, type);
+--
+2.53.0
+
--- /dev/null
+From aacfa2daf3d8b132e43e6eb38721d0788f8b7832 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Nov 2025 13:56:46 -0800
+Subject: bnxt_en: Do not set EOP on RX AGG BDs on 5760X chips
+
+From: Michael Chan <michael.chan@broadcom.com>
+
+[ Upstream commit 30f253f8d9a01d532fdb7ec6c8a9d4c15fe29241 ]
+
+With End-of-Packet padding (EOP) set, the chip will disable Relaxed
+Ordering (RO) of TPA data packets. A TPA segment with EOP set will be
+padded to the next cache boundary and can potentially overwrite the
+beginning bytes of the next TPA segment when RO is enabled on 5760X.
+To prevent that, the chip disables RO for TPA when EOP is set.
+
+To take advantge of RO and higher performance, do not set EOP on
+5760X chips when TPA is enabled. Define a proper RX_BD_FLAGS_AGG_EOP
+constant to make it clear that we are setting EOP.
+
+Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
+Reviewed-by: Somnath Kotur <somnath.kotur@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20251126215648.1885936-6-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 ++++++++-
+ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
+ 2 files changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 98a911eae8eac..1efd1f8776abe 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -4495,7 +4495,14 @@ static void bnxt_init_one_rx_agg_ring_rxbd(struct bnxt *bp,
+ ring->fw_ring_id = INVALID_HW_RING_ID;
+ if ((bp->flags & BNXT_FLAG_AGG_RINGS)) {
+ type = ((u32)BNXT_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
+- RX_BD_TYPE_RX_AGG_BD | RX_BD_FLAGS_SOP;
++ RX_BD_TYPE_RX_AGG_BD;
++
++ /* On P7, setting EOP will cause the chip to disable
++ * Relaxed Ordering (RO) for TPA data. Disable EOP for
++ * potentially higher performance with RO.
++ */
++ if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
++ type |= RX_BD_FLAGS_AGG_EOP;
+
+ bnxt_init_rxbd_pages(ring, type);
+ }
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+index d55987e24ad6e..b140799f07d69 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+@@ -131,6 +131,7 @@ struct rx_bd {
+ #define RX_BD_TYPE_48B_BD_SIZE (2 << 4)
+ #define RX_BD_TYPE_64B_BD_SIZE (3 << 4)
+ #define RX_BD_FLAGS_SOP (1 << 6)
++ #define RX_BD_FLAGS_AGG_EOP (1 << 6)
+ #define RX_BD_FLAGS_EOP (1 << 7)
+ #define RX_BD_FLAGS_BUFFERS (3 << 8)
+ #define RX_BD_FLAGS_1_BUFFER_PACKET (0 << 8)
+--
+2.53.0
+
--- /dev/null
+From fbf62b5c86a648fc5a46f53081460449b32a991f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:37 -0700
+Subject: bnxt_en: Fix PTP PPS setting bug
+
+From: Keegan Freyhof <keegan.freyhof@broadcom.com>
+
+[ Upstream commit 80eaf88efec33ac77ed7726d066c4f2f932cc329 ]
+
+The existing driver logic is always turning on PTP_CLK_REQ_PPS
+regardless of the "on" parameter passed to bnxt_ptp_enable().
+During shutdown, PTP_CLK_REQ_PPS may be turned off and this
+bug will do the opposite and may trigger a PCIe PTM request TLP.
+On some systems this can trigger a PCIe AER.
+
+Fix it by properly configuring PTP_CLK_REQ_PPS based on the "on"
+parameter.
+
+Fixes: 9e518f25802c ("bnxt_en: 1PPS functions to configure TSIO pins")
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Keegan Freyhof <keegan.freyhof@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-6-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
+index 0abaa2bbe3577..44b7afe9a6f56 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
+@@ -514,12 +514,15 @@ static int bnxt_ptp_enable(struct ptp_clock_info *ptp_info,
+ return rc;
+ case PTP_CLK_REQ_PPS:
+ /* Configure PHC PPS IN */
+- rc = bnxt_ptp_cfg_pin(bp, 0, BNXT_PPS_PIN_PPS_IN);
++ pin_id = 0;
++ if (!on)
++ break;
++ rc = bnxt_ptp_cfg_pin(bp, pin_id, BNXT_PPS_PIN_PPS_IN);
+ if (rc)
+ return rc;
+ rc = bnxt_ptp_cfg_event(bp, BNXT_PPS_EVENT_INTERNAL);
+ if (!rc)
+- ptp->pps_info.pins[0].event = BNXT_PPS_EVENT_INTERNAL;
++ ptp->pps_info.pins[pin_id].event = BNXT_PPS_EVENT_INTERNAL;
+ return rc;
+ default:
+ netdev_err(ptp->bp->dev, "Unrecognized PIN function\n");
+--
+2.53.0
+
--- /dev/null
+From a1030280b63fcdac7fc9e586e7fa5ce9982f70c2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:33 -0700
+Subject: bnxt_en: Move RSS table fill outside __bnxt_hwrm_vnic_set_rss()
+
+From: Shravya KN <shravya.k-n@broadcom.com>
+
+[ Upstream commit 1d0fc6c7ea49994b8ff50d02979d1e4207ec6c4f ]
+
+This is a refactor patch with no change in behavior. The caller
+will now fill the RSS table before calling __bnxt_hwrm_vnic_set_rss().
+In the next patch, we'll add code to determine the default ring for
+the VNIC when we fill the RSS table.
+
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Shravya KN <shravya.k-n@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-2-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 0b137529a899 ("bnxt_en: Refresh VNIC default ring on queue restart if needed")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index d90775c0ce0b5..fba5b7f27ce7b 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -6595,6 +6595,9 @@ static void bnxt_fill_hw_rss_tbl(struct bnxt *bp, struct bnxt_vnic_info *vnic)
+ bool no_rss = !(vnic->flags & BNXT_VNIC_RSS_FLAG);
+ u16 i, j;
+
++ if (!vnic->rss_table)
++ return;
++
+ /* Fill the RSS indirection table with ring group ids */
+ for (i = 0, j = 0; i < HW_HASH_INDEX_SIZE; i++) {
+ if (!no_rss)
+@@ -6634,13 +6637,8 @@ static void
+ __bnxt_hwrm_vnic_set_rss(struct bnxt *bp, struct hwrm_vnic_rss_cfg_input *req,
+ struct bnxt_vnic_info *vnic)
+ {
+- if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
+- bnxt_fill_hw_rss_tbl_p5(bp, vnic);
+- if (bp->flags & BNXT_FLAG_CHIP_P7)
+- req->flags |= VNIC_RSS_CFG_REQ_FLAGS_IPSEC_HASH_TYPE_CFG_SUPPORT;
+- } else {
+- bnxt_fill_hw_rss_tbl(bp, vnic);
+- }
++ if (bp->flags & BNXT_FLAG_CHIP_P7)
++ req->flags |= VNIC_RSS_CFG_REQ_FLAGS_IPSEC_HASH_TYPE_CFG_SUPPORT;
+
+ if (bp->rss_hash_delta) {
+ req->hash_type = cpu_to_le32(bp->rss_hash_delta);
+@@ -6692,6 +6690,7 @@ static int bnxt_hwrm_vnic_set_rss_p5(struct bnxt *bp,
+ if (!set_rss)
+ return hwrm_req_send(bp, req);
+
++ bnxt_fill_hw_rss_tbl_p5(bp, vnic);
+ __bnxt_hwrm_vnic_set_rss(bp, req, vnic);
+ ring_tbl_map = vnic->rss_table_dma_addr;
+ nr_ctxs = bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings);
+@@ -10722,6 +10721,7 @@ static int __bnxt_setup_vnic(struct bnxt *bp, struct bnxt_vnic_info *vnic)
+ }
+
+ skip_rss_ctx:
++ bnxt_fill_hw_rss_tbl(bp, vnic);
+ /* configure default vnic, ring grp */
+ rc = bnxt_hwrm_vnic_cfg(bp, vnic);
+ if (rc) {
+--
+2.53.0
+
--- /dev/null
+From 1ff9996190e57f9f4ff49d24cc8b362d75c0c39b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:35 -0700
+Subject: bnxt_en: Refresh VNIC default ring on queue restart if needed
+
+From: Shravya KN <shravya.k-n@broadcom.com>
+
+[ Upstream commit 0b137529a8997caf67190ca1d71ba8bbdb44fbfb ]
+
+When a queue is restarted, refresh VNIC_CFG for all VNICs whose
+default RX ring is the restarted ring. This will eliminate this
+possible FW warning caused by a stale default ring in the VNIC:
+
+FW reported unknown error type 10
+
+Fixes: 5ac066b7b062 ("bnxt_en: Fix queue start to update vnic RSS table")
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Shravya KN <shravya.k-n@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-4-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index df5fd228d84ae..0d6b6866154ab 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -10954,6 +10954,11 @@ static int bnxt_set_vnic_mru_p5(struct bnxt *bp, struct bnxt_vnic_info *vnic,
+ vnic->vnic_id, rc);
+ return rc;
+ }
++ if (rxr_id == vnic->default_rx_ring) {
++ rc = bnxt_hwrm_vnic_cfg(bp, vnic);
++ if (rc)
++ return rc;
++ }
+ }
+ vnic->mru = mru;
+ bnxt_hwrm_vnic_update(bp, vnic,
+--
+2.53.0
+
--- /dev/null
+From 3b559a15596e2418c9a530f1a89502a4e11b5651 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 25 Jul 2026 23:39:30 +0000
+Subject: bonding: alb: re-check primary_is_promisc under RTNL in
+ bond_alb_monitor
+
+From: Xiang Mei (Microsoft) <xmei5@asu.edu>
+
+[ Upstream commit 683c6ba6e58e6ed1037831ea97dd58d9c0e76b8d ]
+
+bond_alb_monitor() reads primary_is_promisc under RCU, then drops RCU and
+takes RTNL via rtnl_trylock() before undoing the promiscuity it set on the
+active slave. In that window the active slave can change under RTNL
+(RTM_DELLINK -> __bond_release_one() -> bond_alb_handle_active_change()),
+which already drops the promiscuity and clears primary_is_promisc. The
+monitor still acts on the stale decision: if the slave was removed with no
+failover, curr_active_slave is now NULL and the deref faults; if it failed
+over, the stale dev_set_promiscuity(-1) underflows the new slave's
+promiscuity counter and pins it in IFF_PROMISC.
+
+ Oops: general protection fault, probably for non-canonical address ...
+ KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
+ Workqueue: b42 bond_alb_monitor
+ RIP: 0010:bond_alb_monitor (drivers/net/bonding/bond_alb.c:1600)
+ process_one_work (kernel/workqueue.c:3322)
+ worker_thread (kernel/workqueue.c:3486)
+ kthread (kernel/kthread.c:436)
+ ret_from_fork (arch/x86/kernel/process.c:158)
+ Kernel panic - not syncing: Fatal exception
+
+Re-check primary_is_promisc (and curr_active_slave) after taking RTNL so
+the monitor only undoes an increment it still owns. The other bonding
+monitors already re-read state under RTNL in their commit phase
+(bond_miimon_commit/bond_ab_arp_commit); bond_alb_monitor() was the only
+one acting on the pre-trylock decision.
+
+Fixes: d0e81b7e2246 ("bonding: Acquire correct locks in alb for promisc change")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
+Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
+Acked-by: Jay Vosburgh <jv@jvosburgh.net>
+Link: https://patch.msgid.link/20260725233930.2957317-1-xmei5@asu.edu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/bonding/bond_alb.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
+index 2d37b07c8215c..839f7482dc182 100644
+--- a/drivers/net/bonding/bond_alb.c
++++ b/drivers/net/bonding/bond_alb.c
+@@ -1534,8 +1534,8 @@ void bond_alb_monitor(struct work_struct *work)
+ struct bonding *bond = container_of(work, struct bonding,
+ alb_work.work);
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
++ struct slave *slave, *curr;
+ struct list_head *iter;
+- struct slave *slave;
+
+ if (!bond_has_slaves(bond)) {
+ atomic_set(&bond_info->tx_rebalance_counter, 0);
+@@ -1597,9 +1597,11 @@ void bond_alb_monitor(struct work_struct *work)
+ * because a slave was disabled then
+ * it can now leave promiscuous mode.
+ */
+- dev_set_promiscuity(rtnl_dereference(bond->curr_active_slave)->dev,
+- -1);
+- bond_info->primary_is_promisc = 0;
++ curr = rtnl_dereference(bond->curr_active_slave);
++ if (bond_info->primary_is_promisc && curr) {
++ dev_set_promiscuity(curr->dev, -1);
++ bond_info->primary_is_promisc = 0;
++ }
+
+ rtnl_unlock();
+ rcu_read_lock();
+--
+2.53.0
+
--- /dev/null
+From 01c95813af37e406055b7e67372ae48bd3e300e5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:18:28 +0000
+Subject: bpf: Preserve pointer state for commuted arithmetic
+
+From: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+
+[ Upstream commit a4c6f804b44c5c790269b25e0e61cf4e9f117c86 ]
+
+When scalar += pointer is handled in adjust_ptr_min_max_vals(), the
+destination register inherits the pointer state from the source pointer.
+Copying only selected fields is fragile because pointer provenance is
+tracked by several bpf_reg_state fields.
+
+Use the caller's temporary offset register to preserve the scalar operand
+while replacing the destination with the full pointer state. This preserves
+the frame number for PTR_TO_STACK registers and keeps parent identity
+fields consistent.
+
+Fixes: f4d7e40a5b71 ("bpf: introduce function calls (verification)")
+Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+Tested-by: Daniel Wade <danjwade95@gmail.com>
+Acked-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-2-8ee297e2346b@mails.tsinghua.edu.cn
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 463455180a8e3..17c1ccff3ac20 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -14734,11 +14734,12 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ return -EACCES;
+ }
+
+- /* In case of 'scalar += pointer', dst_reg inherits pointer type and id.
+- * The id may be overwritten later if we create a new variable offset.
++ /* For 'scalar += pointer', dst_reg inherits the complete pointer
++ * register state. Individual fields may be adjusted later by pointer
++ * arithmetic. Callers guarantee that below does not overwrite off_reg.
+ */
+- dst_reg->type = ptr_reg->type;
+- dst_reg->id = ptr_reg->id;
++ if (dst_reg != ptr_reg)
++ *dst_reg = *ptr_reg;
+
+ if (!check_reg_sane_offset(env, off_reg, ptr_reg->type) ||
+ !check_reg_sane_offset(env, ptr_reg, ptr_reg->type))
+@@ -14800,7 +14801,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ }
+ break;
+ case BPF_SUB:
+- if (dst_reg == off_reg) {
++ if (dst_reg != ptr_reg) {
+ /* scalar -= pointer. Creates an unknown scalar */
+ verbose(env, "R%d tried to subtract pointer from scalar\n",
+ dst);
+@@ -15764,8 +15765,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
+ err = mark_chain_precision(env, insn->dst_reg);
+ if (err)
+ return err;
+- return adjust_ptr_min_max_vals(env, insn,
+- src_reg, dst_reg);
++ off_reg = *dst_reg;
++ return adjust_ptr_min_max_vals(env, insn, src_reg, &off_reg);
+ }
+ } else if (ptr_reg) {
+ /* pointer += scalar */
+--
+2.53.0
+
--- /dev/null
+From 9fb7974d831b5f9814d9ba0bbc74ed3df62c62d8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:18:29 +0000
+Subject: bpf: Propagate untrusted pointer state in commuted arithmetic
+
+From: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+
+[ Upstream commit cdf19b1b3c01791de074ce282089131026f52261 ]
+
+The untrusted PTR_TO_MEM early return skips pointer offset tracking
+because accesses go through probe-read handling. Moving it after full
+pointer-state propagation ensures scalar += untrusted_pointer leaves the
+destination as PTR_TO_MEM instead of an unrelated scalar.
+
+Fixes: f2362a57aeff ("bpf: allow void* cast using bpf_rdonly_cast()")
+Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+Tested-by: Daniel Wade <danjwade95@gmail.com>
+Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-3-8ee297e2346b@mails.tsinghua.edu.cn
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 80710cb8421ef..459ed144542cc 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -14713,13 +14713,6 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ return -EACCES;
+ }
+
+- /*
+- * Accesses to untrusted PTR_TO_MEM are done through probe
+- * instructions, hence no need to track offsets.
+- */
+- if (base_type(ptr_reg->type) == PTR_TO_MEM && (ptr_reg->type & PTR_UNTRUSTED))
+- return 0;
+-
+ switch (base_type(ptr_reg->type)) {
+ case PTR_TO_CTX:
+ case PTR_TO_MAP_VALUE:
+@@ -14756,6 +14749,13 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ if (dst_reg != ptr_reg)
+ *dst_reg = *ptr_reg;
+
++ /*
++ * Accesses to untrusted PTR_TO_MEM are done through probe
++ * instructions, hence no need to track offsets.
++ */
++ if (base_type(ptr_reg->type) == PTR_TO_MEM && (ptr_reg->type & PTR_UNTRUSTED))
++ return 0;
++
+ if (!check_reg_sane_offset_scalar(env, off_reg, ptr_reg->type) ||
+ !check_reg_sane_offset_ptr(env, ptr_reg, ptr_reg->type))
+ return -EINVAL;
+--
+2.53.0
+
--- /dev/null
+From b8e7076f524063ba4e7f374868757137f94e065a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Feb 2026 13:34:21 -0800
+Subject: bpf: split check_reg_sane_offset() in two parts
+
+From: Eduard Zingerman <eddyz87@gmail.com>
+
+[ Upstream commit ed20a14309e09216d1fa86e12b1578fa822119b4 ]
+
+check_reg_sane_offset() is used when verifying operations like:
+
+ dst_reg += src_reg
+ ^ ^
+ | '-------- scalar
+ '------------------- pointer
+
+To verify range for both dst_reg and src_reg. Split it in two parts:
+- one to check a pointer offset
+- another to check scalar offset
+
+This would be useful for further refactoring.
+
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20260212-ptrs-off-migration-v2-1-00820e4d3438@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Stable-dep-of: cdf19b1b3c01 ("bpf: Propagate untrusted pointer state in commuted arithmetic")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 39 +++++++++++++++++++++++++++------------
+ 1 file changed, 27 insertions(+), 12 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 17c1ccff3ac20..80710cb8421ef 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -14291,9 +14291,9 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
+ return 0;
+ }
+
+-static bool check_reg_sane_offset(struct bpf_verifier_env *env,
+- const struct bpf_reg_state *reg,
+- enum bpf_reg_type type)
++static bool check_reg_sane_offset_scalar(struct bpf_verifier_env *env,
++ const struct bpf_reg_state *reg,
++ enum bpf_reg_type type)
+ {
+ bool known = tnum_is_const(reg->var_off);
+ s64 val = reg->var_off.value;
+@@ -14305,12 +14305,6 @@ static bool check_reg_sane_offset(struct bpf_verifier_env *env,
+ return false;
+ }
+
+- if (reg->off >= BPF_MAX_VAR_OFF || reg->off <= -BPF_MAX_VAR_OFF) {
+- verbose(env, "%s pointer offset %d is not allowed\n",
+- reg_type_str(env, type), reg->off);
+- return false;
+- }
+-
+ if (smin == S64_MIN) {
+ verbose(env, "math between %s pointer and register with unbounded min value is not allowed\n",
+ reg_type_str(env, type));
+@@ -14326,6 +14320,27 @@ static bool check_reg_sane_offset(struct bpf_verifier_env *env,
+ return true;
+ }
+
++static bool check_reg_sane_offset_ptr(struct bpf_verifier_env *env,
++ const struct bpf_reg_state *reg,
++ enum bpf_reg_type type)
++{
++ s64 smin = reg->smin_value;
++
++ if (reg->off >= BPF_MAX_VAR_OFF || reg->off <= -BPF_MAX_VAR_OFF) {
++ verbose(env, "%s pointer offset %d is not allowed\n",
++ reg_type_str(env, type), reg->off);
++ return false;
++ }
++
++ if (smin >= BPF_MAX_VAR_OFF || smin <= -BPF_MAX_VAR_OFF) {
++ verbose(env, "%s pointer offset %lld is not allowed\n",
++ reg_type_str(env, type), smin);
++ return false;
++ }
++
++ return true;
++}
++
+ enum {
+ REASON_BOUNDS = -1,
+ REASON_TYPE = -2,
+@@ -14741,8 +14756,8 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ if (dst_reg != ptr_reg)
+ *dst_reg = *ptr_reg;
+
+- if (!check_reg_sane_offset(env, off_reg, ptr_reg->type) ||
+- !check_reg_sane_offset(env, ptr_reg, ptr_reg->type))
++ if (!check_reg_sane_offset_scalar(env, off_reg, ptr_reg->type) ||
++ !check_reg_sane_offset_ptr(env, ptr_reg, ptr_reg->type))
+ return -EINVAL;
+
+ /* pointer types do not carry 32-bit bounds at the moment. */
+@@ -14871,7 +14886,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ return -EACCES;
+ }
+
+- if (!check_reg_sane_offset(env, dst_reg, ptr_reg->type))
++ if (!check_reg_sane_offset_ptr(env, dst_reg, ptr_reg->type))
+ return -EINVAL;
+ reg_bounds_sync(dst_reg);
+ bounds_ret = sanitize_check_bounds(env, insn, dst_reg);
+--
+2.53.0
+
--- /dev/null
+From ccb35938773815882e066696dbda415f1d0f0d2b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 22:32:47 +0000
+Subject: bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()
+
+From: Jose Fernandez (Anthropic) <jose.fernandez@linux.dev>
+
+[ Upstream commit e5fd3f514e27db1f05fbd72ba615d74941e23c51 ]
+
+reqsk_queue_hash_req() publishes a TCP_NEW_SYN_RECV request_sock onto
+the ehash chain, drops the bucket lock, and only afterwards sets
+rsk_refcnt to 3.
+
+Lockless readers such as __inet_lookup_established() handle this with
+refcount_inc_not_zero(), but bpf_iter_tcp_established_batch() uses plain
+sock_hold() while holding the bucket lock, on the assumption that the
+lock guarantees sk_refcnt > 0. That assumption does not hold for
+request_sock:
+
+ CPU 0 CPU 1
+ ----- -----
+ tcp_conn_request()
+ reqsk_queue_hash_req()
+ inet_ehash_insert(req)
+ spin_lock(bucket)
+ __sk_nulls_add_node_rcu(req) // rsk_refcnt == 0
+ spin_unlock(bucket)
+ bpf_iter_tcp_established_batch()
+ spin_lock(bucket)
+ sock_hold(req) <-- addition on 0
+ spin_unlock(bucket)
+ refcount_set(&req->rsk_refcnt, 3) // clobbers saturated value
+
+which surfaces as:
+
+ refcount_t: addition on 0; use-after-free.
+ WARNING: lib/refcount.c:25 at refcount_warn_saturate+0x48/0x90, CPU#1
+ Call Trace:
+ bpf_iter_tcp_established_batch+0x14e/0x170
+ bpf_iter_tcp_batch+0x53/0x200
+ bpf_iter_tcp_seq_next+0x27/0x70
+ bpf_seq_read+0x107/0x410
+ vfs_read+0xb9/0x380
+
+The iterator's stolen reference is lost when the publishing CPU's
+refcount_set() overwrites the count, leaving the socket one reference
+short. When the last legitimate owner drops its reference the reqsk is
+freed while still reachable, leading to use-after-free.
+
+This reproduces in seconds with tcp_syncookies=0, a handful of threads
+doing connect()/close() to a local listener while others read an
+iter/tcp link in a tight loop.
+
+Use refcount_inc_not_zero() and skip the socket on failure. A skipped
+socket is still part of the bucket, so keep counting it in expected.
+The reallocations are sized from expected, and a request sock whose
+refcount gets published while the lock is held across the last realloc
+must already have room.
+
+A skipped socket is counted in expected but never batched, so end_sk
+can be short of expected on a batch that is actually complete. Decide
+completeness by whether the walk left any socket behind instead. The
+WARN after the locked realloc checks the same, replacing an
+end_sk == expected check that could not hold on that path since
+commit cdec67a489d4 ("bpf: tcp: Make sure iter->batch always
+contains a full bucket snapshot").
+
+If every matching socket in a bucket is mid-init (refcount 0), end_sk
+stays 0. Advance to the next bucket rather than returning a batch entry
+that was never filled this round.
+
+Fixes: 04c7820b776f ("bpf: tcp: Bpf iter batching and lock_sock")
+Assisted-by: Claude:unspecified
+Signed-off-by: Jose Fernandez (Anthropic) <jose.fernandez@linux.dev>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Link: https://lore.kernel.org/bpf/20260730-bpf-iter-tcp-refcnt-v3-1-754b9c8a6717@linux.dev
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 43 ++++++++++++++++++++++++-------------------
+ 1 file changed, 24 insertions(+), 19 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index 3463e5b964a98..708b69cc2f56c 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -3219,24 +3219,24 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,
+ {
+ struct bpf_tcp_iter_state *iter = seq->private;
+ struct hlist_nulls_node *node;
+- unsigned int expected = 1;
+- struct sock *sk;
+-
+- sock_hold(*start_sk);
+- iter->batch[iter->end_sk++].sk = *start_sk;
++ struct sock *sk = *start_sk;
++ unsigned int expected = 0;
+
+- sk = sk_nulls_next(*start_sk);
+ *start_sk = NULL;
+ sk_nulls_for_each_from(sk, node) {
+- if (seq_sk_match(seq, sk)) {
+- if (iter->end_sk < iter->max_sk) {
+- sock_hold(sk);
+- iter->batch[iter->end_sk++].sk = sk;
+- } else if (!*start_sk) {
+- /* Remember where we left off. */
+- *start_sk = sk;
+- }
+- expected++;
++ if (!seq_sk_match(seq, sk))
++ continue;
++ expected++;
++ if (iter->end_sk < iter->max_sk) {
++ /* reqsk_queue_hash_req() inserts with sk_refcnt == 0
++ * and refcount_set()s it after the bucket lock drops.
++ */
++ if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
++ continue;
++ iter->batch[iter->end_sk++].sk = sk;
++ } else if (!*start_sk) {
++ /* Remember where we left off. */
++ *start_sk = sk;
+ }
+ }
+
+@@ -3274,12 +3274,13 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ struct sock *sk;
+ int err;
+
++again:
+ sk = bpf_iter_tcp_resume(seq);
+ if (!sk)
+ return NULL; /* Done */
+
+ expected = bpf_iter_fill_batch(seq, &sk);
+- if (likely(iter->end_sk == expected))
++ if (likely(!sk))
+ goto done;
+
+ /* Batch size was too small. */
+@@ -3298,7 +3299,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ return NULL; /* Done */
+
+ expected = bpf_iter_fill_batch(seq, &sk);
+- if (likely(iter->end_sk == expected))
++ if (likely(!sk))
+ goto done;
+
+ /* Batch size was still too small. Hold onto the lock while we try
+@@ -3311,10 +3312,14 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ return ERR_PTR(err);
+ }
+
+- expected = bpf_iter_fill_batch(seq, &sk);
+- WARN_ON_ONCE(iter->end_sk != expected);
++ bpf_iter_fill_batch(seq, &sk);
++ WARN_ON_ONCE(sk);
+ done:
+ bpf_iter_tcp_unlock_bucket(seq);
++ if (unlikely(!iter->end_sk)) {
++ ++iter->state.bucket;
++ goto again;
++ }
+ return iter->batch[0].sk;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 9b2b7318df597191bf84329f5e6e74a56cb73d0c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 16:37:39 +0930
+Subject: btrfs: disable bs > ps support if no transparent hugepage support
+
+From: Qu Wenruo <wqu@suse.com>
+
+[ Upstream commit 4c375ac546ea667e619ab77d34cca6edcab7c448 ]
+
+Btrfs relies on mapping_set_folio_order_range() to set the minimal
+folio order for all its data inodes, but that function will be no-op if
+transparent hugepage is not enabled.
+
+Guard the bs > ps support behind CONFIG_TRANSPARENT_HUGEPAGE, just like
+all other filesystems.
+
+Fixes: 98077f7f2180 ("btrfs: enable experimental bs > ps support")
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/Kconfig | 3 ++-
+ fs/btrfs/fs.c | 12 ++++++++++--
+ 2 files changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig
+index 4bafbf6636cd2..5f922563b6b62 100644
+--- a/fs/btrfs/Kconfig
++++ b/fs/btrfs/Kconfig
+@@ -115,7 +115,8 @@ config BTRFS_EXPERIMENTAL
+
+ - extent tree v2 - complex rework of extent tracking
+
+- - block size > page size support
++ - block size > page size support - needs transparent huge page and
++ non-HIGHMEM system
+
+ - shutdown ioctl and auto-degradation support
+
+diff --git a/fs/btrfs/fs.c b/fs/btrfs/fs.c
+index feb0a2faa8379..bf86d8d5a05d9 100644
+--- a/fs/btrfs/fs.c
++++ b/fs/btrfs/fs.c
+@@ -94,9 +94,17 @@ bool __attribute_const__ btrfs_supported_blocksize(u32 blocksize)
+ *
+ * Considering HIGHMEM is such a pain to deal with and it's going
+ * to be deprecated eventually, just reject HIGHMEM && bs > ps cases.
++ *
++ * Finally, for bs > ps cases, we need to set the minimal folio order,
++ * which requires transparent hugepage.
+ */
+- if (IS_ENABLED(CONFIG_HIGHMEM) && blocksize > PAGE_SIZE)
+- return false;
++ if (blocksize > PAGE_SIZE) {
++ if (IS_ENABLED(CONFIG_HIGHMEM))
++ return false;
++
++ if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
++ return false;
++ }
+ return true;
+ #endif
+ return false;
+--
+2.53.0
+
--- /dev/null
+From edcab8276b4fe316fe5c1e52c8c15ec4636fe137 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 14:53:52 +0300
+Subject: btrfs: fix memory leak in btrfs_do_encoded_write()
+
+From: Dmitry Antipov <dmantipov@yandex.ru>
+
+[ Upstream commit d2a4e4e626b2f4670b69b430c357f03f53eb6632 ]
+
+Local fuzzing of 6.12.94 has found the following memory leak:
+
+Unreferenced object 0xffff888018050a80 (size 64):
+ comm "syz.0.17", pid 10297, jiffies 4294953601
+ hex dump (first 32 bytes):
+ 00 10 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................
+ 10 0a 05 18 80 88 ff ff 10 0a 05 18 80 88 ff ff ................
+ backtrace (crc a8a6fc29):
+ kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
+ slab_post_alloc_hook mm/slub.c:4152 [inline]
+ slab_alloc_node mm/slub.c:4197 [inline]
+ __kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358
+ kmalloc_noprof include/linux/slab.h:878 [inline]
+ extent_changeset_alloc fs/btrfs/extent_io.h:207 [inline]
+ qgroup_reserve_data+0x1c5/0x7d0 fs/btrfs/qgroup.c:4305
+ btrfs_qgroup_reserve_data+0x2e/0xb0 fs/btrfs/qgroup.c:4355
+ btrfs_do_encoded_write+0x92e/0x1040 fs/btrfs/inode.c:9746
+ btrfs_encoded_write fs/btrfs/file.c:1482 [inline]
+ btrfs_do_write_iter+0x280/0x610 fs/btrfs/file.c:1507
+ btrfs_ioctl_encoded_write+0x3d6/0x490 fs/btrfs/ioctl.c:4738
+ btrfs_ioctl+0x6f9/0xc90 fs/btrfs/ioctl.c:-1
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:906 [inline]
+ __se_sys_ioctl+0xf9/0x170 fs/ioctl.c:892
+ do_syscall_x64 arch/x86/entry/common.c:47 [inline]
+ do_syscall_64+0xbe/0x1a0 arch/x86/entry/common.c:78
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Unreferenced object 0xffff888018050a00 (size 64):
+ comm "syz.0.17", pid 10297, jiffies 4294953601
+ hex dump (first 32 bytes):
+ 00 00 00 00 00 00 00 00 ff 0f 00 00 00 00 00 00 ................
+ 90 0a 05 18 80 88 ff ff 90 0a 05 18 80 88 ff ff ................
+ backtrace (crc cb5c9580):
+ kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
+ slab_post_alloc_hook mm/slub.c:4152 [inline]
+ slab_alloc_node mm/slub.c:4197 [inline]
+ __kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358
+ kmalloc_noprof include/linux/slab.h:878 [inline]
+ kzalloc_noprof include/linux/slab.h:1014 [inline]
+ ulist_prealloc+0x9c/0x110 fs/btrfs/ulist.c:114
+ extent_changeset_prealloc fs/btrfs/extent_io.h:217 [inline]
+ __set_extent_bit+0x16b/0x1a70 fs/btrfs/extent-io-tree.c:1086
+ set_record_extent_bits+0x50/0x90 fs/btrfs/extent-io-tree.c:1821
+ qgroup_reserve_data+0x274/0x7d0 fs/btrfs/qgroup.c:4312
+ btrfs_qgroup_reserve_data+0x2e/0xb0 fs/btrfs/qgroup.c:4355
+ btrfs_do_encoded_write+0x92e/0x1040 fs/btrfs/inode.c:9746
+ btrfs_encoded_write fs/btrfs/file.c:1482 [inline]
+ btrfs_do_write_iter+0x280/0x610 fs/btrfs/file.c:1507
+ btrfs_ioctl_encoded_write+0x3d6/0x490 fs/btrfs/ioctl.c:4738
+ btrfs_ioctl+0x6f9/0xc90 fs/btrfs/ioctl.c:-1
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:906 [inline]
+ __se_sys_ioctl+0xf9/0x170 fs/ioctl.c:892
+ do_syscall_x64 arch/x86/entry/common.c:47 [inline]
+ do_syscall_64+0xbe/0x1a0 arch/x86/entry/common.c:78
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Fix this by freeing an extent changeset before returning from
+btrfs_do_encoded_write().
+
+Fixes: 7c0c7269f7b5 ("btrfs: add BTRFS_IOC_ENCODED_WRITE")
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/inode.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index 36f75c6a8344d..7af5ea0cf55fd 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -10037,6 +10037,7 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
+ }
+ kvfree(folios);
+ out:
++ extent_changeset_free(data_reserved);
+ if (ret >= 0)
+ iocb->ki_pos += encoded->len;
+ return ret;
+--
+2.53.0
+
--- /dev/null
+From edd1fee37171e82730173367ff9ae8cfc44a8296 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Apr 2026 10:20:25 +0930
+Subject: btrfs: move large data folios out of experimental features
+
+From: Qu Wenruo <wqu@suse.com>
+
+[ Upstream commit 9bce95edb1b4d2802de9273b5170bfcff3090d24 ]
+
+This feature was introduced in v6.17 under experimental, and we had
+several small bugs related to or exposed by that:
+
+ e9e3b22ddfa7 ("btrfs: fix beyond-EOF write handling")
+ 18de34daa7c6 ("btrfs: truncate ordered extent when skipping writeback past i_size")
+
+Otherwise, the feature has been frequently tested by btrfs developers.
+
+The latest fix only arrived in v6.19. After three releases, I think it's
+time to move this feature out of experimental.
+
+And since we're here, also remove the comment about the bitmap size
+limit, which is no longer relevant in the context. It will soon be
+outdated for the incoming huge folio support.
+
+Reviewed-by: Neal Gompa <neal@gompa.dev>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Stable-dep-of: 4c375ac546ea ("btrfs: disable bs > ps support if no transparent hugepage support")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/Kconfig | 2 +-
+ fs/btrfs/btrfs_inode.h | 3 ---
+ fs/btrfs/defrag.c | 17 -----------------
+ 3 files changed, 1 insertion(+), 21 deletions(-)
+
+diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig
+index 6d6fc85835d46..4bafbf6636cd2 100644
+--- a/fs/btrfs/Kconfig
++++ b/fs/btrfs/Kconfig
+@@ -115,7 +115,7 @@ config BTRFS_EXPERIMENTAL
+
+ - extent tree v2 - complex rework of extent tracking
+
+- - large folio and block size (> page size) support
++ - block size > page size support
+
+ - shutdown ioctl and auto-degradation support
+
+diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
+index b6b46f951f11a..7a647d42d181c 100644
+--- a/fs/btrfs/btrfs_inode.h
++++ b/fs/btrfs/btrfs_inode.h
+@@ -535,12 +535,9 @@ static inline void btrfs_set_inode_mapping_order(struct btrfs_inode *inode)
+ /* Metadata inode should not reach here. */
+ ASSERT(is_data_inode(inode));
+
+- /* We only allow BITS_PER_LONGS blocks for each bitmap. */
+-#ifdef CONFIG_BTRFS_EXPERIMENTAL
+ mapping_set_folio_order_range(inode->vfs_inode.i_mapping,
+ inode->root->fs_info->block_min_order,
+ inode->root->fs_info->block_max_order);
+-#endif
+ }
+
+ /* Array of bytes with variable length, hexadecimal format 0x1234 */
+diff --git a/fs/btrfs/defrag.c b/fs/btrfs/defrag.c
+index 2e3c011d410a6..a47dc6b9d33ff 100644
+--- a/fs/btrfs/defrag.c
++++ b/fs/btrfs/defrag.c
+@@ -862,23 +862,6 @@ static struct folio *defrag_prepare_one_folio(struct btrfs_inode *inode, pgoff_t
+ if (IS_ERR(folio))
+ return folio;
+
+- /*
+- * Since we can defragment files opened read-only, we can encounter
+- * transparent huge pages here (see CONFIG_READ_ONLY_THP_FOR_FS).
+- *
+- * The IO for such large folios is not fully tested, thus return
+- * an error to reject such folios unless it's an experimental build.
+- *
+- * Filesystem transparent huge pages are typically only used for
+- * executables that explicitly enable them, so this isn't very
+- * restrictive.
+- */
+- if (!IS_ENABLED(CONFIG_BTRFS_EXPERIMENTAL) && folio_test_large(folio)) {
+- folio_unlock(folio);
+- folio_put(folio);
+- return ERR_PTR(-ETXTBSY);
+- }
+-
+ ret = set_folio_extent_mapped(folio);
+ if (ret < 0) {
+ folio_unlock(folio);
+--
+2.53.0
+
--- /dev/null
+From 712ac69e62af09ee2c9d66ae8c196713d1583fbe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 9 Jan 2026 14:01:14 +1030
+Subject: btrfs: update the Kconfig string for CONFIG_BTRFS_EXPERIMENTAL
+
+From: Qu Wenruo <wqu@suse.com>
+
+[ Upstream commit 64dd1caf88f96146edee24e82834cf2a11c3932b ]
+
+The following new features are missing:
+
+- Async checksum
+
+- Shutdown ioctl and auto-degradation
+
+- Larger block size support
+ Which is dependent on larger folios.
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Stable-dep-of: 4c375ac546ea ("btrfs: disable bs > ps support if no transparent hugepage support")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/Kconfig | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig
+index 4438637c8900c..6d6fc85835d46 100644
+--- a/fs/btrfs/Kconfig
++++ b/fs/btrfs/Kconfig
+@@ -115,6 +115,10 @@ config BTRFS_EXPERIMENTAL
+
+ - extent tree v2 - complex rework of extent tracking
+
+- - large folio support
++ - large folio and block size (> page size) support
++
++ - shutdown ioctl and auto-degradation support
++
++ - asynchronous checksum generation for data writes
+
+ If unsure, say N.
+--
+2.53.0
+
--- /dev/null
+From 4ffa634392b99b5d073f4e33073160b27cdf927b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jul 2026 04:29:10 +0000
+Subject: counter: microchip-tcb-capture: Fix DT channel validation
+
+From: Babanpreet Singh <bbnpreetsingh@gmail.com>
+
+[ Upstream commit f1a3a9946aab611dd2200c01ff122f64b033dad2 ]
+
+mchp_tc_probe() reads the devicetree "reg" cell - a u32, per the API
+contract of of_property_read_u32_index() - into a signed int, so the
+bounds check "channel > 2" fails to reject cell values at or above
+0x80000000: reinterpreted as a negative int, they compare below 2 and
+pass validation.
+
+A malformed devicetree can therefore drive a negative channel into the
+ATMEL_TC_REG() offset arithmetic, making the driver access syscon
+regmap offsets outside the TC block's register window, and into the
+"t%d_clk" clock-name formatting, where it truncates clk_name (sized
+for "t0_clk".."t2_clk").
+
+Declare channel as u32, matching the API contract; the unsigned
+comparison then rejects everything except channels 0..2. Adjust the
+format specifier to %u accordingly, which also resolves the W=1
+warning that exposed the gap:
+
+ microchip-tcb-capture.c:520:56: warning: '%d' directive output may
+ be truncated writing between 1 and 11 bytes into a region of size
+ 6 [-Wformat-truncation=]
+ note: directive argument in the range [-2147483648, 2]
+
+No behavior change for well-formed devicetrees: channels 0..2 take
+identical paths before and after.
+
+Fixes: 106b104137fd ("counter: Add microchip TCB capture counter")
+Assisted-by: Claude:claude-fable-5 [gcc W=1]
+Signed-off-by: Babanpreet Singh <bbnpreetsingh@gmail.com>
+Reviewed-by: Joshua Crofts <joshua.crofts1@gmail.com>
+Link: https://lore.kernel.org/r/20260714042910.7-1-bbnpreetsingh@gmail.com
+Signed-off-by: William Breathitt Gray <wbg@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/counter/microchip-tcb-capture.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/counter/microchip-tcb-capture.c b/drivers/counter/microchip-tcb-capture.c
+index 19d457ae4c3bb..e53a8390756b7 100644
+--- a/drivers/counter/microchip-tcb-capture.c
++++ b/drivers/counter/microchip-tcb-capture.c
+@@ -483,7 +483,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
+ char clk_name[7];
+ struct regmap *regmap;
+ struct clk *clk[3];
+- int channel;
++ u32 channel;
+ int ret, i;
+
+ counter = devm_counter_alloc(&pdev->dev, sizeof(*priv));
+@@ -517,7 +517,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
+
+ priv->channel[i] = channel;
+
+- snprintf(clk_name, sizeof(clk_name), "t%d_clk", channel);
++ snprintf(clk_name, sizeof(clk_name), "t%u_clk", channel);
+
+ clk[i] = of_clk_get_by_name(np->parent, clk_name);
+ if (IS_ERR(clk[i])) {
+--
+2.53.0
+
--- /dev/null
+From cc145e70baf7a1cdaf437fb3dc4a5fb51ed45e41 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 11:06:00 +0300
+Subject: devlink: fix net namespace reference leak in reload
+
+From: Or Har-Toov <ohartoov@nvidia.com>
+
+[ Upstream commit 1c4dac9bf1d2ac31da63b794bdec697777cbd0fd ]
+
+devlink_nl_reload_doit() calls devlink_netns_get(), which returns a net
+with a held reference. When the requested namespace differs from the
+current one and the reload action is not DRIVER_REINIT, the function
+returns -EOPNOTSUPP without releasing the reference. Add the missing
+put_net() on this error path.
+
+Fixes: 2edd92570441 ("devlink: don't allow to change net namespace for FW_ACTIVATE reload action")
+Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
+Reviewed-by: Jiri Pirko <jiri@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Reviewed-by: Antoine Tenart <atenart@kernel.org>
+Link: https://patch.msgid.link/20260729080600.2427721-1-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/devlink/dev.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/devlink/dev.c b/net/devlink/dev.c
+index 02602704bdeaa..ed442c1bed8db 100644
+--- a/net/devlink/dev.c
++++ b/net/devlink/dev.c
+@@ -577,6 +577,7 @@ int devlink_nl_reload_doit(struct sk_buff *skb, struct genl_info *info)
+ action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) {
+ NL_SET_ERR_MSG_MOD(info->extack,
+ "Changing namespace is only supported for reinit action");
++ put_net(dest_net);
+ return -EOPNOTSUPP;
+ }
+ }
+--
+2.53.0
+
--- /dev/null
+From e3855d2b96d64b35e4fc56c3e25f1c23738f197a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jul 2026 10:38:06 +0800
+Subject: drm/bridge: ps8640: propagate AUX transfer register errors
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 20697ecb299cd77b4cf8b28f655e56606b0472d8 ]
+
+ps8640_aux_transfer_msg() programs the AUX address registers, starts the
+AUX transfer, waits for SWAUX_SEND to clear, and reads the AUX status
+register. Several of those regmap operations have return values, but the
+function only checks a stale ret after the status read.
+
+Propagate failures from the address write, transfer start, completion
+poll, and status read. This avoids returning a transfer length when the
+bridge register transaction or AUX completion wait failed.
+
+Fixes: 13afcdd7277e ("drm/bridge: parade-ps8640: Add support for AUX channel")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Link: https://patch.msgid.link/20260723103509.2-ps8640-v2-pengpeng@iscas.ac.cn
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/bridge/parade-ps8640.c | 27 ++++++++++++++++++++------
+ 1 file changed, 21 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
+index 825777a5758f6..db8e5889dc7f1 100644
+--- a/drivers/gpu/drm/bridge/parade-ps8640.c
++++ b/drivers/gpu/drm/bridge/parade-ps8640.c
+@@ -257,8 +257,14 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
+ addr_len[PAGE0_SWAUX_LENGTH - base] = (len == 0) ? SWAUX_NO_PAYLOAD :
+ ((len - 1) & SWAUX_LENGTH_MASK);
+
+- regmap_bulk_write(map, PAGE0_SWAUX_ADDR_7_0, addr_len,
+- ARRAY_SIZE(addr_len));
++ ret = regmap_bulk_write(map, PAGE0_SWAUX_ADDR_7_0, addr_len,
++ ARRAY_SIZE(addr_len));
++ if (ret) {
++ DRM_DEV_ERROR(dev,
++ "failed to write AUX address %#x, len %zu: %d\n",
++ msg->address, len, ret);
++ return ret;
++ }
+
+ if (len && (request == DP_AUX_NATIVE_WRITE ||
+ request == DP_AUX_I2C_WRITE)) {
+@@ -274,13 +280,22 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
+ }
+ }
+
+- regmap_write(map, PAGE0_SWAUX_CTRL, SWAUX_SEND);
++ ret = regmap_write(map, PAGE0_SWAUX_CTRL, SWAUX_SEND);
++ if (ret) {
++ DRM_DEV_ERROR(dev, "failed to start AUX transfer: %d\n", ret);
++ return ret;
++ }
+
+ /* Zero delay loop because i2c transactions are slow already */
+- regmap_read_poll_timeout(map, PAGE0_SWAUX_CTRL, data,
+- !(data & SWAUX_SEND), 0, 50 * 1000);
++ ret = regmap_read_poll_timeout(map, PAGE0_SWAUX_CTRL, data,
++ !(data & SWAUX_SEND), 0, 50 * 1000);
++ if (ret) {
++ DRM_DEV_ERROR(dev, "failed to complete AUX transfer: %d\n",
++ ret);
++ return ret;
++ }
+
+- regmap_read(map, PAGE0_SWAUX_STATUS, &data);
++ ret = regmap_read(map, PAGE0_SWAUX_STATUS, &data);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to read PAGE0_SWAUX_STATUS: %d\n",
+ ret);
+--
+2.53.0
+
--- /dev/null
+From 1865e71f3fb4885f01ec3ba8c92281d8bde935c4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 09:59:45 +0200
+Subject: drm/xe/uc: Apply RCS/CCS yield policy to SR-IOV VFs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
+
+[ Upstream commit d1643db3b037b57f2af7f85c3821d6fe69c492f6 ]
+
+VFs were missing the call to apply the global scheduling policy.
+Call xe_guc_submit_enable() during vf_uc_load_hw() to ensure VFs
+get the same policy enforcement as PF.
+
+Fixes: 26caeae9fb48 ("drm/xe/guc: Set RCS/CCS yield policy")
+Suggested-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
+Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
+Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Reviewed-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
+Link: https://patch.msgid.link/20260709075945.1337660-1-marcin.bernatowicz@linux.intel.com
+Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
+(cherry picked from commit f09360e857130f7ab7f069e2421e6b4a6e502531)
+Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_uc.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_uc.c b/drivers/gpu/drm/xe/xe_uc.c
+index 465bda3554439..b799efc838017 100644
+--- a/drivers/gpu/drm/xe/xe_uc.c
++++ b/drivers/gpu/drm/xe/xe_uc.c
+@@ -15,6 +15,7 @@
+ #include "xe_guc.h"
+ #include "xe_guc_pc.h"
+ #include "xe_guc_engine_activity.h"
++#include "xe_guc_submit.h"
+ #include "xe_huc.h"
+ #include "xe_sriov.h"
+ #include "xe_uc_fw.h"
+@@ -160,12 +161,14 @@ static int vf_uc_load_hw(struct xe_uc *uc)
+ if (err)
+ goto err_out;
+
+- uc->guc.submission_state.enabled = true;
+-
+ err = xe_guc_opt_in_features_enable(&uc->guc);
+ if (err)
+ goto err_out;
+
++ err = xe_guc_submit_enable(&uc->guc);
++ if (err)
++ return err;
++
+ err = xe_gt_record_default_lrcs(uc_to_gt(uc));
+ if (err)
+ goto err_out;
+--
+2.53.0
+
--- /dev/null
+From f411b21abd65a052fdac454837fb4120d4276142 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 23:26:30 -0700
+Subject: enic: fix tx_hang_reset use-after-free on device removal
+
+From: Satish Kharat <satishkh@cisco.com>
+
+[ Upstream commit ec680ea4ba1bca92a767fb7e7869758bfdd886e3 ]
+
+enic_remove() cancels the reset and change_mtu_work items but does not
+cancel tx_hang_reset. A TX timeout that fires while the device is being
+removed can schedule enic_tx_hang_reset() so that it runs after
+free_netdev(), resulting in a use-after-free.
+
+cancel_work_sync() alone is not sufficient here: the still-live watchdog
+and notify paths can re-schedule these work items in the window between
+the cancel and unregister_netdev(). Use disable_work_sync(), which
+cancels the work and blocks any subsequent schedule_work() from
+requeuing it, and apply it to the reset and change_mtu_work items as
+well so the same requeue race is closed for all teardown work.
+
+Fixes: 937317c7c109 ("enic: do hang reset only in case of tx timeout")
+Signed-off-by: Satish Kharat <satishkh@cisco.com>
+Link: https://patch.msgid.link/20260728062730.2394873-1-satishkh@cisco.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cisco/enic/enic_main.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
+index 6bc8dfdb3d4be..2a8b41d8eb883 100644
+--- a/drivers/net/ethernet/cisco/enic/enic_main.c
++++ b/drivers/net/ethernet/cisco/enic/enic_main.c
+@@ -2959,8 +2959,9 @@ static void enic_remove(struct pci_dev *pdev)
+ if (netdev) {
+ struct enic *enic = netdev_priv(netdev);
+
+- cancel_work_sync(&enic->reset);
+- cancel_work_sync(&enic->change_mtu_work);
++ disable_work_sync(&enic->reset);
++ disable_work_sync(&enic->tx_hang_reset);
++ disable_work_sync(&enic->change_mtu_work);
+ unregister_netdev(netdev);
+ enic_dev_deinit(enic);
+ vnic_dev_close(enic->vdev);
+--
+2.53.0
+
--- /dev/null
+From 38ccb00a12bf489e36975ecc880f154886b60d39 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 21 Apr 2025 15:28:11 -0700
+Subject: eth: bnxt: store rx buffer size per queue
+
+From: Pavel Begunkov <asml.silence@gmail.com>
+
+[ Upstream commit f57efb32aae1da5c0a25acf473ef4ab559894adf ]
+
+Instead of using a constant buffer length, allow configuring the size
+for each queue separately. There is no way to change the length yet, and
+it'll be passed from memory providers in a later patch.
+
+Suggested-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 56 +++++++++++--------
+ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
+ drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 6 +-
+ drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h | 2 +-
+ 4 files changed, 38 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index f3fbbf188053c..fddfdf807950f 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -905,7 +905,7 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
+
+ static bool bnxt_separate_head_pool(struct bnxt_rx_ring_info *rxr)
+ {
+- return rxr->need_head_pool || PAGE_SIZE > BNXT_RX_PAGE_SIZE;
++ return rxr->need_head_pool || rxr->rx_page_size < PAGE_SIZE;
+ }
+
+ static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping,
+@@ -915,9 +915,9 @@ static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping,
+ {
+ struct page *page;
+
+- if (PAGE_SIZE > BNXT_RX_PAGE_SIZE) {
++ if (rxr->rx_page_size < PAGE_SIZE) {
+ page = page_pool_dev_alloc_frag(rxr->page_pool, offset,
+- BNXT_RX_PAGE_SIZE);
++ rxr->rx_page_size);
+ } else {
+ page = page_pool_dev_alloc_pages(rxr->page_pool);
+ *offset = 0;
+@@ -936,8 +936,9 @@ static netmem_ref __bnxt_alloc_rx_netmem(struct bnxt *bp, dma_addr_t *mapping,
+ {
+ netmem_ref netmem;
+
+- if (PAGE_SIZE > BNXT_RX_PAGE_SIZE) {
+- netmem = page_pool_alloc_frag_netmem(rxr->page_pool, offset, BNXT_RX_PAGE_SIZE, gfp);
++ if (rxr->rx_page_size < PAGE_SIZE) {
++ netmem = page_pool_alloc_frag_netmem(rxr->page_pool, offset,
++ rxr->rx_page_size, gfp);
+ } else {
+ netmem = page_pool_alloc_netmems(rxr->page_pool, gfp);
+ *offset = 0;
+@@ -1155,9 +1156,9 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp,
+ return NULL;
+ }
+ dma_addr -= bp->rx_dma_offset;
+- dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, BNXT_RX_PAGE_SIZE,
++ dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, rxr->rx_page_size,
+ bp->rx_dir);
+- skb = napi_build_skb(data_ptr - bp->rx_offset, BNXT_RX_PAGE_SIZE);
++ skb = napi_build_skb(data_ptr - bp->rx_offset, rxr->rx_page_size);
+ if (!skb) {
+ page_pool_recycle_direct(rxr->page_pool, page);
+ return NULL;
+@@ -1189,7 +1190,7 @@ static struct sk_buff *bnxt_rx_page_skb(struct bnxt *bp,
+ return NULL;
+ }
+ dma_addr -= bp->rx_dma_offset;
+- dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, BNXT_RX_PAGE_SIZE,
++ dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, rxr->rx_page_size,
+ bp->rx_dir);
+
+ if (unlikely(!payload))
+@@ -1203,7 +1204,7 @@ static struct sk_buff *bnxt_rx_page_skb(struct bnxt *bp,
+
+ skb_mark_for_recycle(skb);
+ off = (void *)data_ptr - page_address(page);
+- skb_add_rx_frag(skb, 0, page, off, len, BNXT_RX_PAGE_SIZE);
++ skb_add_rx_frag(skb, 0, page, off, len, rxr->rx_page_size);
+ memcpy(skb->data - NET_IP_ALIGN, data_ptr - NET_IP_ALIGN,
+ payload + NET_IP_ALIGN);
+
+@@ -1288,7 +1289,7 @@ static u32 __bnxt_rx_agg_netmems(struct bnxt *bp,
+ if (skb) {
+ skb_add_rx_frag_netmem(skb, i, cons_rx_buf->netmem,
+ cons_rx_buf->offset,
+- frag_len, BNXT_RX_PAGE_SIZE);
++ frag_len, rxr->rx_page_size);
+ } else {
+ skb_frag_t *frag = &shinfo->frags[i];
+
+@@ -1313,7 +1314,7 @@ static u32 __bnxt_rx_agg_netmems(struct bnxt *bp,
+ if (skb) {
+ skb->len -= frag_len;
+ skb->data_len -= frag_len;
+- skb->truesize -= BNXT_RX_PAGE_SIZE;
++ skb->truesize -= rxr->rx_page_size;
+ }
+
+ --shinfo->nr_frags;
+@@ -1328,7 +1329,7 @@ static u32 __bnxt_rx_agg_netmems(struct bnxt *bp,
+ }
+
+ page_pool_dma_sync_netmem_for_cpu(rxr->page_pool, netmem, 0,
+- BNXT_RX_PAGE_SIZE);
++ rxr->rx_page_size);
+
+ total_frag_len += frag_len;
+ prod = NEXT_RX_AGG(prod);
+@@ -2295,8 +2296,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
+ if (!skb)
+ goto oom_next_rx;
+ } else {
+- skb = bnxt_xdp_build_skb(bp, skb, agg_bufs,
+- rxr->page_pool, &xdp);
++ skb = bnxt_xdp_build_skb(bp, skb, agg_bufs, rxr, &xdp);
+ if (!skb) {
+ /* we should be able to free the old skb here */
+ bnxt_xdp_buff_frags_free(rxr, &xdp);
+@@ -3844,11 +3844,13 @@ static int bnxt_alloc_rx_page_pool(struct bnxt *bp,
+ pp.pool_size = bp->rx_agg_ring_size / agg_size_fac;
+ if (BNXT_RX_PAGE_MODE(bp))
+ pp.pool_size += bp->rx_ring_size / rx_size_fac;
++
++ pp.order = get_order(rxr->rx_page_size);
+ pp.nid = numa_node;
+ pp.netdev = bp->dev;
+ pp.dev = &bp->pdev->dev;
+ pp.dma_dir = bp->rx_dir;
+- pp.max_len = PAGE_SIZE;
++ pp.max_len = PAGE_SIZE << pp.order;
+ pp.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV |
+ PP_FLAG_ALLOW_UNREADABLE_NETMEM;
+ pp.queue_idx = rxr->bnapi->index;
+@@ -3859,7 +3861,10 @@ static int bnxt_alloc_rx_page_pool(struct bnxt *bp,
+ rxr->page_pool = pool;
+
+ rxr->need_head_pool = page_pool_is_unreadable(pool);
++ rxr->need_head_pool |= !!pp.order;
+ if (bnxt_separate_head_pool(rxr)) {
++ pp.order = 0;
++ pp.max_len = PAGE_SIZE;
+ pp.pool_size = min(bp->rx_ring_size / rx_size_fac, 1024);
+ pp.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
+ pool = page_pool_create(&pp);
+@@ -4335,6 +4340,8 @@ static void bnxt_init_ring_struct(struct bnxt *bp)
+ if (!rxr)
+ goto skip_rx;
+
++ rxr->rx_page_size = BNXT_RX_PAGE_SIZE;
++
+ ring = &rxr->rx_ring_struct;
+ rmem = &ring->ring_mem;
+ rmem->nr_pages = bp->rx_nr_pages;
+@@ -4494,7 +4501,7 @@ static void bnxt_init_one_rx_agg_ring_rxbd(struct bnxt *bp,
+ ring = &rxr->rx_agg_ring_struct;
+ ring->fw_ring_id = INVALID_HW_RING_ID;
+ if ((bp->flags & BNXT_FLAG_AGG_RINGS)) {
+- type = ((u32)BNXT_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
++ type = ((u32)rxr->rx_page_size << RX_BD_LEN_SHIFT) |
+ RX_BD_TYPE_RX_AGG_BD;
+
+ /* On P7, setting EOP will cause the chip to disable
+@@ -7071,6 +7078,7 @@ static void bnxt_hwrm_ring_grp_free(struct bnxt *bp)
+
+ static void bnxt_set_rx_ring_params_p5(struct bnxt *bp, u32 ring_type,
+ struct hwrm_ring_alloc_input *req,
++ struct bnxt_rx_ring_info *rxr,
+ struct bnxt_ring_struct *ring)
+ {
+ struct bnxt_ring_grp_info *grp_info = &bp->grp_info[ring->grp_idx];
+@@ -7080,7 +7088,7 @@ static void bnxt_set_rx_ring_params_p5(struct bnxt *bp, u32 ring_type,
+ if (ring_type == HWRM_RING_ALLOC_AGG) {
+ req->ring_type = RING_ALLOC_REQ_RING_TYPE_RX_AGG;
+ req->rx_ring_id = cpu_to_le16(grp_info->rx_fw_ring_id);
+- req->rx_buf_size = cpu_to_le16(BNXT_RX_PAGE_SIZE);
++ req->rx_buf_size = cpu_to_le16(rxr->rx_page_size);
+ enables |= RING_ALLOC_REQ_ENABLES_RX_RING_ID_VALID;
+ } else {
+ req->rx_buf_size = cpu_to_le16(bp->rx_buf_use_size);
+@@ -7094,6 +7102,7 @@ static void bnxt_set_rx_ring_params_p5(struct bnxt *bp, u32 ring_type,
+ }
+
+ static int hwrm_ring_alloc_send_msg(struct bnxt *bp,
++ struct bnxt_rx_ring_info *rxr,
+ struct bnxt_ring_struct *ring,
+ u32 ring_type, u32 map_index)
+ {
+@@ -7150,7 +7159,8 @@ static int hwrm_ring_alloc_send_msg(struct bnxt *bp,
+ cpu_to_le32(bp->rx_ring_mask + 1) :
+ cpu_to_le32(bp->rx_agg_ring_mask + 1);
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
+- bnxt_set_rx_ring_params_p5(bp, ring_type, req, ring);
++ bnxt_set_rx_ring_params_p5(bp, ring_type, req,
++ rxr, ring);
+ break;
+ case HWRM_RING_ALLOC_CMPL:
+ req->ring_type = RING_ALLOC_REQ_RING_TYPE_L2_CMPL;
+@@ -7298,7 +7308,7 @@ static int bnxt_hwrm_rx_ring_alloc(struct bnxt *bp,
+ u32 map_idx = bnapi->index;
+ int rc;
+
+- rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx);
++ rc = hwrm_ring_alloc_send_msg(bp, rxr, ring, type, map_idx);
+ if (rc)
+ return rc;
+
+@@ -7318,7 +7328,7 @@ static int bnxt_hwrm_rx_agg_ring_alloc(struct bnxt *bp,
+ int rc;
+
+ map_idx = grp_idx + bp->rx_nr_rings;
+- rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx);
++ rc = hwrm_ring_alloc_send_msg(bp, rxr, ring, type, map_idx);
+ if (rc)
+ return rc;
+
+@@ -7342,7 +7352,7 @@ static int bnxt_hwrm_cp_ring_alloc_p5(struct bnxt *bp,
+
+ ring = &cpr->cp_ring_struct;
+ ring->handle = BNXT_SET_NQ_HDL(cpr);
+- rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx);
++ rc = hwrm_ring_alloc_send_msg(bp, NULL, ring, type, map_idx);
+ if (rc)
+ return rc;
+ bnxt_set_db(bp, &cpr->cp_db, type, map_idx, ring->fw_ring_id);
+@@ -7357,7 +7367,7 @@ static int bnxt_hwrm_tx_ring_alloc(struct bnxt *bp,
+ const u32 type = HWRM_RING_ALLOC_TX;
+ int rc;
+
+- rc = hwrm_ring_alloc_send_msg(bp, ring, type, tx_idx);
++ rc = hwrm_ring_alloc_send_msg(bp, NULL, ring, type, tx_idx);
+ if (rc)
+ return rc;
+ bnxt_set_db(bp, &txr->tx_db, type, tx_idx, ring->fw_ring_id);
+@@ -7383,7 +7393,7 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
+
+ vector = bp->irq_tbl[map_idx].vector;
+ disable_irq_nosync(vector);
+- rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx);
++ rc = hwrm_ring_alloc_send_msg(bp, NULL, ring, type, map_idx);
+ if (rc) {
+ enable_irq(vector);
+ goto err_out;
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+index b140799f07d69..9a1be6b71219d 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+@@ -1105,6 +1105,7 @@ struct bnxt_rx_ring_info {
+
+ unsigned long *rx_agg_bmap;
+ u16 rx_agg_bmap_size;
++ u32 rx_page_size;
+ bool need_head_pool;
+
+ dma_addr_t rx_desc_mapping[MAX_RX_PAGES];
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
+index c94a391b1ba5b..85cbeb35681c2 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
+@@ -183,7 +183,7 @@ void bnxt_xdp_buff_init(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
+ u16 cons, u8 *data_ptr, unsigned int len,
+ struct xdp_buff *xdp)
+ {
+- u32 buflen = BNXT_RX_PAGE_SIZE;
++ u32 buflen = rxr->rx_page_size;
+ struct bnxt_sw_rx_bd *rx_buf;
+ struct pci_dev *pdev;
+ dma_addr_t mapping;
+@@ -460,7 +460,7 @@ int bnxt_xdp(struct net_device *dev, struct netdev_bpf *xdp)
+
+ struct sk_buff *
+ bnxt_xdp_build_skb(struct bnxt *bp, struct sk_buff *skb, u8 num_frags,
+- struct page_pool *pool, struct xdp_buff *xdp)
++ struct bnxt_rx_ring_info *rxr, struct xdp_buff *xdp)
+ {
+ struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
+
+@@ -468,7 +468,7 @@ bnxt_xdp_build_skb(struct bnxt *bp, struct sk_buff *skb, u8 num_frags,
+ return NULL;
+
+ xdp_update_skb_frags_info(skb, num_frags, sinfo->xdp_frags_size,
+- BNXT_RX_PAGE_SIZE * num_frags,
++ rxr->rx_page_size * num_frags,
+ xdp_buff_get_skb_flags(xdp));
+ return skb;
+ }
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h
+index 220285e190fcd..8933a0dec09a6 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h
+@@ -32,6 +32,6 @@ void bnxt_xdp_buff_init(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
+ void bnxt_xdp_buff_frags_free(struct bnxt_rx_ring_info *rxr,
+ struct xdp_buff *xdp);
+ struct sk_buff *bnxt_xdp_build_skb(struct bnxt *bp, struct sk_buff *skb,
+- u8 num_frags, struct page_pool *pool,
++ u8 num_frags, struct bnxt_rx_ring_info *rxr,
+ struct xdp_buff *xdp);
+ #endif
+--
+2.53.0
+
--- /dev/null
+From a59a81103a6acf1ab7301d46ab0dc041cb976384 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Oct 2025 23:10:32 +0100
+Subject: eth: bnxt: support qcfg provided rx page size
+
+From: Pavel Begunkov <asml.silence@gmail.com>
+
+[ Upstream commit f96e1b35779e153be266fd7de50bda0c5553ad21 ]
+
+Implement support for qcfg provided rx page sizes. For that, implement
+the ndo_default_qcfg callback and validate the config on restart. Also,
+use the current config's value in bnxt_init_ring_struct to retain the
+correct size across resets.
+
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 36 ++++++++++++++++++++++-
+ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
+ 2 files changed, 36 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index fddfdf807950f..52b356f4966ab 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -4323,6 +4323,7 @@ static void bnxt_init_ring_struct(struct bnxt *bp)
+ struct bnxt_rx_ring_info *rxr;
+ struct bnxt_tx_ring_info *txr;
+ struct bnxt_ring_struct *ring;
++ struct netdev_rx_queue *rxq;
+
+ if (!bnapi)
+ continue;
+@@ -4340,7 +4341,8 @@ static void bnxt_init_ring_struct(struct bnxt *bp)
+ if (!rxr)
+ goto skip_rx;
+
+- rxr->rx_page_size = BNXT_RX_PAGE_SIZE;
++ rxq = __netif_get_rx_queue(bp->dev, i);
++ rxr->rx_page_size = rxq->qcfg.rx_page_size;
+
+ ring = &rxr->rx_ring_struct;
+ rmem = &ring->ring_mem;
+@@ -15964,6 +15966,29 @@ static const struct netdev_stat_ops bnxt_stat_ops = {
+ .get_base_stats = bnxt_get_base_stats,
+ };
+
++static void bnxt_queue_default_qcfg(struct net_device *dev,
++ struct netdev_queue_config *qcfg)
++{
++ qcfg->rx_page_size = BNXT_RX_PAGE_SIZE;
++}
++
++static int bnxt_validate_qcfg(struct bnxt *bp, struct netdev_queue_config *qcfg)
++{
++ /* Older chips need MSS calc so rx_page_size is not supported */
++ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS) &&
++ qcfg->rx_page_size != BNXT_RX_PAGE_SIZE)
++ return -EINVAL;
++
++ if (!is_power_of_2(qcfg->rx_page_size))
++ return -ERANGE;
++
++ if (qcfg->rx_page_size < BNXT_RX_PAGE_SIZE ||
++ qcfg->rx_page_size > BNXT_MAX_RX_PAGE_SIZE)
++ return -ERANGE;
++
++ return 0;
++}
++
+ static int bnxt_queue_mem_alloc(struct net_device *dev,
+ struct netdev_queue_config *qcfg,
+ void *qmem, int idx)
+@@ -15976,6 +16001,10 @@ static int bnxt_queue_mem_alloc(struct net_device *dev,
+ if (!bp->rx_ring)
+ return -ENETDOWN;
+
++ rc = bnxt_validate_qcfg(bp, qcfg);
++ if (rc < 0)
++ return rc;
++
+ rxr = &bp->rx_ring[idx];
+ clone = qmem;
+ memcpy(clone, rxr, sizeof(*rxr));
+@@ -15987,6 +16016,7 @@ static int bnxt_queue_mem_alloc(struct net_device *dev,
+ clone->rx_sw_agg_prod = 0;
+ clone->rx_next_cons = 0;
+ clone->need_head_pool = false;
++ clone->rx_page_size = qcfg->rx_page_size;
+
+ rc = bnxt_alloc_rx_page_pool(bp, clone, rxr->page_pool->p.nid);
+ if (rc)
+@@ -16113,6 +16143,8 @@ static void bnxt_copy_rx_ring(struct bnxt *bp,
+ src_ring = &src->rx_agg_ring_struct;
+ src_rmem = &src_ring->ring_mem;
+
++ dst->rx_page_size = src->rx_page_size;
++
+ WARN_ON(dst_rmem->nr_pages != src_rmem->nr_pages);
+ WARN_ON(dst_rmem->page_size != src_rmem->page_size);
+ WARN_ON(dst_rmem->flags != src_rmem->flags);
+@@ -16267,6 +16299,8 @@ static const struct netdev_queue_mgmt_ops bnxt_queue_mgmt_ops = {
+ .ndo_queue_mem_free = bnxt_queue_mem_free,
+ .ndo_queue_start = bnxt_queue_start,
+ .ndo_queue_stop = bnxt_queue_stop,
++ .ndo_default_qcfg = bnxt_queue_default_qcfg,
++ .supported_params = QCFG_RX_PAGE_SIZE,
+ };
+
+ static void bnxt_remove_one(struct pci_dev *pdev)
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+index 9a1be6b71219d..3ca989da0eb02 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+@@ -760,6 +760,7 @@ struct nqe_cn {
+ #endif
+
+ #define BNXT_RX_PAGE_SIZE (1 << BNXT_RX_PAGE_SHIFT)
++#define BNXT_MAX_RX_PAGE_SIZE BIT(15)
+
+ #define BNXT_MAX_MTU 9500
+
+--
+2.53.0
+
--- /dev/null
+From 05573f9cac201179c53b2a5fa41a294b66a6f649 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:16:45 +0800
+Subject: hwmon: (ads7828) Fix external VREF regulator handling
+
+From: Qingshuang Fu <fuqingshuang@kylinos.cn>
+
+[ Upstream commit fddb5ceaf901b050ed2a1a7deeecbf97e003435a ]
+
+The driver currently has two issues with the external VREF regulator
+handling in ads7828_probe():
+
+1. All errors from devm_regulator_get_optional() are ignored, causing the
+ driver to incorrectly fall back to internal VREF even for transient
+ errors like -EPROBE_DEFER or genuine failures like -ENOMEM.
+
+2. The external regulator is never enabled. The driver calls
+ regulator_get_voltage() without first calling regulator_enable(),
+ so the VREF pin may remain unpowered if the regulator is not
+ configured as always-on.
+
+Fix both issues by switching to devm_regulator_get_enable_read_voltage(),
+which handles regulator get, enable, and voltage read in one call.
+Only -ENODEV (no regulator specified in device tree) should trigger the
+fallback to internal VREF. All other errors are propagated to the caller.
+
+Fixes: a8ddfea09566 ("hwmon: (ads7828) Accept optional parameters from device tree")
+Signed-off-by: Qingshuang Fu <fuqingshuang@kylinos.cn>
+Link: https://lore.kernel.org/r/20260805061645.1331652-1-fffsqian@163.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ads7828.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
+index 436637264056c..20ef4992f5bb8 100644
+--- a/drivers/hwmon/ads7828.c
++++ b/drivers/hwmon/ads7828.c
+@@ -106,12 +106,11 @@ static int ads7828_probe(struct i2c_client *client)
+ struct ads7828_data *data;
+ struct device *hwmon_dev;
+ unsigned int vref_mv = ADS7828_INT_VREF_MV;
+- unsigned int vref_uv;
++ int vref_uv;
+ bool diff_input = false;
+ bool ext_vref = false;
+ unsigned int regval;
+ enum ads7828_chips chip;
+- struct regulator *reg;
+
+ data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL);
+ if (!data)
+@@ -125,9 +124,11 @@ static int ads7828_probe(struct i2c_client *client)
+ } else if (dev->of_node) {
+ diff_input = of_property_read_bool(dev->of_node,
+ "ti,differential-input");
+- reg = devm_regulator_get_optional(dev, "vref");
+- if (!IS_ERR(reg)) {
+- vref_uv = regulator_get_voltage(reg);
++ vref_uv = devm_regulator_get_enable_read_voltage(dev, "vref");
++ if (vref_uv < 0) {
++ if (vref_uv != -ENODEV)
++ return vref_uv;
++ } else {
+ vref_mv = DIV_ROUND_CLOSEST(vref_uv, 1000);
+ if (vref_mv < ADS7828_EXT_VREF_MV_MIN ||
+ vref_mv > ADS7828_EXT_VREF_MV_MAX)
+--
+2.53.0
+
--- /dev/null
+From 8d6687b405b9c2caa6341e1dfc81bf7dc2f47e59 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 07:19:20 +0000
+Subject: hwmon: (corsair-psu) fix possible out-of-bounds access on missing
+ string termination
+
+From: Wilken Gottwalt <wilken.gottwalt@posteo.net>
+
+[ Upstream commit 36c4d73ce05d1d8896c2669eb0730d35a02a2ec1 ]
+
+In theory it could be possible that the REPLY_SIZE sized buffers for
+holding the vendor and product strings could be end up missing the null
+termination (for example by malicious hardware built on purpose)
+required by the seq_printf() call. That limits the debugfs printf calls
+to a maximum string length of REPLY_SIZE.
+
+Fixes: d115b51e0e567 ("hwmon: add Corsair PSU HID controller driver")
+Signed-off-by: Wilken Gottwalt <wilken.gottwalt@posteo.net>
+Link: https://lore.kernel.org/r/anLj9gPWRoRDbQBV@monster.localdomain
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/corsair-psu.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c
+index 4681af6843596..679fb30983465 100644
+--- a/drivers/hwmon/corsair-psu.c
++++ b/drivers/hwmon/corsair-psu.c
+@@ -709,7 +709,7 @@ static int vendor_show(struct seq_file *seqf, void *unused)
+ {
+ struct corsairpsu_data *priv = seqf->private;
+
+- seq_printf(seqf, "%s\n", priv->vendor);
++ seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->vendor);
+
+ return 0;
+ }
+@@ -719,7 +719,7 @@ static int product_show(struct seq_file *seqf, void *unused)
+ {
+ struct corsairpsu_data *priv = seqf->private;
+
+- seq_printf(seqf, "%s\n", priv->product);
++ seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->product);
+
+ return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From 26b682eeccf8c3539e863f0ef97e32a5f01b5d10 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 15:42:42 -0700
+Subject: hwmon: (ltc4282) Avoid overflow in maximum power calculation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit edd11a94335747423569500a194c6eaa915f2963 ]
+
+During device initialization in ltc4282_set_max_limits(), the calculation
+of the maximum power limit can suffer from a 32-bit integer overflow.
+
+static int ltc4282_set_max_limits(struct ltc4282_state *st)
+{
+ ...
+ st->power_max = DIV_ROUND_CLOSEST(st->vsense_max * DECA * MILLI,
+ st->rsense) * st->vfs_out;
+ ...
+}
+
+The result of DIV_ROUND_CLOSEST() evaluates to a 32-bit unsigned integer
+on 32-bit architectures. This result is then multiplied by st->vfs_out,
+which is a 16-bit unsigned integer. According to C promotion rules, since
+both operands are 32-bit or smaller, the multiplication is performed in
+32-bit precision.
+
+If the device is configured with a low sense resistor value via the device
+tree (for example, 100 nano-ohms, resulting in st->rsense = 1) and the
+voltage is high, the division result can reach 343,750,000 and st->vfs_out
+can be 33,280. The product of these values is approximately 11.44 trillion,
+which exceeds the maximum capacity of a 32-bit integer and overflows
+before being stored in st->power_max.
+
+This overflow causes a truncated value to be assigned to st->power_max and
+written to the hardware limit register. An incorrect maximum power limit
+can trigger spurious power-bad faults or alarms, which may lead to the
+shutdown of the monitored power rail.
+
+Avoid the problem by calculating and storing the maximum power using 64-bit
+variables.
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282")
+Cc: Nuno Sa <nuno.sa@analog.com>
+Reviewed-by: Nuno Sá <nuno.sa@analog.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ltc4282.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c
+index 4000bcbc7353d..e5ea1db83da47 100644
+--- a/drivers/hwmon/ltc4282.c
++++ b/drivers/hwmon/ltc4282.c
+@@ -142,7 +142,7 @@ struct ltc4282_state {
+ */
+ struct ltc4282_cache in0_1_cache[LTC4282_CHAN_VGPIO];
+ u32 vsense_max;
+- long power_max;
++ s64 power_max;
+ u32 rsense;
+ u16 vdd;
+ u16 vfs_out;
+@@ -623,13 +623,12 @@ static int ltc4282_read(struct device *dev, enum hwmon_sensor_types type,
+ }
+
+ static int ltc4282_write_power_byte(const struct ltc4282_state *st, u32 reg,
+- long val)
++ s64 val)
+ {
+ u32 power;
+ u64 temp;
+
+- if (val > st->power_max)
+- val = st->power_max;
++ val = clamp(val, 0, st->power_max);
+
+ temp = val * int_pow(U8_MAX, 2) * st->rsense;
+ power = DIV64_U64_ROUND_CLOSEST(temp,
+@@ -639,7 +638,7 @@ static int ltc4282_write_power_byte(const struct ltc4282_state *st, u32 reg,
+ }
+
+ static int ltc4282_write_power_word(const struct ltc4282_state *st, u32 reg,
+- long val)
++ u64 val)
+ {
+ u64 temp = int_pow(U16_MAX, 2) * st->rsense, temp_2;
+ __be16 __raw;
+@@ -1256,7 +1255,8 @@ static int ltc4282_set_max_limits(struct ltc4282_state *st)
+ return ret;
+
+ /* Power is given by ISENSE * Vout. */
+- st->power_max = DIV_ROUND_CLOSEST(st->vsense_max * DECA * MILLI, st->rsense) * st->vfs_out;
++ st->power_max = DIV_ROUND_CLOSEST_ULL((u64)st->vsense_max * DECA * MILLI,
++ st->rsense) * st->vfs_out;
+ ret = ltc4282_write_power_byte(st, LTC4282_POWER_MAX, st->power_max);
+ if (ret)
+ return ret;
+--
+2.53.0
+
--- /dev/null
+From 448377d436425cf61b5ddbcc1d7e2823d0ec6f0f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 16:26:05 -0700
+Subject: hwmon: (ltc4282) Clamp negative current limits
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit e253dd5f9f6d875a317895bf43ec9534ed7523cb ]
+
+When a negative value is passed to ltc4282_write_curr(), the signed long
+val is cast directly to u64:
+
+drivers/hwmon/ltc4282.c:ltc4282_write_curr() {
+ /* need to pass it in millivolt */
+ u32 in = DIV_ROUND_CLOSEST_ULL((u64)val * st->rsense, DECA * MICRO);
+ ...
+}
+
+This cast converts negative inputs into large positive values. The
+subsequent division result overflows the u32 in variable, truncating
+to a pseudo-random positive value. When this is passed to
+ltc4282_write_voltage_byte(), it is clamped to the maximum limit instead
+of zero.
+
+Clamp val to 0 and to the maximum supported upper limit before the cast
+and assign the result to a 64-bit temporary variable before the division
+to avoid the underflow and an also possible overflow.
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282")
+Cc: Nuno Sa <nuno.sa@analog.com>
+Reviewed-by: Nuno Sá <nuno.sa@analog.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ltc4282.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c
+index e5ea1db83da47..b45a6e128d32e 100644
+--- a/drivers/hwmon/ltc4282.c
++++ b/drivers/hwmon/ltc4282.c
+@@ -15,6 +15,7 @@
+ #include <linux/hwmon-sysfs.h>
+ #include <linux/i2c.h>
+ #include <linux/math.h>
++#include <linux/math64.h>
+ #include <linux/minmax.h>
+ #include <linux/module.h>
+ #include <linux/mod_devicetable.h>
+@@ -947,8 +948,11 @@ static int ltc4282_curr_reset_hist(struct ltc4282_state *st)
+ static int ltc4282_write_curr(struct ltc4282_state *st, u32 attr,
+ long val)
+ {
++ s32 ulimit = min_t(u64, INT_MAX,
++ div_u64((u64)INT_MAX * DECA * MICRO, st->rsense));
++ u64 val64 = clamp(val, 0, ulimit);
+ /* need to pass it in millivolt */
+- u32 in = DIV_ROUND_CLOSEST_ULL((u64)val * st->rsense, DECA * MICRO);
++ u32 in = DIV_ROUND_CLOSEST_ULL(val64 * st->rsense, DECA * MICRO);
+
+ switch (attr) {
+ case hwmon_curr_max:
+--
+2.53.0
+
--- /dev/null
+From 2e61ebc39d33c9c30c0e57215677414ba53634ec Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 17:30:42 -0700
+Subject: hwmon: (ltc4282) Fix parsing adi,current-limit-sense-microvolt
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit 335698fd7f60b6707b21fda725f97f35fa956b07 ]
+
+ltc4282_parse_dt() evaluates the wrong variable when parsing the current
+limit.
+
+When the adi,current-limit-sense-microvolt property is parsed into
+st->vsense_max, the subsequent switch statement evaluates the unrelated
+val variable instead of st->vsense_max:
+
+drivers/hwmon/ltc4282.c:ltc4282_parse_dt() {
+ ...
+ ret = device_property_read_u32(dev, "adi,current-limit-sense-microvolt",
+ &st->vsense_max);
+ if (!ret) {
+ int reg_val;
+
+ switch (val) {
+ case 12500:
+ reg_val = 0;
+ break;
+ ...
+}
+
+Because val holds a small integer representing vin_mode (from 0 to 3), it
+never matches any of the valid current limit cases.
+
+This causes it to always fall through to the default error case, return
+-EINVAL, and aborts probe initialization for any device tree using this
+property.
+
+Validate st->vsense_max instead to fix the problem.
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282")
+Cc: Nuno Sa <nuno.sa@analog.com>
+Reviewed-by: Nuno Sá <nuno.sa@analog.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ltc4282.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c
+index b45a6e128d32e..269f96738f5b3 100644
+--- a/drivers/hwmon/ltc4282.c
++++ b/drivers/hwmon/ltc4282.c
+@@ -1427,7 +1427,7 @@ static int ltc4282_setup(struct ltc4282_state *st, struct device *dev)
+ if (!ret) {
+ int reg_val;
+
+- switch (val) {
++ switch (st->vsense_max) {
+ case 12500:
+ reg_val = 0;
+ break;
+--
+2.53.0
+
--- /dev/null
+From 44b774092b414caeb155a01a7502fcf314c31595 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 15:48:42 +0800
+Subject: hwmon: (nzxt-smart2) Check return value of init_device() in probe
+
+From: Qingshuang Fu <fuqingshuang@kylinos.cn>
+
+[ Upstream commit d533882ce1060866a590257f2c77ee23eabef5b8 ]
+
+The init_device() call in nzxt_smart2_hid_probe() can fail because it
+sends HID output reports to the hardware to detect fans and set the
+update interval. If the hardware is not responding or the HID reports
+fail, init_device() returns a negative error code.
+
+However, the return value was ignored, causing the probe to continue
+and register an hwmon device even though the device was never properly
+initialized. This leads to an inconsistent state where the driver
+reports stale data or blocks on wait queues that will never be woken.
+
+The same function's return value is already checked in the
+reset_resume() handler, confirming the author's intent that errors
+should be propagated.
+
+Note that this fix was not possible before commit 59d104b54b0b
+("hwmon: (nzxt-smart2) Stop device IO before calling hid_hw_stop")
+because the out_hw_close error path was missing hid_device_io_stop(),
+which would have opened a use-after-free risk window.
+
+Fixes: 53e68c20aeb1 ("hwmon: add driver for NZXT RGB&Fan Controller/Smart Device v2.")
+Signed-off-by: Qingshuang Fu <fuqingshuang@kylinos.cn>
+Link: https://lore.kernel.org/r/20260804074842.505923-1-fffsqian@163.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/nzxt-smart2.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/nzxt-smart2.c b/drivers/hwmon/nzxt-smart2.c
+index ff0c0bee0e839..efc78a8f58c88 100644
+--- a/drivers/hwmon/nzxt-smart2.c
++++ b/drivers/hwmon/nzxt-smart2.c
+@@ -754,7 +754,11 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev,
+
+ hid_device_io_start(hdev);
+
+- init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS);
++ ret = init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS);
++ if (ret) {
++ dev_err(&hdev->dev, "init_device failed: %d\n", ret);
++ goto out_hw_close;
++ }
+
+ drvdata->hwmon =
+ hwmon_device_register_with_info(&hdev->dev, "nzxtsmart2", drvdata,
+--
+2.53.0
+
--- /dev/null
+From be4c8782c47bbeb107212621f1f7ec2ea28590a5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jul 2026 10:57:35 -0700
+Subject: hwmon: (pmbus) Fix type confusion in notification logic
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit 59bd68ab05a8f9c9a60b6ec44682084184803ff4 ]
+
+Sashiko reports:
+
+At the start of the loop in pmbus_notify(), the code unconditionally casts
+every attribute to a struct sensor_device_attribute:
+
+drivers/hwmon/pmbus/pmbus_core.c:pmbus_notify() {
+ for (i = 0; i < data->num_attributes; i++) {
+ struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int index = attr->index;
+...
+}
+
+However, data->group.attrs can contain other types like struct
+pmbus_samples_reg or struct pmbus_sensor, which only embed a base
+struct device_attribute.
+
+If da is a struct pmbus_samples_reg, dev_attr is the last member. Casting
+it to struct sensor_device_attribute and reading the index field appears
+to access memory past the end of the allocation, which might trigger a
+slab-out-of-bounds read.
+
+Additionally, if da is a struct pmbus_sensor, casting it causes the index
+field to overlap with the page, phase, and reg fields. Could this produce
+a garbage mask on little-endian systems that spuriously matches the target
+reg, page, and flags during an alert?
+
+Fix the problem by using struct sensor_device_attr in struct pmbus_sensor
+and struct pmbus_label. Since those attributes never trigger a
+notification, set the value of attr->index to -1 for them. Use this value
+to distinguish from boolean attributes which _can_ trigger a notification
+and use the index field to encode mask, page, and register values.
+
+Fixes: f469bde9afd1 ("hwmon: (pmbus/core) Notify hwmon events")
+Cc: Vincent Jardin <vjardin@free.fr>
+Tested-by: Vincent Jardin <vjardin@free.fr>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/pmbus/pmbus_core.c | 61 +++++++++++++++++++-------------
+ 1 file changed, 37 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
+index a95ffd563018d..20a26db668940 100644
+--- a/drivers/hwmon/pmbus/pmbus_core.c
++++ b/drivers/hwmon/pmbus/pmbus_core.c
+@@ -46,7 +46,7 @@ module_param(wp, int, 0444);
+ struct pmbus_sensor {
+ struct pmbus_sensor *next;
+ char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */
+- struct device_attribute attribute;
++ struct sensor_device_attribute attribute;
+ u8 page; /* page number */
+ u8 phase; /* phase number, 0xff for all phases */
+ u16 reg; /* register */
+@@ -69,7 +69,7 @@ struct pmbus_boolean {
+
+ struct pmbus_label {
+ char name[PMBUS_NAME_SIZE]; /* sysfs label name */
+- struct device_attribute attribute;
++ struct sensor_device_attribute attribute;
+ char label[PMBUS_NAME_SIZE]; /* label */
+ };
+ #define to_pmbus_label(_attr) \
+@@ -1218,7 +1218,8 @@ static ssize_t pmbus_show_sensor(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+ {
+ struct i2c_client *client = to_i2c_client(dev->parent);
+- struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ struct pmbus_sensor *sensor = to_pmbus_sensor(attr);
+ struct pmbus_data *data = i2c_get_clientdata(client);
+ s64 val;
+
+@@ -1238,7 +1239,8 @@ static ssize_t pmbus_set_sensor(struct device *dev,
+ {
+ struct i2c_client *client = to_i2c_client(dev->parent);
+ struct pmbus_data *data = i2c_get_clientdata(client);
+- struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ struct pmbus_sensor *sensor = to_pmbus_sensor(attr);
+ s64 val;
+ int ret;
+ u16 regval;
+@@ -1260,7 +1262,8 @@ static ssize_t pmbus_set_sensor(struct device *dev,
+ static ssize_t pmbus_show_label(struct device *dev,
+ struct device_attribute *da, char *buf)
+ {
+- struct pmbus_label *label = to_pmbus_label(da);
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
++ struct pmbus_label *label = to_pmbus_label(attr);
+
+ return sysfs_emit(buf, "%s\n", label->label);
+ }
+@@ -1413,8 +1416,8 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
+ bool update, bool readonly,
+ bool writeonly, bool convert)
+ {
++ struct sensor_device_attribute *a;
+ struct pmbus_sensor *sensor;
+- struct device_attribute *a;
+
+ sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
+@@ -1438,12 +1441,11 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
+ sensor->update = update;
+ sensor->convert = convert;
+ sensor->data = -ENODATA;
+- pmbus_dev_attr_init(a, sensor->name,
+- readonly ? 0444 : 0644,
+- writeonly ? pmbus_show_zero : pmbus_show_sensor,
+- pmbus_set_sensor);
++ pmbus_attr_init(a, sensor->name, readonly ? 0444 : 0644,
++ writeonly ? pmbus_show_zero : pmbus_show_sensor,
++ pmbus_set_sensor, -1);
+
+- if (pmbus_add_attribute(data, &a->attr))
++ if (pmbus_add_attribute(data, &a->dev_attr.attr))
+ return NULL;
+
+ sensor->next = data->sensors;
+@@ -1460,8 +1462,8 @@ static int pmbus_add_label(struct pmbus_data *data,
+ const char *name, int seq,
+ const char *lstring, int index, int phase)
+ {
++ struct sensor_device_attribute *a;
+ struct pmbus_label *label;
+- struct device_attribute *a;
+
+ label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL);
+ if (!label)
+@@ -1485,8 +1487,8 @@ static int pmbus_add_label(struct pmbus_data *data,
+ lstring, index, phase);
+ }
+
+- pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL);
+- return pmbus_add_attribute(data, &a->attr);
++ pmbus_attr_init(a, label->name, 0444, pmbus_show_label, NULL, -1);
++ return pmbus_add_attribute(data, &a->dev_attr.attr);
+ }
+
+ /*
+@@ -2374,7 +2376,7 @@ struct pmbus_samples_attr {
+ struct pmbus_samples_reg {
+ int page;
+ struct pmbus_samples_attr *attr;
+- struct device_attribute dev_attr;
++ struct sensor_device_attribute attribute;
+ };
+
+ static struct pmbus_samples_attr pmbus_samples_registers[] = {
+@@ -2396,14 +2398,15 @@ static struct pmbus_samples_attr pmbus_samples_registers[] = {
+ }
+ };
+
+-#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, dev_attr)
++#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, attribute)
+
+ static ssize_t pmbus_show_samples(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+ {
+ int val;
+ struct i2c_client *client = to_i2c_client(dev->parent);
+- struct pmbus_samples_reg *reg = to_samples_reg(devattr);
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ struct pmbus_samples_reg *reg = to_samples_reg(attr);
+
+ scoped_guard(pmbus_lock, client) {
+ val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg);
+@@ -2421,7 +2424,8 @@ static ssize_t pmbus_set_samples(struct device *dev,
+ int ret;
+ long val;
+ struct i2c_client *client = to_i2c_client(dev->parent);
+- struct pmbus_samples_reg *reg = to_samples_reg(devattr);
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ struct pmbus_samples_reg *reg = to_samples_reg(attr);
+
+ if (kstrtol(buf, 0, &val) < 0)
+ return -EINVAL;
+@@ -2436,6 +2440,7 @@ static ssize_t pmbus_set_samples(struct device *dev,
+ static int pmbus_add_samples_attr(struct pmbus_data *data, int page,
+ struct pmbus_samples_attr *attr)
+ {
++ struct sensor_device_attribute *a;
+ struct pmbus_samples_reg *reg;
+
+ reg = devm_kzalloc(data->dev, sizeof(*reg), GFP_KERNEL);
+@@ -2445,10 +2450,12 @@ static int pmbus_add_samples_attr(struct pmbus_data *data, int page,
+ reg->attr = attr;
+ reg->page = page;
+
+- pmbus_dev_attr_init(®->dev_attr, attr->name, 0644,
+- pmbus_show_samples, pmbus_set_samples);
++ a = ®->attribute;
++
++ pmbus_attr_init(a, attr->name, 0644,
++ pmbus_show_samples, pmbus_set_samples, -1);
+
+- return pmbus_add_attribute(data, ®->dev_attr.attr);
++ return pmbus_add_attribute(data, &a->dev_attr.attr);
+ }
+
+ static int pmbus_add_samples_attributes(struct i2c_client *client,
+@@ -2956,9 +2963,15 @@ static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags)
+ struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int index = attr->index;
+- u16 smask = pb_index_to_mask(index);
+- u8 spage = pb_index_to_page(index);
+- u16 sreg = pb_index_to_reg(index);
++ u16 smask, sreg;
++ u8 spage;
++
++ if (index == -1)
++ continue;
++
++ smask = pb_index_to_mask(index);
++ spage = pb_index_to_page(index);
++ sreg = pb_index_to_reg(index);
+
+ if (reg == sreg && page == spage && (smask & flags)) {
+ dev_dbg(data->dev, "sysfs notify: %s", da->attr.name);
+--
+2.53.0
+
--- /dev/null
+From 21c8dbd4d0f82468f8825dd772f74951d344f1d1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 14:12:31 -0700
+Subject: hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit 0dabe8a56f772f0ece46d2597799f412c277d874 ]
+
+In lm25066_probe(), the PMBus coefficients for current and power are
+scaled based on the shunt resistor value. The calculation evaluates the
+multiplication using 32-bit arithmetic because info->m is an int and
+shunt is a u32:
+
+static int lm25066_probe(struct i2c_client *client) {
+ ...
+ info->m[PSC_CURRENT_IN] = info->m[PSC_CURRENT_IN] * shunt / 1000;
+ info->m[PSC_POWER] = info->m[PSC_POWER] * shunt / 1000;
+ ...
+}
+
+For large coefficients like 26882 (LM25056) or 15076 (LM5066i), a device
+tree shunt-resistor-micro-ohms value exceeding approximately 159,000
+(159 mOhm, which is physically valid for low-current applications) causes
+the intermediate product to exceed UINT_MAX (4,294,967,295). This results
+in a silent wraparound before the division by 1000.
+
+Furthermore, if the wrapped value has the most significant bit set,
+converting it back to the signed int info->m results in negative
+coefficients. This logic error leads to drastically corrupted current and
+power readings, which can cause erratic thermal or power management
+behavior in the system.
+
+Fix the problem by using 64-bit operations for the multiply/divide
+operations. This can still overflow, but only for unreasonably large
+shunt resistor values.
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Fixes: 94ee5fcc240fe ("hwmon: (pmbus/lm25066) Support configurable sense resistor values")
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/pmbus/lm25066.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c
+index dd7275a67a0ab..7774d678022e2 100644
+--- a/drivers/hwmon/pmbus/lm25066.c
++++ b/drivers/hwmon/pmbus/lm25066.c
+@@ -14,6 +14,7 @@
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
+ #include <linux/log2.h>
++#include <linux/math.h>
+ #include <linux/of.h>
+ #include "pmbus.h"
+
+@@ -540,8 +541,8 @@ static int lm25066_probe(struct i2c_client *client)
+ if (of_property_read_u32(client->dev.of_node, "shunt-resistor-micro-ohms", &shunt))
+ shunt = 1000;
+
+- info->m[PSC_CURRENT_IN] = info->m[PSC_CURRENT_IN] * shunt / 1000;
+- info->m[PSC_POWER] = info->m[PSC_POWER] * shunt / 1000;
++ info->m[PSC_CURRENT_IN] = DIV_ROUND_CLOSEST_ULL((u64)info->m[PSC_CURRENT_IN] * shunt, 1000);
++ info->m[PSC_POWER] = DIV_ROUND_CLOSEST_ULL((u64)info->m[PSC_POWER] * shunt, 1000);
+
+ #if IS_ENABLED(CONFIG_SENSORS_LM25066_REGULATOR)
+ /* LM25056 doesn't support OPERATION */
+--
+2.53.0
+
--- /dev/null
+From 6aee13770ebae0710e220f91c03381d5dd5f0dbf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 20 Mar 2026 07:45:55 -0700
+Subject: hwmon: (pmbus_core) Use guard() for mutex protection
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit bd1c178affd7d1ca86eaf97cf797e0d15e57eb0a ]
+
+Simplify the code by using guard() and scoped_guard() instead of
+mutex_lock()/mutex_unlock() sequences.
+
+This patch changes semantics for debugfs accesses. Previously, those
+used mutex_lock_interruptible() and not mutex_lock(). This change is
+intentional and should have little if any impact since locks should not
+be held for a significant amount of time and debugfs accesses are less
+critical than sysfs accesses (which never used interruptable locks).
+
+Reviewed-by: Sanman Pradhan <psanman@juniper.net>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Stable-dep-of: 59bd68ab05a8 ("hwmon: (pmbus) Fix type confusion in notification logic")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/pmbus/pmbus_core.c | 277 ++++++++++++-------------------
+ 1 file changed, 107 insertions(+), 170 deletions(-)
+
+diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
+index c9e3ec4552efd..a95ffd563018d 100644
+--- a/drivers/hwmon/pmbus/pmbus_core.c
++++ b/drivers/hwmon/pmbus/pmbus_core.c
+@@ -1156,12 +1156,11 @@ static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b,
+ int ret, status;
+ u16 regval;
+
+- mutex_lock(&data->update_lock);
++ guard(pmbus_lock)(client);
++
+ status = pmbus_get_status(client, page, reg);
+- if (status < 0) {
+- ret = status;
+- goto unlock;
+- }
++ if (status < 0)
++ return status;
+
+ if (s1)
+ pmbus_update_sensor_data(client, s1);
+@@ -1173,7 +1172,7 @@ static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b,
+ if (data->revision >= PMBUS_REV_12) {
+ ret = _pmbus_write_byte_data(client, page, reg, regval);
+ if (ret)
+- goto unlock;
++ return ret;
+ } else {
+ pmbus_clear_fault_page(client, page);
+ }
+@@ -1181,14 +1180,10 @@ static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b,
+ if (s1 && s2) {
+ s64 v1, v2;
+
+- if (s1->data < 0) {
+- ret = s1->data;
+- goto unlock;
+- }
+- if (s2->data < 0) {
+- ret = s2->data;
+- goto unlock;
+- }
++ if (s1->data < 0)
++ return s1->data;
++ if (s2->data < 0)
++ return s2->data;
+
+ v1 = pmbus_reg2data(data, s1);
+ v2 = pmbus_reg2data(data, s2);
+@@ -1196,8 +1191,6 @@ static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b,
+ } else {
+ ret = !!regval;
+ }
+-unlock:
+- mutex_unlock(&data->update_lock);
+ return ret;
+ }
+
+@@ -1227,16 +1220,16 @@ static ssize_t pmbus_show_sensor(struct device *dev,
+ struct i2c_client *client = to_i2c_client(dev->parent);
+ struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
+ struct pmbus_data *data = i2c_get_clientdata(client);
+- ssize_t ret;
++ s64 val;
+
+- mutex_lock(&data->update_lock);
+- pmbus_update_sensor_data(client, sensor);
+- if (sensor->data < 0)
+- ret = sensor->data;
+- else
+- ret = sysfs_emit(buf, "%lld\n", pmbus_reg2data(data, sensor));
+- mutex_unlock(&data->update_lock);
+- return ret;
++ scoped_guard(pmbus_lock, client) {
++ pmbus_update_sensor_data(client, sensor);
++ if (sensor->data < 0)
++ return sensor->data;
++ val = pmbus_reg2data(data, sensor);
++ }
++
++ return sysfs_emit(buf, "%lld\n", val);
+ }
+
+ static ssize_t pmbus_set_sensor(struct device *dev,
+@@ -1246,7 +1239,6 @@ static ssize_t pmbus_set_sensor(struct device *dev,
+ struct i2c_client *client = to_i2c_client(dev->parent);
+ struct pmbus_data *data = i2c_get_clientdata(client);
+ struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
+- ssize_t rv = count;
+ s64 val;
+ int ret;
+ u16 regval;
+@@ -1254,15 +1246,15 @@ static ssize_t pmbus_set_sensor(struct device *dev,
+ if (kstrtos64(buf, 10, &val) < 0)
+ return -EINVAL;
+
+- mutex_lock(&data->update_lock);
++ guard(pmbus_lock)(client);
++
+ regval = pmbus_data2reg(data, sensor, val);
+ ret = _pmbus_write_word_data(client, sensor->page, sensor->reg, regval);
+ if (ret < 0)
+- rv = ret;
+- else
+- sensor->data = -ENODATA;
+- mutex_unlock(&data->update_lock);
+- return rv;
++ return ret;
++
++ sensor->data = -ENODATA;
++ return count;
+ }
+
+ static ssize_t pmbus_show_label(struct device *dev,
+@@ -1364,7 +1356,7 @@ static int pmbus_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
+ struct pmbus_data *pmbus_data = tdata->pmbus_data;
+ struct i2c_client *client = to_i2c_client(pmbus_data->dev);
+ struct device *dev = pmbus_data->hwmon_dev;
+- int ret = 0;
++ int _temp;
+
+ if (!dev) {
+ /* May not even get to hwmon yet */
+@@ -1372,15 +1364,15 @@ static int pmbus_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
+ return 0;
+ }
+
+- mutex_lock(&pmbus_data->update_lock);
+- pmbus_update_sensor_data(client, sensor);
+- if (sensor->data < 0)
+- ret = sensor->data;
+- else
+- *temp = (int)pmbus_reg2data(pmbus_data, sensor);
+- mutex_unlock(&pmbus_data->update_lock);
++ scoped_guard(pmbus_lock, client) {
++ pmbus_update_sensor_data(client, sensor);
++ if (sensor->data < 0)
++ return sensor->data;
++ _temp = (int)pmbus_reg2data(pmbus_data, sensor);
++ }
+
+- return ret;
++ *temp = _temp;
++ return 0;
+ }
+
+ static const struct thermal_zone_device_ops pmbus_thermal_ops = {
+@@ -2412,13 +2404,12 @@ static ssize_t pmbus_show_samples(struct device *dev,
+ int val;
+ struct i2c_client *client = to_i2c_client(dev->parent);
+ struct pmbus_samples_reg *reg = to_samples_reg(devattr);
+- struct pmbus_data *data = i2c_get_clientdata(client);
+
+- mutex_lock(&data->update_lock);
+- val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg);
+- mutex_unlock(&data->update_lock);
+- if (val < 0)
+- return val;
++ scoped_guard(pmbus_lock, client) {
++ val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg);
++ if (val < 0)
++ return val;
++ }
+
+ return sysfs_emit(buf, "%d\n", val);
+ }
+@@ -2431,14 +2422,13 @@ static ssize_t pmbus_set_samples(struct device *dev,
+ long val;
+ struct i2c_client *client = to_i2c_client(dev->parent);
+ struct pmbus_samples_reg *reg = to_samples_reg(devattr);
+- struct pmbus_data *data = i2c_get_clientdata(client);
+
+ if (kstrtol(buf, 0, &val) < 0)
+ return -EINVAL;
+
+- mutex_lock(&data->update_lock);
++ guard(pmbus_lock)(client);
++
+ ret = _pmbus_write_word_data(client, reg->page, reg->attr->reg, val);
+- mutex_unlock(&data->update_lock);
+
+ return ret ? : count;
+ }
+@@ -2950,14 +2940,9 @@ static int _pmbus_is_enabled(struct i2c_client *client, u8 page)
+
+ static int __maybe_unused pmbus_is_enabled(struct i2c_client *client, u8 page)
+ {
+- struct pmbus_data *data = i2c_get_clientdata(client);
+- int ret;
++ guard(pmbus_lock)(client);
+
+- mutex_lock(&data->update_lock);
+- ret = _pmbus_is_enabled(client, page);
+- mutex_unlock(&data->update_lock);
+-
+- return ret;
++ return _pmbus_is_enabled(client, page);
+ }
+
+ #define to_dev_attr(_dev_attr) \
+@@ -2988,14 +2973,13 @@ static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags)
+ }
+ }
+
+-static int _pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags,
++static int _pmbus_get_flags(struct i2c_client *client, u8 page, unsigned int *flags,
+ unsigned int *event, bool notify)
+ {
++ struct pmbus_data *data = i2c_get_clientdata(client);
+ int i, status;
+ const struct pmbus_status_category *cat;
+ const struct pmbus_status_assoc *bit;
+- struct device *dev = data->dev;
+- struct i2c_client *client = to_i2c_client(dev);
+ int func = data->info->func[page];
+
+ *flags = 0;
+@@ -3071,16 +3055,12 @@ static int _pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flag
+ return 0;
+ }
+
+-static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags,
++static int __maybe_unused pmbus_get_flags(struct i2c_client *client, u8 page, unsigned int *flags,
+ unsigned int *event, bool notify)
+ {
+- int ret;
+-
+- mutex_lock(&data->update_lock);
+- ret = _pmbus_get_flags(data, page, flags, event, notify);
+- mutex_unlock(&data->update_lock);
++ guard(pmbus_lock)(client);
+
+- return ret;
++ return _pmbus_get_flags(client, page, flags, event, notify);
+ }
+
+ #if IS_ENABLED(CONFIG_REGULATOR)
+@@ -3096,17 +3076,13 @@ static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable)
+ {
+ struct device *dev = rdev_get_dev(rdev);
+ struct i2c_client *client = to_i2c_client(dev->parent);
+- struct pmbus_data *data = i2c_get_clientdata(client);
+ u8 page = rdev_get_id(rdev);
+- int ret;
+
+- mutex_lock(&data->update_lock);
+- ret = pmbus_update_byte_data(client, page, PMBUS_OPERATION,
+- PB_OPERATION_CONTROL_ON,
+- enable ? PB_OPERATION_CONTROL_ON : 0);
+- mutex_unlock(&data->update_lock);
++ guard(pmbus_lock)(client);
+
+- return ret;
++ return pmbus_update_byte_data(client, page, PMBUS_OPERATION,
++ PB_OPERATION_CONTROL_ON,
++ enable ? PB_OPERATION_CONTROL_ON : 0);
+ }
+
+ static int pmbus_regulator_enable(struct regulator_dev *rdev)
+@@ -3123,54 +3099,41 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
+ {
+ struct device *dev = rdev_get_dev(rdev);
+ struct i2c_client *client = to_i2c_client(dev->parent);
+- struct pmbus_data *data = i2c_get_clientdata(client);
+ int event;
+
+- return pmbus_get_flags(data, rdev_get_id(rdev), flags, &event, false);
++ return pmbus_get_flags(client, rdev_get_id(rdev), flags, &event, false);
+ }
+
+ static int pmbus_regulator_get_status(struct regulator_dev *rdev)
+ {
+ struct device *dev = rdev_get_dev(rdev);
+ struct i2c_client *client = to_i2c_client(dev->parent);
+- struct pmbus_data *data = i2c_get_clientdata(client);
+ u8 page = rdev_get_id(rdev);
+ int status, ret;
+ int event;
+
+- mutex_lock(&data->update_lock);
++ guard(pmbus_lock)(client);
++
+ status = pmbus_get_status(client, page, PMBUS_STATUS_WORD);
+- if (status < 0) {
+- ret = status;
+- goto unlock;
+- }
++ if (status < 0)
++ return status;
+
+- if (status & PB_STATUS_OFF) {
+- ret = REGULATOR_STATUS_OFF;
+- goto unlock;
+- }
++ if (status & PB_STATUS_OFF)
++ return REGULATOR_STATUS_OFF;
+
+ /* If regulator is ON & reports power good then return ON */
+- if (!(status & PB_STATUS_POWER_GOOD_N)) {
+- ret = REGULATOR_STATUS_ON;
+- goto unlock;
+- }
++ if (!(status & PB_STATUS_POWER_GOOD_N))
++ return REGULATOR_STATUS_ON;
+
+- ret = _pmbus_get_flags(data, rdev_get_id(rdev), &status, &event, false);
++ ret = _pmbus_get_flags(client, rdev_get_id(rdev), &status, &event, false);
+ if (ret)
+- goto unlock;
++ return ret;
+
+ if (status & (REGULATOR_ERROR_UNDER_VOLTAGE | REGULATOR_ERROR_OVER_CURRENT |
+- REGULATOR_ERROR_REGULATION_OUT | REGULATOR_ERROR_FAIL | REGULATOR_ERROR_OVER_TEMP)) {
+- ret = REGULATOR_STATUS_ERROR;
+- goto unlock;
+- }
+-
+- ret = REGULATOR_STATUS_UNDEFINED;
++ REGULATOR_ERROR_REGULATION_OUT | REGULATOR_ERROR_FAIL | REGULATOR_ERROR_OVER_TEMP))
++ return REGULATOR_STATUS_ERROR;
+
+-unlock:
+- mutex_unlock(&data->update_lock);
+- return ret;
++ return REGULATOR_STATUS_UNDEFINED;
+ }
+
+ static int pmbus_regulator_get_low_margin(struct i2c_client *client, int page)
+@@ -3235,19 +3198,16 @@ static int pmbus_regulator_get_voltage(struct regulator_dev *rdev)
+ .class = PSC_VOLTAGE_OUT,
+ .convert = true,
+ };
+- int ret;
++ int voltage;
+
+- mutex_lock(&data->update_lock);
+- s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_READ_VOUT);
+- if (s.data < 0) {
+- ret = s.data;
+- goto unlock;
++ scoped_guard(pmbus_lock, client) {
++ s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_READ_VOUT);
++ if (s.data < 0)
++ return s.data;
++ voltage = (int)pmbus_reg2data(data, &s);
+ }
+
+- ret = (int)pmbus_reg2data(data, &s) * 1000; /* unit is uV */
+-unlock:
+- mutex_unlock(&data->update_lock);
+- return ret;
++ return voltage * 1000; /* unit is uV */
+ }
+
+ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
+@@ -3264,22 +3224,18 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
+ };
+ int val = DIV_ROUND_CLOSEST(min_uv, 1000); /* convert to mV */
+ int low, high;
+- int ret;
+
+ *selector = 0;
+
+- mutex_lock(&data->update_lock);
++ guard(pmbus_lock)(client);
++
+ low = pmbus_regulator_get_low_margin(client, s.page);
+- if (low < 0) {
+- ret = low;
+- goto unlock;
+- }
++ if (low < 0)
++ return low;
+
+ high = pmbus_regulator_get_high_margin(client, s.page);
+- if (high < 0) {
+- ret = high;
+- goto unlock;
+- }
++ if (high < 0)
++ return high;
+
+ /* Make sure we are within margins */
+ if (low > val)
+@@ -3289,10 +3245,7 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
+
+ val = pmbus_data2reg(data, &s, val);
+
+- ret = _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
+-unlock:
+- mutex_unlock(&data->update_lock);
+- return ret;
++ return _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
+ }
+
+ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
+@@ -3302,7 +3255,6 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
+ struct i2c_client *client = to_i2c_client(dev->parent);
+ struct pmbus_data *data = i2c_get_clientdata(client);
+ int val, low, high;
+- int ret;
+
+ if (data->flags & PMBUS_VOUT_PROTECTED)
+ return 0;
+@@ -3315,29 +3267,20 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
+ val = DIV_ROUND_CLOSEST(rdev->desc->min_uV +
+ (rdev->desc->uV_step * selector), 1000); /* convert to mV */
+
+- mutex_lock(&data->update_lock);
++ guard(pmbus_lock)(client);
+
+ low = pmbus_regulator_get_low_margin(client, rdev_get_id(rdev));
+- if (low < 0) {
+- ret = low;
+- goto unlock;
+- }
++ if (low < 0)
++ return low;
+
+ high = pmbus_regulator_get_high_margin(client, rdev_get_id(rdev));
+- if (high < 0) {
+- ret = high;
+- goto unlock;
+- }
++ if (high < 0)
++ return high;
+
+- if (val >= low && val <= high) {
+- ret = val * 1000; /* unit is uV */
+- goto unlock;
+- }
++ if (val >= low && val <= high)
++ return val * 1000; /* unit is uV */
+
+- ret = 0;
+-unlock:
+- mutex_unlock(&data->update_lock);
+- return ret;
++ return 0;
+ }
+
+ const struct regulator_ops pmbus_regulator_ops = {
+@@ -3478,16 +3421,16 @@ static irqreturn_t pmbus_fault_handler(int irq, void *pdata)
+ struct i2c_client *client = to_i2c_client(data->dev);
+ int i, status, event;
+
+- mutex_lock(&data->update_lock);
++ guard(pmbus_lock)(client);
++
+ for (i = 0; i < data->info->pages; i++) {
+- _pmbus_get_flags(data, i, &status, &event, true);
++ _pmbus_get_flags(client, i, &status, &event, true);
+
+ if (event)
+ pmbus_regulator_notify(data, i, event);
+ }
+
+ pmbus_clear_faults(client);
+- mutex_unlock(&data->update_lock);
+
+ return IRQ_HANDLED;
+ }
+@@ -3543,15 +3486,13 @@ static struct dentry *pmbus_debugfs_dir; /* pmbus debugfs directory */
+
+ static int pmbus_debugfs_get(void *data, u64 *val)
+ {
+- int rc;
+ struct pmbus_debugfs_entry *entry = data;
+- struct pmbus_data *pdata = i2c_get_clientdata(entry->client);
++ struct i2c_client *client = entry->client;
++ int rc;
+
+- rc = mutex_lock_interruptible(&pdata->update_lock);
+- if (rc)
+- return rc;
+- rc = _pmbus_read_byte_data(entry->client, entry->page, entry->reg);
+- mutex_unlock(&pdata->update_lock);
++ guard(pmbus_lock)(client);
++
++ rc = _pmbus_read_byte_data(client, entry->page, entry->reg);
+ if (rc < 0)
+ return rc;
+
+@@ -3564,15 +3505,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops, pmbus_debugfs_get, NULL,
+
+ static int pmbus_debugfs_get_status(void *data, u64 *val)
+ {
+- int rc;
+ struct pmbus_debugfs_entry *entry = data;
+- struct pmbus_data *pdata = i2c_get_clientdata(entry->client);
++ struct i2c_client *client = entry->client;
++ struct pmbus_data *pdata = i2c_get_clientdata(client);
++ int rc;
+
+- rc = mutex_lock_interruptible(&pdata->update_lock);
+- if (rc)
+- return rc;
+- rc = pdata->read_status(entry->client, entry->page);
+- mutex_unlock(&pdata->update_lock);
++ guard(pmbus_lock)(client);
++
++ rc = pdata->read_status(client, entry->page);
+ if (rc < 0)
+ return rc;
+
+@@ -3588,17 +3528,14 @@ static ssize_t pmbus_debugfs_block_read(struct file *file, char __user *buf,
+ {
+ int rc;
+ struct pmbus_debugfs_entry *entry = file->private_data;
+- struct pmbus_data *pdata = i2c_get_clientdata(entry->client);
++ struct i2c_client *client = entry->client;
+ char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
+
+- rc = mutex_lock_interruptible(&pdata->update_lock);
+- if (rc)
+- return rc;
+- rc = pmbus_read_block_data(entry->client, entry->page, entry->reg,
+- data);
+- mutex_unlock(&pdata->update_lock);
+- if (rc < 0)
+- return rc;
++ scoped_guard(pmbus_lock, client) {
++ rc = pmbus_read_block_data(client, entry->page, entry->reg, data);
++ if (rc < 0)
++ return rc;
++ }
+
+ /* Add newline at the end of a read data */
+ data[rc] = '\n';
+--
+2.53.0
+
--- /dev/null
+From 6b5a62c1854f99c5c70617574cde5b6944d75c6e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 21:35:05 +0300
+Subject: ipvs: avoid out-of-bounds write in ip_vs_nat_icmp
+
+From: Julian Anastasov <ja@ssi.bg>
+
+[ Upstream commit 646922a0379496154e8c8faca4f8e2fd9100cacc ]
+
+Sashiko warns that local attacker can modify the packet
+while it is processed by IPVS. Some places read the
+IP ihl field multiple times which can cause out-of-bounds
+access. One such place is ip_vs_nat_icmp where we
+can write after the validated area.
+
+Fix it by providing ciph argument just like it is done for
+IPv6 and use ciph->len as offset to the embedded transport
+header.
+
+Modify some IPv4 header checks by reading the ihl field
+only once.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Link: https://sashiko.dev/#/patchset/20260722101517.36313-1-ja%40ssi.bg
+Signed-off-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/ip_vs.h | 2 +-
+ net/netfilter/ipvs/ip_vs_core.c | 67 +++++++++++++++++----------------
+ net/netfilter/ipvs/ip_vs_xmit.c | 2 +-
+ 3 files changed, 36 insertions(+), 35 deletions(-)
+
+diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
+index 17a97086b294f..cbad9c74a8868 100644
+--- a/include/net/ip_vs.h
++++ b/include/net/ip_vs.h
+@@ -1720,7 +1720,7 @@ static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp)
+
+ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct ip_vs_conn *cp, int dir, unsigned int toff,
+- bool has_ports);
++ bool has_ports, struct ip_vs_iphdr *ciph);
+
+ #ifdef CONFIG_IP_VS_IPV6
+ void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
+diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
+index 6207a91e93f3b..586346110cd89 100644
+--- a/net/netfilter/ipvs/ip_vs_core.c
++++ b/net/netfilter/ipvs/ip_vs_core.c
+@@ -747,28 +747,27 @@ static int ip_vs_route_me_harder(struct netns_ipvs *ipvs, int af,
+ */
+ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct ip_vs_conn *cp, int inout, unsigned int toff,
+- bool has_ports)
++ bool has_ports, struct ip_vs_iphdr *ciph)
+ {
+ struct iphdr *iph = ip_hdr(skb);
+ struct icmphdr *icmph = (struct icmphdr *)(skb->data + toff);
+- struct iphdr *ciph = (struct iphdr *)(icmph + 1);
+- unsigned int coff __maybe_unused = toff + sizeof(struct icmphdr);
++ struct iphdr *cih = (struct iphdr *)(icmph + 1);
+
+ if (inout) {
+ iph->saddr = cp->vaddr.ip;
+ ip_send_check(iph);
+- ciph->daddr = cp->vaddr.ip;
+- ip_send_check(ciph);
++ cih->daddr = cp->vaddr.ip;
++ ip_send_check(cih);
+ } else {
+ iph->daddr = cp->daddr.ip;
+ ip_send_check(iph);
+- ciph->saddr = cp->daddr.ip;
+- ip_send_check(ciph);
++ cih->saddr = cp->daddr.ip;
++ ip_send_check(cih);
+ }
+
+ /* the TCP/UDP/SCTP port */
+ if (has_ports) {
+- __be16 *ports = (void *)ciph + ciph->ihl*4;
++ __be16 *ports = (void *)(skb->data + ciph->len);
+
+ if (inout)
+ ports[1] = cp->vport;
+@@ -782,10 +781,10 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ if (inout)
+- IP_VS_DBG_PKT(11, AF_INET, pp, skb, coff,
++ IP_VS_DBG_PKT(11, AF_INET, pp, skb, ciph->off,
+ "Forwarding altered outgoing ICMP");
+ else
+- IP_VS_DBG_PKT(11, AF_INET, pp, skb, coff,
++ IP_VS_DBG_PKT(11, AF_INET, pp, skb, ciph->off,
+ "Forwarding altered incoming ICMP");
+ }
+
+@@ -878,7 +877,7 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
+ ip_vs_nat_icmp_v6(skb, pp, cp, 1, toff, has_ports, ciph);
+ else
+ #endif
+- ip_vs_nat_icmp(skb, pp, cp, 1, toff, has_ports);
++ ip_vs_nat_icmp(skb, pp, cp, 1, toff, has_ports, ciph);
+
+ if (ip_vs_route_me_harder(cp->ipvs, af, skb, hooknum))
+ goto out;
+@@ -914,7 +913,7 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ struct ip_vs_iphdr ciph;
+ struct ip_vs_conn *cp;
+ struct ip_vs_protocol *pp;
+- unsigned int offset, ihl;
++ unsigned int offset;
+ union nf_inet_addr snet;
+
+ *related = 1;
+@@ -927,7 +926,6 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ return NF_ACCEPT;
+ }
+
+- ihl = ipvsh->len;
+ offset = ipvsh->len;
+ ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
+ if (ic == NULL)
+@@ -953,11 +951,15 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+
+ /* Now find the contained IP header */
+ offset += sizeof(_icmph);
++ if (!ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, true, &ciph))
++ return NF_ACCEPT; /* The packet looks wrong, ignore */
++
+ cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+- if (!(cih && cih->version == 4 && cih->ihl >= 5))
++ if (!(cih && cih->version == 4 &&
++ ciph.len - ciph.off >= sizeof(struct iphdr)))
+ return NF_ACCEPT; /* The packet looks wrong, ignore */
+
+- pp = ip_vs_proto_get(cih->protocol);
++ pp = ip_vs_proto_get(ciph.protocol);
+ if (!pp)
+ return NF_ACCEPT;
+
+@@ -968,8 +970,6 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ IP_VS_DBG_PKT(11, AF_INET, pp, skb, offset,
+ "Checking outgoing ICMP for");
+
+- ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, true, &ciph);
+-
+ /* The embedded headers contain source and dest in reverse order */
+ cp = INDIRECT_CALL_1(pp->conn_out_get, ip_vs_conn_out_get_proto,
+ ipvs, AF_INET, skb, &ciph);
+@@ -977,8 +977,8 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ return NF_ACCEPT;
+
+ snet.ip = ipvsh->saddr.ip;
+- return handle_response_icmp(AF_INET, skb, &snet, cp, pp, &ciph, ihl,
+- hooknum);
++ return handle_response_icmp(AF_INET, skb, &snet, cp, pp, &ciph,
++ ipvsh->len, hooknum);
+ }
+
+ #ifdef CONFIG_IP_VS_IPV6
+@@ -1625,10 +1625,12 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ /* Now find the contained IP header */
+ offset += sizeof(_icmph);
+ cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+- if (!(cih && cih->version == 4 && cih->ihl >= 5))
++ if (!cih)
+ return NF_ACCEPT; /* The packet looks wrong, ignore */
+- raddr = (union nf_inet_addr *)&cih->daddr;
+ hlen_ipip = cih->ihl * 4;
++ if (!(cih->version == 4 && hlen_ipip >= sizeof(struct iphdr)))
++ return NF_ACCEPT; /* The packet looks wrong, ignore */
++ raddr = (union nf_inet_addr *)&cih->daddr;
+
+ /* Special case for errors for IPIP/UDP/GRE tunnel packets */
+ tunnel = false;
+@@ -1645,9 +1647,6 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ if (!dest || dest->tun_type != IP_VS_CONN_F_TUNNEL_TYPE_IPIP)
+ return NF_ACCEPT;
+ offset += hlen_ipip;
+- cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+- if (!(cih && cih->version == 4 && cih->ihl >= 5))
+- return NF_ACCEPT; /* The packet looks wrong, ignore */
+ tunnel = true;
+ } else if ((cih->protocol == IPPROTO_UDP || /* Can be UDP encap */
+ cih->protocol == IPPROTO_GRE) && /* Can be GRE encap */
+@@ -1672,21 +1671,25 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ /* Skip IP and UDP/GRE tunnel headers */
+ offset = offset2 + ulen;
+ /* Now we should be at the original IP header */
+- cih = skb_header_pointer(skb, offset, sizeof(_ciph),
+- &_ciph);
+- if (cih && cih->version == 4 && cih->ihl >= 5 &&
+- iproto == IPPROTO_IPIP)
++ if (iproto == IPPROTO_IPIP)
+ tunnel = true;
+ else
+ return NF_ACCEPT;
+ }
+ }
+
+- pd = ip_vs_proto_data_get(ipvs, cih->protocol);
++ if (!ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, !tunnel, &ciph))
++ return NF_ACCEPT;
++ pd = ip_vs_proto_data_get(ipvs, ciph.protocol);
+ if (!pd)
+ return NF_ACCEPT;
+ pp = pd->pp;
+
++ cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
++ if (!(cih && cih->version == 4 &&
++ ciph.len - ciph.off >= sizeof(struct iphdr)))
++ return NF_ACCEPT; /* The packet looks wrong, ignore */
++
+ /* Is the embedded protocol header present? */
+ if (unlikely(cih->frag_off & htons(IP_OFFSET) && !pp->dont_defrag))
+ return NF_ACCEPT;
+@@ -1694,9 +1697,6 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ IP_VS_DBG_PKT(11, AF_INET, pp, skb, offset,
+ "Checking incoming ICMP for");
+
+- offset2 = offset;
+- ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, !tunnel, &ciph);
+-
+ /* The embedded headers contain source and dest in reverse order.
+ * For IPIP/UDP/GRE tunnel this is error for request, not for reply.
+ */
+@@ -1726,11 +1726,12 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ }
+
+ if (tunnel) {
+- unsigned int hlen_orig = cih->ihl * 4;
++ unsigned int hlen_orig = ciph.len - ciph.off;
+ __be32 info = ic->un.gateway;
+ __u8 type = ic->type;
+ __u8 code = ic->code;
+
++ offset2 = offset;
+ /* Update the MTU */
+ if (ic->type == ICMP_DEST_UNREACH &&
+ ic->code == ICMP_FRAG_NEEDED) {
+diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
+index ac1827ef78949..7db74b2ea358c 100644
+--- a/net/netfilter/ipvs/ip_vs_xmit.c
++++ b/net/netfilter/ipvs/ip_vs_xmit.c
+@@ -1577,7 +1577,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
+ if (skb_cow(skb, rt->dst.dev->hard_header_len))
+ goto tx_error;
+
+- ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports);
++ ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports, ciph);
+
+ /* Another hack: avoid icmp_send in ip_fragment */
+ skb->ignore_df = 1;
+--
+2.53.0
+
--- /dev/null
+From cfce862a01d8cfd7f60dfc533eff1fa537741863 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 21:35:06 +0300
+Subject: ipvs: return the csum validation for forward hook
+
+From: Julian Anastasov <ja@ssi.bg>
+
+[ Upstream commit 99609cb0aa789c8d071050ce8579989551882cc6 ]
+
+Sashiko notes that playing games with the skb dst and rt
+flags instead of providing hooknum is not a good idea
+when validating the checksums.
+
+Also, skipping checksum validation for FORWARD packets
+risk silent data corruption, even if the only user is
+the FTP-CMD packets coming from the real server.
+
+Sashiko also noticed that by using common checksum
+helper in the previous commit we actually fixed old bug
+where the TCP/UDP checksum for IPv6 on CHECKSUM_COMPLETE
+was not validated correctly.
+
+Fixes: e876b75b9020 ("ipvs: fix the checksum validations")
+Link: https://sashiko.dev/#/patchset/20260722211420.153933-1-pablo%40netfilter.org
+Link: https://sashiko.dev/#/patchset/20260727185024.67534-1-ja%40ssi.bg
+Link: https://sashiko.dev/#/patchset/20260728202520.59179-1-ja%40ssi.bg
+Signed-off-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/ip_vs.h | 19 +++++--------------
+ net/netfilter/ipvs/ip_vs_proto_sctp.c | 2 +-
+ 2 files changed, 6 insertions(+), 15 deletions(-)
+
+diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
+index cbad9c74a8868..d63d6459727d6 100644
+--- a/include/net/ip_vs.h
++++ b/include/net/ip_vs.h
+@@ -24,9 +24,7 @@
+ #include <linux/netfilter.h> /* for union nf_inet_addr */
+ #include <linux/ip.h>
+ #include <linux/ipv6.h> /* for struct ipv6hdr */
+-#include <net/route.h>
+ #include <net/ipv6.h>
+-#include <net/ip6_fib.h>
+ #if IS_ENABLED(CONFIG_NF_CONNTRACK)
+ #include <net/netfilter/nf_conntrack.h>
+ #endif
+@@ -1753,30 +1751,23 @@ static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum)
+ return csum_partial(diff, sizeof(diff), oldsum);
+ }
+
+-static inline bool ip_vs_checksum_needed(struct sk_buff *skb, int af)
++static inline bool ip_vs_checksum_needed(struct sk_buff *skb)
+ {
+ /* Checksum unnecessary or already validated? */
+ if (skb_csum_unnecessary(skb))
+ return false;
+- /* LOCAL_OUT ? */
+- if (!skb->dev || skb->dev->flags & IFF_LOOPBACK)
++ /* Locally generated ? */
++ if (!skb->dev)
+ return false;
+- /* !LOCAL_IN (FORWARD) ? */
+- if (af == AF_INET6) {
+- if (!(dst_rt6_info(skb_dst(skb))->rt6i_flags & RTF_LOCAL))
+- return false;
+- } else {
+- if (!(skb_rtable(skb)->rt_flags & RTCF_LOCAL))
+- return false;
+- }
+ return true;
+ }
+
+ static inline bool ip_vs_checksum_common_check(struct sk_buff *skb,
+ int offset, int proto, int af)
+ {
+- if (!ip_vs_checksum_needed(skb, af))
++ if (!ip_vs_checksum_needed(skb))
+ return true;
++ /* Validate csum even for FORWARD */
+ return !nf_checksum(skb, NF_INET_LOCAL_IN, offset, proto, af);
+ }
+
+diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
+index 3dbd3096e1637..c80567c73469b 100644
+--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
++++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
+@@ -193,7 +193,7 @@ sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct sctphdr *sh;
+ __le32 cmp, val;
+
+- if (!ip_vs_checksum_needed(skb, af))
++ if (!ip_vs_checksum_needed(skb))
+ return 1;
+ sh = (struct sctphdr *)(skb->data + sctphoff);
+ cmp = sh->checksum;
+--
+2.53.0
+
--- /dev/null
+From 2c798cddd711a9895fd7c51d5dc1b86ca62f64e8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Jan 2026 13:25:40 +0000
+Subject: net: add bare bone queue configs
+
+From: Pavel Begunkov <asml.silence@gmail.com>
+
+[ Upstream commit efcb9a4d32d3d9b924642c086b868bfbb9a07c13 ]
+
+We'll need to pass extra parameters when allocating a queue for memory
+providers. Define a new structure for queue configurations, and pass it
+to qapi callbacks. It's empty for now, actual parameters will be added
+in following patches.
+
+Configurations should persist across resets, and for that they're
+default-initialised on device registration and stored in struct
+netdev_rx_queue. We also add a new qapi callback for defaulting a given
+config. It must be implemented if a driver wants to use queue configs
+and is optional otherwise.
+
+Suggested-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 8 ++++++--
+ drivers/net/ethernet/google/gve/gve_main.c | 9 ++++++---
+ .../net/ethernet/mellanox/mlx5/core/en_main.c | 10 ++++++----
+ drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 8 ++++++--
+ drivers/net/netdevsim/netdev.c | 7 +++++--
+ include/net/netdev_queues.h | 9 +++++++++
+ include/net/netdev_rx_queue.h | 2 ++
+ net/core/dev.c | 17 +++++++++++++++++
+ net/core/netdev_rx_queue.c | 12 +++++++++---
+ 9 files changed, 66 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 1efd1f8776abe..f3fbbf188053c 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -15954,7 +15954,9 @@ static const struct netdev_stat_ops bnxt_stat_ops = {
+ .get_base_stats = bnxt_get_base_stats,
+ };
+
+-static int bnxt_queue_mem_alloc(struct net_device *dev, void *qmem, int idx)
++static int bnxt_queue_mem_alloc(struct net_device *dev,
++ struct netdev_queue_config *qcfg,
++ void *qmem, int idx)
+ {
+ struct bnxt_rx_ring_info *rxr, *clone;
+ struct bnxt *bp = netdev_priv(dev);
+@@ -16120,7 +16122,9 @@ static void bnxt_copy_rx_ring(struct bnxt *bp,
+ dst->rx_agg_bmap = src->rx_agg_bmap;
+ }
+
+-static int bnxt_queue_start(struct net_device *dev, void *qmem, int idx)
++static int bnxt_queue_start(struct net_device *dev,
++ struct netdev_queue_config *qcfg,
++ void *qmem, int idx)
+ {
+ struct bnxt *bp = netdev_priv(dev);
+ struct bnxt_rx_ring_info *rxr, *clone;
+diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c
+index 030800776ead1..9751049849432 100644
+--- a/drivers/net/ethernet/google/gve/gve_main.c
++++ b/drivers/net/ethernet/google/gve/gve_main.c
+@@ -2580,8 +2580,9 @@ static void gve_rx_queue_mem_free(struct net_device *dev, void *per_q_mem)
+ gve_rx_free_ring_dqo(priv, gve_per_q_mem, &cfg);
+ }
+
+-static int gve_rx_queue_mem_alloc(struct net_device *dev, void *per_q_mem,
+- int idx)
++static int gve_rx_queue_mem_alloc(struct net_device *dev,
++ struct netdev_queue_config *qcfg,
++ void *per_q_mem, int idx)
+ {
+ struct gve_priv *priv = netdev_priv(dev);
+ struct gve_rx_alloc_rings_cfg cfg = {0};
+@@ -2602,7 +2603,9 @@ static int gve_rx_queue_mem_alloc(struct net_device *dev, void *per_q_mem,
+ return err;
+ }
+
+-static int gve_rx_queue_start(struct net_device *dev, void *per_q_mem, int idx)
++static int gve_rx_queue_start(struct net_device *dev,
++ struct netdev_queue_config *qcfg,
++ void *per_q_mem, int idx)
+ {
+ struct gve_priv *priv = netdev_priv(dev);
+ struct gve_rx_ring *gve_per_q_mem;
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index 7e754b72f889f..58e255910c43e 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -5540,8 +5540,9 @@ struct mlx5_qmgmt_data {
+ struct mlx5e_channel_param cparam;
+ };
+
+-static int mlx5e_queue_mem_alloc(struct net_device *dev, void *newq,
+- int queue_index)
++static int mlx5e_queue_mem_alloc(struct net_device *dev,
++ struct netdev_queue_config *qcfg,
++ void *newq, int queue_index)
+ {
+ struct mlx5_qmgmt_data *new = (struct mlx5_qmgmt_data *)newq;
+ struct mlx5e_priv *priv = netdev_priv(dev);
+@@ -5602,8 +5603,9 @@ static int mlx5e_queue_stop(struct net_device *dev, void *oldq, int queue_index)
+ return 0;
+ }
+
+-static int mlx5e_queue_start(struct net_device *dev, void *newq,
+- int queue_index)
++static int mlx5e_queue_start(struct net_device *dev,
++ struct netdev_queue_config *qcfg,
++ void *newq, int queue_index)
+ {
+ struct mlx5_qmgmt_data *new = (struct mlx5_qmgmt_data *)newq;
+ struct mlx5e_priv *priv = netdev_priv(dev);
+diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
+index 14885c3d70697..dbe0855ecb575 100644
+--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
++++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
+@@ -2811,7 +2811,9 @@ void fbnic_napi_depletion_check(struct net_device *netdev)
+ fbnic_wrfl(fbd);
+ }
+
+-static int fbnic_queue_mem_alloc(struct net_device *dev, void *qmem, int idx)
++static int fbnic_queue_mem_alloc(struct net_device *dev,
++ struct netdev_queue_config *qcfg,
++ void *qmem, int idx)
+ {
+ struct fbnic_net *fbn = netdev_priv(dev);
+ const struct fbnic_q_triad *real;
+@@ -2863,7 +2865,9 @@ static void __fbnic_nv_restart(struct fbnic_net *fbn,
+ netif_wake_subqueue(fbn->netdev, nv->qt[i].sub0.q_idx);
+ }
+
+-static int fbnic_queue_start(struct net_device *dev, void *qmem, int idx)
++static int fbnic_queue_start(struct net_device *dev,
++ struct netdev_queue_config *qcfg,
++ void *qmem, int idx)
+ {
+ struct fbnic_net *fbn = netdev_priv(dev);
+ struct fbnic_napi_vector *nv;
+diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
+index 06446b03cd9bc..7a8e17bf46bdb 100644
+--- a/drivers/net/netdevsim/netdev.c
++++ b/drivers/net/netdevsim/netdev.c
+@@ -760,7 +760,9 @@ struct nsim_queue_mem {
+ };
+
+ static int
+-nsim_queue_mem_alloc(struct net_device *dev, void *per_queue_mem, int idx)
++nsim_queue_mem_alloc(struct net_device *dev,
++ struct netdev_queue_config *qcfg,
++ void *per_queue_mem, int idx)
+ {
+ struct nsim_queue_mem *qmem = per_queue_mem;
+ struct netdevsim *ns = netdev_priv(dev);
+@@ -809,7 +811,8 @@ static void nsim_queue_mem_free(struct net_device *dev, void *per_queue_mem)
+ }
+
+ static int
+-nsim_queue_start(struct net_device *dev, void *per_queue_mem, int idx)
++nsim_queue_start(struct net_device *dev, struct netdev_queue_config *qcfg,
++ void *per_queue_mem, int idx)
+ {
+ struct nsim_queue_mem *qmem = per_queue_mem;
+ struct netdevsim *ns = netdev_priv(dev);
+diff --git a/include/net/netdev_queues.h b/include/net/netdev_queues.h
+index 541e7d9853b1b..f6f1f71a24e15 100644
+--- a/include/net/netdev_queues.h
++++ b/include/net/netdev_queues.h
+@@ -14,6 +14,9 @@ struct netdev_config {
+ u8 hds_config;
+ };
+
++struct netdev_queue_config {
++};
++
+ /* See the netdev.yaml spec for definition of each statistic */
+ struct netdev_queue_stats_rx {
+ u64 bytes;
+@@ -130,6 +133,8 @@ void netdev_stat_queue_sum(struct net_device *netdev,
+ * @ndo_queue_get_dma_dev: Get dma device for zero-copy operations to be used
+ * for this queue. Return NULL on error.
+ *
++ * @ndo_default_qcfg: Populate queue config struct with defaults. Optional.
++ *
+ * Note that @ndo_queue_mem_alloc and @ndo_queue_mem_free may be called while
+ * the interface is closed. @ndo_queue_start and @ndo_queue_stop will only
+ * be called for an interface which is open.
+@@ -137,16 +142,20 @@ void netdev_stat_queue_sum(struct net_device *netdev,
+ struct netdev_queue_mgmt_ops {
+ size_t ndo_queue_mem_size;
+ int (*ndo_queue_mem_alloc)(struct net_device *dev,
++ struct netdev_queue_config *qcfg,
+ void *per_queue_mem,
+ int idx);
+ void (*ndo_queue_mem_free)(struct net_device *dev,
+ void *per_queue_mem);
+ int (*ndo_queue_start)(struct net_device *dev,
++ struct netdev_queue_config *qcfg,
+ void *per_queue_mem,
+ int idx);
+ int (*ndo_queue_stop)(struct net_device *dev,
+ void *per_queue_mem,
+ int idx);
++ void (*ndo_default_qcfg)(struct net_device *dev,
++ struct netdev_queue_config *qcfg);
+ struct device * (*ndo_queue_get_dma_dev)(struct net_device *dev,
+ int idx);
+ };
+diff --git a/include/net/netdev_rx_queue.h b/include/net/netdev_rx_queue.h
+index 8cdcd138b33f2..cfa72c4853876 100644
+--- a/include/net/netdev_rx_queue.h
++++ b/include/net/netdev_rx_queue.h
+@@ -7,6 +7,7 @@
+ #include <linux/sysfs.h>
+ #include <net/xdp.h>
+ #include <net/page_pool/types.h>
++#include <net/netdev_queues.h>
+
+ /* This structure contains an instance of an RX queue. */
+ struct netdev_rx_queue {
+@@ -27,6 +28,7 @@ struct netdev_rx_queue {
+ struct xsk_buff_pool *pool;
+ #endif
+ struct napi_struct *napi;
++ struct netdev_queue_config qcfg;
+ struct pp_memory_provider_params mp_params;
+ } ____cacheline_aligned_in_smp;
+
+diff --git a/net/core/dev.c b/net/core/dev.c
+index a83083e8761b1..e4ea5615e81ea 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -11223,6 +11223,21 @@ static void netdev_free_phy_link_topology(struct net_device *dev)
+ }
+ }
+
++static void init_rx_queue_cfgs(struct net_device *dev)
++{
++ const struct netdev_queue_mgmt_ops *qops = dev->queue_mgmt_ops;
++ struct netdev_rx_queue *rxq;
++ int i;
++
++ if (!qops || !qops->ndo_default_qcfg)
++ return;
++
++ for (i = 0; i < dev->num_rx_queues; i++) {
++ rxq = __netif_get_rx_queue(dev, i);
++ qops->ndo_default_qcfg(dev, &rxq->qcfg);
++ }
++}
++
+ /**
+ * register_netdevice() - register a network device
+ * @dev: device to register
+@@ -11268,6 +11283,8 @@ int register_netdevice(struct net_device *dev)
+ if (!dev->name_node)
+ goto out;
+
++ init_rx_queue_cfgs(dev);
++
+ /* Init, if this function is available */
+ if (dev->netdev_ops->ndo_init) {
+ ret = dev->netdev_ops->ndo_init(dev);
+diff --git a/net/core/netdev_rx_queue.c b/net/core/netdev_rx_queue.c
+index c7d9341b76307..f18147b478688 100644
+--- a/net/core/netdev_rx_queue.c
++++ b/net/core/netdev_rx_queue.c
+@@ -22,6 +22,7 @@ int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx)
+ {
+ struct netdev_rx_queue *rxq = __netif_get_rx_queue(dev, rxq_idx);
+ const struct netdev_queue_mgmt_ops *qops = dev->queue_mgmt_ops;
++ struct netdev_queue_config qcfg;
+ void *new_mem, *old_mem;
+ int err;
+
+@@ -31,6 +32,10 @@ int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx)
+
+ netdev_assert_locked(dev);
+
++ memset(&qcfg, 0, sizeof(qcfg));
++ if (qops->ndo_default_qcfg)
++ qops->ndo_default_qcfg(dev, &qcfg);
++
+ new_mem = kvzalloc(qops->ndo_queue_mem_size, GFP_KERNEL);
+ if (!new_mem)
+ return -ENOMEM;
+@@ -41,7 +46,7 @@ int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx)
+ goto err_free_new_mem;
+ }
+
+- err = qops->ndo_queue_mem_alloc(dev, new_mem, rxq_idx);
++ err = qops->ndo_queue_mem_alloc(dev, &qcfg, new_mem, rxq_idx);
+ if (err)
+ goto err_free_old_mem;
+
+@@ -54,7 +59,7 @@ int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx)
+ if (err)
+ goto err_free_new_queue_mem;
+
+- err = qops->ndo_queue_start(dev, new_mem, rxq_idx);
++ err = qops->ndo_queue_start(dev, &qcfg, new_mem, rxq_idx);
+ if (err)
+ goto err_start_queue;
+ } else {
+@@ -66,6 +71,7 @@ int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx)
+ kvfree(old_mem);
+ kvfree(new_mem);
+
++ rxq->qcfg = qcfg;
+ return 0;
+
+ err_start_queue:
+@@ -76,7 +82,7 @@ int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx)
+ * WARN if we fail to recover the old rx queue, and at least free
+ * old_mem so we don't also leak that.
+ */
+- if (qops->ndo_queue_start(dev, old_mem, rxq_idx)) {
++ if (qops->ndo_queue_start(dev, &rxq->qcfg, old_mem, rxq_idx)) {
+ WARN(1,
+ "Failed to restart old queue in error path. RX queue %d may be unhealthy.",
+ rxq_idx);
+--
+2.53.0
+
--- /dev/null
+From 29cdbab9bcd2e7dba7f145c95ccf34d98b3ce8f1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 13:15:08 +0000
+Subject: net/atm: fix slab-out-of-bounds read in vcc_setsockopt()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit d0c80dbb970439bd2eeb0e5effff8c16a5f4e1e3 ]
+
+vcc_setsockopt() contained an ineffective optlen check:
+ if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
+ return -EINVAL;
+
+If __SO_LEVEL_MATCH(optname, level) evaluated to false (e.g. if the caller
+passed a mismatched level), the length check optlen != __SO_SIZE(optname)
+was short-circuited and bypassed. Execution then fell through to switch(optname),
+calling copy_from_sockptr() assuming optval contained sufficient space.
+
+Furthermore, even if level matched, a cgroup BPF setsockopt filter could shrink
+optlen after entry. Because copy_from_sockptr() on kernel pointers uses memcpy(),
+this leads to a KASAN slab-out-of-bounds read when optlen is smaller than the
+expected structure size.
+
+Fix this by using copy_safe_from_sockptr(), which unconditionally validates
+that optlen is at least the expected size before copying. Also change the local
+'value' variable type from 'unsigned long' to 'int' so that SO_SETCLP matches
+its sizeof(int) ABI encoding on 64-bit systems.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: syzbot+53ecc09fb81df10ef4de@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=53ecc09fb81df10ef4de
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260805131508.3227331-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/atm/common.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/net/atm/common.c b/net/atm/common.c
+index f4c6e0131c921..f4be6cb220861 100644
+--- a/net/atm/common.c
++++ b/net/atm/common.c
+@@ -760,7 +760,7 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
+ sockptr_t optval, unsigned int optlen)
+ {
+ struct atm_vcc *vcc;
+- unsigned long value;
++ int value;
+ int error;
+
+ if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
+@@ -772,8 +772,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
+ {
+ struct atm_qos qos;
+
+- if (copy_from_sockptr(&qos, optval, sizeof(qos)))
+- return -EFAULT;
++ error = copy_safe_from_sockptr(&qos, sizeof(qos), optval,
++ optlen);
++ if (error)
++ return error;
+ error = check_qos(&qos);
+ if (error)
+ return error;
+@@ -786,8 +788,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
+ return 0;
+ }
+ case SO_SETCLP:
+- if (copy_from_sockptr(&value, optval, sizeof(value)))
+- return -EFAULT;
++ error = copy_safe_from_sockptr(&value, sizeof(value), optval,
++ optlen);
++ if (error)
++ return error;
+ if (value)
+ vcc->atm_options |= ATM_ATMOPT_CLP;
+ else
+--
+2.53.0
+
--- /dev/null
+From f85fc2f0b87800e63b00f5d0247d15aa328d45ee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 12:17:10 +0400
+Subject: net: hisilicon: hix5hd2_gmac: remove redundant NAPI delete
+
+From: Jiawen Liu <1298662399@qq.com>
+
+[ Upstream commit f307a7dc32097c11413178fca437a10d20890bc2 ]
+
+hix5hd2_dev_remove() calls netif_napi_del() before unregister_netdev().
+This is not needed because free_netdev() deletes all NAPI instances
+attached to the net_device.
+
+Remove the redundant call and let the networking core tear down the NAPI
+instance during unregister_netdev(). The probe error path still keeps its
+explicit netif_napi_del(), because the device has not been registered
+there.
+
+Fixes: 57c5bc9ad7d7 ("net: hisilicon: add hix5hd2 mac driver")
+Signed-off-by: Jiawen Liu <1298662399@qq.com>
+Link: https://patch.msgid.link/tencent_5FFD37A252B4FEA6A80AD25B17C8E904F005@qq.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hix5hd2_gmac.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+index e3e7f2270560c..02282dc86faf4 100644
+--- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
++++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+@@ -1282,7 +1282,6 @@ static void hix5hd2_dev_remove(struct platform_device *pdev)
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct hix5hd2_priv *priv = netdev_priv(ndev);
+
+- netif_napi_del(&priv->napi);
+ unregister_netdev(ndev);
+ mdiobus_unregister(priv->bus);
+ mdiobus_free(priv->bus);
+--
+2.53.0
+
--- /dev/null
+From 14b6ecce397d8f08fa8d54bac30a5a21f0852567 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jul 2026 17:30:36 +0800
+Subject: net: hns3: fix speed configuration residue after driver reload
+
+From: Jijie Shao <shaojijie@huawei.com>
+
+[ Upstream commit 3860d8748af315bfee6fe669fddc1fc17d3214db ]
+
+After setting a 100G optical port to 40G via ethtool and reloading
+the driver, the port remains at 40G instead of reverting to the
+firmware default speed of 100G.
+
+The commit referenced in Fixes: added two overwrites in
+hclge_init_ae_dev() for non-copper media, so that optical ports
+connected to forced-mode remotes inherit the firmware-preset
+autoneg and speed instead of the hardcoded defaults:
+
+ req_autoneg = mac.autoneg
+ req_speed = mac.speed (when autoneg disabled)
+
+The autoneg overwrite keeps existing behavior:
+hclge_set_autoneg_speed_dup() already uses mac.autoneg (not
+req_autoneg) since it was introduced, so autoneg inheritance from
+firmware was already in place. This part is kept.
+
+The speed overwrite, however, introduces the residue: mac.speed
+reflects whatever was last programmed into the MAC, and after unload
+firmware does not restore the MAC speed to the flash default. So if
+the user changed speed via ethtool in a prior load, mac.speed still
+carries that value on reload and req_speed inherits it.
+
+Fix by dropping the req_speed overwrite only. req_speed keeps the
+firmware default value set in hclge_configure() (cfg.default_speed),
+so a reload reverts the speed to default, matching the expectation
+that a driver reload resets link configuration.
+
+Trade-off: on optical ports whose firmware default speed does not
+match a forced-mode remote, reload now drops the link and the user
+must re-apply ethtool configuration. This is acceptable: a driver
+reload is expected to reset link configuration, not to inherit
+runtime state from before unload. The autoneg inheritance is left
+in place as established behavior; changing it is out of scope for
+this patch and would itself be a user-perceivable behavior change.
+
+Fixes: d9d349c4e8a0 ("net: hns3: differentiate autoneg default values between copper and fiber")
+Signed-off-by: Jijie Shao <shaojijie@huawei.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260724093036.426631-1-shaojijie@huawei.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+index 7f174453928c1..02fee71c20886 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+@@ -11930,12 +11930,8 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
+ if (ret)
+ goto err_ptp_uninit;
+
+- if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_COPPER) {
++ if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_COPPER)
+ hdev->hw.mac.req_autoneg = hdev->hw.mac.autoneg;
+- if (hdev->hw.mac.autoneg == AUTONEG_DISABLE &&
+- hdev->hw.mac.speed != SPEED_UNKNOWN)
+- hdev->hw.mac.req_speed = hdev->hw.mac.speed;
+- }
+
+ ret = hclge_set_autoneg_speed_dup(hdev);
+ if (ret) {
+--
+2.53.0
+
--- /dev/null
+From c407f2d60c0f5a44fa5e60229849286d9a2f44e8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 11:04:02 +0300
+Subject: net/mlx5: fw_tracer, return NULL on create error
+
+From: Michael Guralnik <michaelgur@nvidia.com>
+
+[ Upstream commit af39eb111ce6b5eba9c08513b62c4868eb7e7fd5 ]
+
+Tracer creation can fail by returning either NULL or ERR_PTR.
+The return value is stored without a check on the device, and users
+treat ERR_PTR and NULL the same way.
+This also causes a crash in the core dump logic, which is missing the
+ERR_PTR check and ends up dereferencing it, as shown in the trace below.
+
+Switch tracer creation to return NULL on failure only, so callers only
+need a single NULL check.
+
+ Internal error: Oops: 0000000096000006 [#1] SMP
+ Modules linked in: mlx5_ib ib_uverbs ib_core ipv6 mlx5_core
+ CPU: 1 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted 6.19.7 #1 PREEMPT(none)
+ Workqueue: mlx5_health0001:01:00.0 mlx5_fw_reporter_err_work [mlx5_core]
+ pstate: a3400009 (NzCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
+ pc : mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core]
+ lr : mlx5_fw_tracer_trigger_core_dump_general+0x40/0xe0 [mlx5_core]
+ sp : ffff800081cf3c40
+ x29: ffff800081cf3c90 x28: 0000000000000000 x27: 0000000000000000
+ x26: ffff000080018828 x25: 0000000000000000 x24: ffff000080304a05
+ x23: ffff800081cf3d80 x22: ffff0000847e01a0 x21: 0000000000000000
+ x20: ffff0000847e01a0 x19: ffffffffffffffa1 x18: ffff80008310bbf0
+ x17: ffff800080119650 x16: ffff80008010df54 x15: ffff80008010d4ac
+ x14: ffff800079c202e4 x13: ffff80008002fe60 x12: ffff800080119650
+ x11: ffff80008010df54 x10: ffff80008010d4ac x9 : ffff800079c203d8
+ x8 : ffff800081cf3c88 x7 : 0000000000000000 x6 : 0000000000000000
+ x5 : 0000000000000000 x4 : 0000000000000008 x3 : 0000000000000030
+ x2 : 0000000000000008 x1 : 0000000000000000 x0 : 00000000c5c4000e
+ Call trace:
+ mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core] (P)
+ mlx5_fw_reporter_dump+0x30/0x2e0 [mlx5_core]
+ devlink_health_do_dump+0x9c/0x160
+ devlink_health_report+0x1c0/0x288
+ mlx5_fw_reporter_err_work+0xac/0xc0 [mlx5_core]
+ process_one_work+0x15c/0x3d8
+ worker_thread+0x18c/0x320
+ kthread+0x148/0x228
+ ret_from_fork+0x10/0x20
+ Code: b9400000 5ac00800 7a401800 540003ca (3940a260)
+ ---[ end trace 0000000000000000 ]---
+ Kernel panic - not syncing: Oops: Fatal exception
+ SMP: stopping secondary CPUs
+ Kernel Offset: disabled
+ CPU features: 0x000000,00078031,75fce5a1,35fffe67
+ Memory Limit: none
+ ---[ end Kernel panic - not syncing: Oops: Fatal exception ]---
+
+Fixes: fd1483fe1f9f ("net/mlx5: Add support for FW reporter dump")
+Signed-off-by: Michael Guralnik <michaelgur@nvidia.com>
+Reviewed-by: Shay Drori <shayd@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260729080402.2427184-1-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ethernet/mellanox/mlx5/core/diag/fw_tracer.c | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+index 0b82a6a133d6c..74f68b70ad1c1 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+@@ -1025,13 +1025,11 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
+
+ tracer = kvzalloc(sizeof(*tracer), GFP_KERNEL);
+ if (!tracer)
+- return ERR_PTR(-ENOMEM);
++ return NULL;
+
+ tracer->work_queue = create_singlethread_workqueue("mlx5_fw_tracer");
+- if (!tracer->work_queue) {
+- err = -ENOMEM;
++ if (!tracer->work_queue)
+ goto free_tracer;
+- }
+
+ tracer->dev = dev;
+
+@@ -1073,7 +1071,7 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
+ destroy_workqueue(tracer->work_queue);
+ free_tracer:
+ kvfree(tracer);
+- return ERR_PTR(err);
++ return NULL;
+ }
+
+ static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data);
+@@ -1084,7 +1082,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
+ struct mlx5_core_dev *dev;
+ int err;
+
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return 0;
+
+ if (!tracer->str_db.loaded)
+@@ -1134,7 +1132,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
+ /* Stop tracer + Cleanup HW resources */
+ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
+ {
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return;
+
+ mutex_lock(&tracer->state_lock);
+@@ -1163,7 +1161,7 @@ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
+ /* Free software resources (Buffers, etc ..) */
+ void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer)
+ {
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return;
+
+ mlx5_core_dbg(tracer->dev, "FWTracer: Destroy\n");
+@@ -1215,7 +1213,7 @@ int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer)
+ struct mlx5_core_dev *dev;
+ int err;
+
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return 0;
+
+ dev = tracer->dev;
+--
+2.53.0
+
--- /dev/null
+From 6371349ea2dfbcc3d33de7c97292ee4e75f9ccea Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 16:47:29 -0700
+Subject: net/mlx5e: fix BQL reset on SQ re-activation
+
+From: Bobby Eshleman <bobbyeshleman@meta.com>
+
+[ Upstream commit e7386770be1bf810bcd6af39d1e4bfeab3408430 ]
+
+mlx5e_queue_start() deactivates and re-activates all channels but closes
+only the queue being restarted. mlx5e_activate_txqsq() then
+unconditionally calls netdev_tx_reset_queue(), zeroing the BQL counters
+of channels that kept their in-flight TX WQEs. The next completion then
+over-charges and trips the BUG_ON() in dql_completed():
+
+ kernel BUG at lib/dynamic_queue_limits.c:99!
+ RIP: 0010:dql_completed+0x23d/0x280
+ Call Trace:
+ <IRQ>
+ mlx5e_poll_tx_cq+0x668/0xa60
+ mlx5e_napi_poll+0x5b/0x7b0
+ net_rx_action+0x15a/0x580
+
+Reset BQL only when the SQ has no bytes in flight (sq->cc == sq->pc).
+
+In the case that reset is skipped, the outstanding WQEs will eventually
+complete and rebalance the dql. The dql->limit is carried across the
+reset.
+
+Fixes: b2588ea40ec9 ("net/mlx5e: Implement queue mgmt ops and single channel swap")
+Signed-off-by: Bobby Eshleman <bobbyeshleman@meta.com>
+Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260803-mlx5-bql-v3-1-a30d4c66fe1d@meta.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index 58e255910c43e..a7d84b540488a 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -1926,8 +1926,10 @@ int mlx5e_open_txqsq(struct mlx5e_channel *c, u32 tisn, int txq_ix,
+ void mlx5e_activate_txqsq(struct mlx5e_txqsq *sq)
+ {
+ sq->txq = netdev_get_tx_queue(sq->netdev, sq->txq_ix);
++ /* Reset BQL only when the SQ has no bytes in flight. */
++ if (sq->cc == sq->pc)
++ netdev_tx_reset_queue(sq->txq);
+ set_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
+- netdev_tx_reset_queue(sq->txq);
+ netif_tx_start_queue(sq->txq);
+ netif_queue_set_napi(sq->netdev, sq->txq_ix, NETDEV_QUEUE_TYPE_TX, sq->cq.napi);
+ }
+--
+2.53.0
+
--- /dev/null
+From d513e5a9d3274974e85faba87cf8adaca7eb6619 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 07:43:38 +0300
+Subject: net/mlx5e: TC, Check if flow is PEER before acquiring devcom lock
+
+From: Shay Drory <shayd@nvidia.com>
+
+[ Upstream commit 6ddfba2ea98db21b001e0e5c472499156224650c ]
+
+In case __mlx5e_add_fdb_flow() fails in lower levels, the flow is
+deleted via mlx5e_tc_del_flow(), and mlx5e_tc_del_flow() is acquiring
+ESW devcom lock without condition. In addition, in case of peer_flow,
+__mlx5e_add_fdb_flow() is called while holding ESW devcom comp lock.
+This results in an AA deadlock.
+
+To fix this, introduce a new PEER flag that is set on flows created as
+peer flows (the duplicate flows on peer devices), and check it in
+mlx5e_tc_del_flow() before acquiring ESW devcom lock.
+
+Lockdep splat:
+============================================
+WARNING: possible recursive locking detected
+============================================
+ Possible unsafe locking scenario:
+ CPU0
+ ----
+ lock(&comp->lock_key#2);
+ lock(&comp->lock_key#2);
+ *** DEADLOCK ***
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0x69/0xa0
+ print_deadlock_bug.cold+0xbd/0xca
+ __lock_acquire+0x1671/0x2ec0
+ lock_acquire+0x10e/0x2e0
+ down_read+0x95/0x430
+ mlx5_devcom_for_each_peer_begin+0x4e/0xe0 [mlx5_core]
+ mlx5e_tc_del_flow+0x11d/0xa70 [mlx5_core]
+ mlx5e_flow_put+0x99/0x100 [mlx5_core]
+ __mlx5e_add_fdb_flow+0x409/0xf00 [mlx5_core]
+ mlx5e_configure_flower+0x2a86/0x4100 [mlx5_core]
+ mlx5e_rep_setup_tc_cls_flower+0x12f/0x1b0 [mlx5_core]
+ mlx5e_rep_setup_tc_cb+0x153/0x750 [mlx5_core]
+ tc_setup_cb_add+0x1dc/0x470
+ fl_change+0x2f4d/0x626d [cls_flower]
+ tc_new_tfilter+0x79b/0x2310
+ rtnetlink_rcv_msg+0x778/0xad0
+ do_syscall_64+0x70/0x960
+ entry_SYSCALL_64_after_hwframe+0x4b/0x53
+ </TASK>
+
+Fixes: 04de7dda7394 ("net/mlx5e: Infrastructure for duplicated offloading of TC flows")
+Signed-off-by: Shay Drory <shayd@nvidia.com>
+Reviewed-by: Cosmin Ratiu <cratiu@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260728044338.2271143-1-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h | 1 +
+ drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 4 +++-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
+index efb34de4cb7ad..692ac2f21d94e 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
+@@ -30,6 +30,7 @@ enum {
+ MLX5E_TC_FLOW_FLAG_FAILED = MLX5E_TC_FLOW_BASE + 9,
+ MLX5E_TC_FLOW_FLAG_SAMPLE = MLX5E_TC_FLOW_BASE + 10,
+ MLX5E_TC_FLOW_FLAG_USE_ACT_STATS = MLX5E_TC_FLOW_BASE + 11,
++ MLX5E_TC_FLOW_FLAG_PEER = MLX5E_TC_FLOW_BASE + 12,
+ };
+
+ struct mlx5e_tc_flow_parse_attr {
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+index ebea43c235cc3..e2de3a9a647c3 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+@@ -2165,7 +2165,8 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
+ if (mlx5e_is_eswitch_flow(flow)) {
+ struct mlx5_devcom_comp_dev *devcom = flow->priv->mdev->priv.eswitch->devcom;
+
+- if (!mlx5_devcom_for_each_peer_begin(devcom)) {
++ if (flow_flag_test(flow, PEER) ||
++ !mlx5_devcom_for_each_peer_begin(devcom)) {
+ mlx5e_tc_del_fdb_flow(priv, flow);
+ return;
+ }
+@@ -4609,6 +4610,7 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f,
+ else
+ in_mdev = priv->mdev;
+
++ flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_PEER);
+ parse_attr = flow->attr->parse_attr;
+ peer_flow = __mlx5e_add_fdb_flow(peer_priv, f, flow_flags,
+ parse_attr->filter_dev,
+--
+2.53.0
+
--- /dev/null
+From 37898435c35b4fcd5c4eb9d33eb0d846f9476bbd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 12:36:18 +0800
+Subject: net/ncsi: fix heap OOB read in NCSI_CMD_SEND_CMD payload length
+
+From: Henry Martin <bsdhenrymartin@gmail.com>
+
+[ Upstream commit afa58b7384913c8773d837acdb07b035690ec5d2 ]
+
+ncsi_send_cmd_nl() takes the number of bytes to copy from the
+attacker-controlled ncsi_pkt_hdr.length field of the in-band packet
+header, while the source buffer is the NCSI_ATTR_DATA netlink
+attribute whose readable size is nla_len() - sizeof(ncsi_pkt_hdr).
+The two length sources are never cross-checked: only
+nla_len() >= sizeof(struct ncsi_pkt_hdr) is enforced.
+
+With hdr->length set larger than the attribute payload (up to 65535
+against at most 2032 readable bytes), ncsi_cmd_handler_oem() copies
+past the end of the netlink attribute buffer with unsafe_memcpy(),
+leaking up to ~64KB of kernel heap memory into the transmitted NCSI
+command packet. The destination skb is sized by the declared payload,
+so the write side does not overflow - this is a pure OOB read /
+information leak, reachable with CAP_NET_ADMIN on systems with a
+registered NCSI device (e.g. OpenBMC on Aspeed BMC SoCs, where
+NET_NCSI=y is standard).
+
+Reject commands whose declared payload extends past the end of the
+data attribute.
+
+The issue was found by the autokbug dynamic kernel fuzzer at Tencent
+Yunding Lab.
+
+Fixes: 9771b8ccdfa6 ("net/ncsi: Extend NC-SI Netlink interface to allow user space to send NC-SI command")
+Reported-by: Henry Martin <bsdhenrymartin@gmail.com>
+Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>
+Link: https://patch.msgid.link/20260803043618.3210301-1-bsdhenrymartin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ncsi/ncsi-netlink.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/net/ncsi/ncsi-netlink.c b/net/ncsi/ncsi-netlink.c
+index 2f872d064396d..8cc538358f6a3 100644
+--- a/net/ncsi/ncsi-netlink.c
++++ b/net/ncsi/ncsi-netlink.c
+@@ -461,6 +461,10 @@ static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info)
+ nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN;
+ nca.info = info;
+ nca.payload = ntohs(hdr->length);
++ if (nca.payload > len - sizeof(*hdr)) {
++ ret = -EINVAL;
++ goto out_netlink;
++ }
+ nca.data = data + sizeof(*hdr);
+
+ ret = ncsi_xmit_cmd(&nca);
+--
+2.53.0
+
--- /dev/null
+From f05ba68c48e829e2d513ed9d4047af14e2f19b6b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 18:20:06 -0400
+Subject: net/openvswitch: check Ethernet header length in key_extract()
+
+From: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+
+[ Upstream commit cf6f8b29befb92173659bcef6a441d274947bfae ]
+
+When a packet arrives on an ARPHRD_NONE device (e.g. TUN),
+ovs_flow_key_extract() trusts the user-provided skb->protocol field: if
+it is ETH_P_TEB, the packet is classified as MAC_PROTO_ETHERNET and
+key_extract() is called without ensuring the skb has ETH_HLEN (14) bytes
+of linear data. key_extract() unconditionally pulls 2 * ETH_ALEN bytes
+for MAC addresses and parse_ethertype() pulls 2 more, either of which
+triggers a kernel BUG in __skb_pull() when the linear area is too small.
+
+ kernel BUG at include/linux/skbuff.h:2848!
+ RIP: 0010:key_extract+0xa7e/0xd90 net/openvswitch/flow.c:933
+ ovs_flow_key_extract+0x419/0xa70
+ ovs_vport_receive+0x222/0x390
+ netdev_frame_hook+0x3e0/0x630
+ tun_get_user+0x2d0c/0x38e0
+
+Fixed by calling check_header() in key_extract() before accessing the
+Ethernet header.
+
+Fixes: 217ac77a3c25 ("openvswitch: allow L3 netdev ports")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Reviewed-by: Eelco Chaudron <echaudro@redhat.com>
+Signed-off-by: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
+Link: https://patch.msgid.link/20260730222006.118652-1-blbllhy@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/flow.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
+index 66366982f6044..46c1d66aad8c3 100644
+--- a/net/openvswitch/flow.c
++++ b/net/openvswitch/flow.c
+@@ -889,8 +889,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ * Ethernet header
+ * @key: output flow key
+ *
+- * The caller must ensure that skb->len >= ETH_HLEN.
+- *
+ * Initializes @skb header fields as follows:
+ *
+ * - skb->mac_header: the L2 header.
+@@ -910,8 +908,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ */
+ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+ {
+- struct ethhdr *eth;
+-
+ /* Flags are always used as part of stats */
+ key->tp.flags = 0;
+
+@@ -926,6 +922,13 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+ skb_reset_network_header(skb);
+ key->eth.type = skb->protocol;
+ } else {
++ struct ethhdr *eth;
++ int err;
++
++ err = check_header(skb, ETH_HLEN);
++ if (unlikely(err))
++ return err;
++
+ eth = eth_hdr(skb);
+ ether_addr_copy(key->eth.src, eth->h_source);
+ ether_addr_copy(key->eth.dst, eth->h_dest);
+--
+2.53.0
+
--- /dev/null
+From 5bdf7ae5af6e7417d271955d8193c1dde850d7ab Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Jan 2026 13:25:40 +0000
+Subject: net: pass queue rx page size from memory provider
+
+From: Pavel Begunkov <asml.silence@gmail.com>
+
+[ Upstream commit c0b709bf438ba9d197d369f55e4a97603fd4a705 ]
+
+Allow memory providers to configure rx queues with a custom receive
+page size. It's passed in struct pp_memory_provider_params, which is
+copied into the queue, so it's preserved across queue restarts. Then,
+it's propagated to the driver in a new queue config parameter.
+
+Drivers should explicitly opt into using it by setting
+QCFG_RX_PAGE_SIZE, in which case they should implement ndo_default_qcfg,
+validate the size on queue restart and honour the current config in case
+of a reset.
+
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netdev_queues.h | 10 ++++++++++
+ include/net/page_pool/types.h | 1 +
+ net/core/netdev_rx_queue.c | 9 +++++++++
+ 3 files changed, 20 insertions(+)
+
+diff --git a/include/net/netdev_queues.h b/include/net/netdev_queues.h
+index f6f1f71a24e15..feca25131930b 100644
+--- a/include/net/netdev_queues.h
++++ b/include/net/netdev_queues.h
+@@ -15,6 +15,7 @@ struct netdev_config {
+ };
+
+ struct netdev_queue_config {
++ u32 rx_page_size;
+ };
+
+ /* See the netdev.yaml spec for definition of each statistic */
+@@ -114,6 +115,11 @@ void netdev_stat_queue_sum(struct net_device *netdev,
+ int tx_start, int tx_end,
+ struct netdev_queue_stats_tx *tx_sum);
+
++enum {
++ /* The queue checks and honours the page size qcfg parameter */
++ QCFG_RX_PAGE_SIZE = 0x1,
++};
++
+ /**
+ * struct netdev_queue_mgmt_ops - netdev ops for queue management
+ *
+@@ -135,6 +141,8 @@ void netdev_stat_queue_sum(struct net_device *netdev,
+ *
+ * @ndo_default_qcfg: Populate queue config struct with defaults. Optional.
+ *
++ * @supported_params: Bitmask of supported parameters, see QCFG_*.
++ *
+ * Note that @ndo_queue_mem_alloc and @ndo_queue_mem_free may be called while
+ * the interface is closed. @ndo_queue_start and @ndo_queue_stop will only
+ * be called for an interface which is open.
+@@ -158,6 +166,8 @@ struct netdev_queue_mgmt_ops {
+ struct netdev_queue_config *qcfg);
+ struct device * (*ndo_queue_get_dma_dev)(struct net_device *dev,
+ int idx);
++
++ unsigned int supported_params;
+ };
+
+ bool netif_rxq_has_unreadable_mp(struct net_device *dev, int idx);
+diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h
+index fb4f03ccd6156..cdd95477af7a2 100644
+--- a/include/net/page_pool/types.h
++++ b/include/net/page_pool/types.h
+@@ -161,6 +161,7 @@ struct memory_provider_ops;
+ struct pp_memory_provider_params {
+ void *mp_priv;
+ const struct memory_provider_ops *mp_ops;
++ u32 rx_page_size;
+ };
+
+ struct page_pool {
+diff --git a/net/core/netdev_rx_queue.c b/net/core/netdev_rx_queue.c
+index f18147b478688..485bdb7447b99 100644
+--- a/net/core/netdev_rx_queue.c
++++ b/net/core/netdev_rx_queue.c
+@@ -30,12 +30,21 @@ int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx)
+ !qops->ndo_queue_mem_alloc || !qops->ndo_queue_start)
+ return -EOPNOTSUPP;
+
++ if (WARN_ON_ONCE(qops->supported_params && !qops->ndo_default_qcfg))
++ return -EINVAL;
++
+ netdev_assert_locked(dev);
+
+ memset(&qcfg, 0, sizeof(qcfg));
+ if (qops->ndo_default_qcfg)
+ qops->ndo_default_qcfg(dev, &qcfg);
+
++ if (rxq->mp_params.rx_page_size) {
++ if (!(qops->supported_params & QCFG_RX_PAGE_SIZE))
++ return -EOPNOTSUPP;
++ qcfg.rx_page_size = rxq->mp_params.rx_page_size;
++ }
++
+ new_mem = kvzalloc(qops->ndo_queue_mem_size, GFP_KERNEL);
+ if (!new_mem)
+ return -ENOMEM;
+--
+2.53.0
+
--- /dev/null
+From 2ef5ff19fdf14ff7d193831ae8ca6e2d903c7b63 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 22:19:06 +0800
+Subject: net: prestera: validate firmware header length
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 8ae344eb540af3f457179b52bc6061416752485c ]
+
+prestera_fw_hdr_parse() reads the firmware header before checking
+that the firmware image contains that header.
+
+Reject images shorter than struct prestera_fw_header before decoding the
+magic and version fields.
+
+Fixes: 4c2703dfd7fabb ("net: marvell: prestera: Add PCI interface support")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Acked-by: Elad Nachman <enachman@marvell.com>
+Link: https://patch.msgid.link/20260731141500.1-prestera-v2-pengpeng@iscas.ac.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/marvell/prestera/prestera_pci.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/marvell/prestera/prestera_pci.c b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+index 3e13322470da6..bacc869551dfd 100644
+--- a/drivers/net/ethernet/marvell/prestera/prestera_pci.c
++++ b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+@@ -684,6 +684,9 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw)
+ struct prestera_fw_header *hdr;
+ u32 magic;
+
++ if (fw->bin->size < sizeof(*hdr))
++ return -EINVAL;
++
+ hdr = (struct prestera_fw_header *)fw->bin->data;
+
+ magic = be32_to_cpu(hdr->magic_number);
+--
+2.53.0
+
--- /dev/null
+From 2209506efea0bd9b6b24d96a485326140d2f89f1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 21 Apr 2025 15:28:15 -0700
+Subject: net: reduce indent of struct netdev_queue_mgmt_ops members
+
+From: Jakub Kicinski <kuba@kernel.org>
+
+[ Upstream commit 92d76cf96dcbc3c58daa84dbbf71a3ca8d9de53d ]
+
+Trivial change, reduce the indent. I think the original is copied
+from real NDOs. It's unnecessarily deep, makes passing struct args
+problematic.
+
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Reviewed-by: Mina Almasry <almasrymina@google.com>
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netdev_queues.h | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/include/net/netdev_queues.h b/include/net/netdev_queues.h
+index cd00e0406cf46..541e7d9853b1b 100644
+--- a/include/net/netdev_queues.h
++++ b/include/net/netdev_queues.h
+@@ -135,20 +135,20 @@ void netdev_stat_queue_sum(struct net_device *netdev,
+ * be called for an interface which is open.
+ */
+ struct netdev_queue_mgmt_ops {
+- size_t ndo_queue_mem_size;
+- int (*ndo_queue_mem_alloc)(struct net_device *dev,
+- void *per_queue_mem,
+- int idx);
+- void (*ndo_queue_mem_free)(struct net_device *dev,
+- void *per_queue_mem);
+- int (*ndo_queue_start)(struct net_device *dev,
+- void *per_queue_mem,
+- int idx);
+- int (*ndo_queue_stop)(struct net_device *dev,
+- void *per_queue_mem,
+- int idx);
+- struct device * (*ndo_queue_get_dma_dev)(struct net_device *dev,
+- int idx);
++ size_t ndo_queue_mem_size;
++ int (*ndo_queue_mem_alloc)(struct net_device *dev,
++ void *per_queue_mem,
++ int idx);
++ void (*ndo_queue_mem_free)(struct net_device *dev,
++ void *per_queue_mem);
++ int (*ndo_queue_start)(struct net_device *dev,
++ void *per_queue_mem,
++ int idx);
++ int (*ndo_queue_stop)(struct net_device *dev,
++ void *per_queue_mem,
++ int idx);
++ struct device * (*ndo_queue_get_dma_dev)(struct net_device *dev,
++ int idx);
+ };
+
+ bool netif_rxq_has_unreadable_mp(struct net_device *dev, int idx);
+--
+2.53.0
+
--- /dev/null
+From 2680d67ddd192bd42d887bbe837c73e558f2bb65 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 15:20:48 +0000
+Subject: net: remove WARN_ON_ONCE() from sk_mc_loop()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit b8a39a09ae4eaae04309e1e38ed6a1101d967496 ]
+
+sk_mc_loop() can be called for sockets that are neither AF_INET
+nor AF_INET6 (e.g. AF_PACKET sockets when sending packets via raw/packet
+socket over virtual devices such as VRF or ipvlan).
+
+In such cases, sk_family is not AF_INET/AF_INET6 and sk_mc_loop() falls
+through the switch statement and triggers WARN_ON_ONCE(1).
+
+Non-INET sockets do not support IP_MULTICAST_LOOP or IPV6_MULTICAST_LOOP
+options, so loopback should default to true without generating a warning.
+
+Fixes: f60e5990d9c1 ("ipv6: protect skb->sk accesses from recursive dereference inside the stack")
+Reported-by: syzbot+22c3218a6fa219e47321@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/6a72024c.13623e66.bdc14.0019.GAE@google.com/T/#u
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260804152048.2134341-1-edumazet@google.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/sock.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/net/core/sock.c b/net/core/sock.c
+index 5a658606c50e8..b69c574c20ad3 100644
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -786,7 +786,6 @@ bool sk_mc_loop(const struct sock *sk)
+ return inet6_test_bit(MC6_LOOP, sk);
+ #endif
+ }
+- WARN_ON_ONCE(1);
+ return true;
+ }
+ EXPORT_SYMBOL(sk_mc_loop);
+--
+2.53.0
+
--- /dev/null
+From 76d1acd39b44c4fa0ec75f9a04f60e933b7cdcd5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 1 Aug 2026 08:56:32 -0400
+Subject: net/sched: cls_api: Always acquire rtnl_lock when destroying locked
+ classifiers
+
+From: Jamal Hadi Salim <jhs@mojatatu.com>
+
+[ Upstream commit a347304b2ca1a5377d5bd2d8a72e4b4f12afe648 ]
+
+Another challenge with unlocked filters.
+There is a short window in tc_new_tfilter where a tcf_proto can be found
+and briefly referenced by a totally unrelated, unlocked classifier's request
+and cause a race.
+
+Feng created a poc which created this race with two threads, one creating a
+u32 filter and other a flower filter in the same chain/prio:
+
+1. Both threads enter tc_new_tfilter, both find the chain empty, both
+ drop filter_chain_lock
+2. u32 finishes tcf_proto_create("u32") first, calls
+ tcf_chain_tp_insert_unique() -> inserts u32_tp into the chain
+3. flower finishes tcf_proto_create("flower") later, calls
+ tcf_chain_tp_insert_unique() -> tcf_chain_tp_find() now sees u32_tp
+ already there, takes a reference on it, destroys flower's own tp_new
+ and returns u32_tp to the caller.
+
+Flower then hits the kind mismatch check (because it requested for kind
+"flower" but tp->ops->kind is "u32") and goes through the errout path
+which calls tcf_proto_put() on u32_tp. If the u32 thread has already
+gone through its own errout (its change() call failed on the PoC's empty
+options) and dropped its create and insert refs, flower's put is the
+last one and drops u32_tp's refcnt to zero.
+
+At this point tp->ops->destroy() runs in a context that never took
+rtnl_lock. When that happens, it might cause a UAF like the following
+(illustrated by the PoC):
+
+[ +0.000710] BUG: KASAN: slab-use-after-free in u32_init (net/sched/cls_u32.c:393)
+[ +0.000281] Read of size 8 at addr ffff888120022f00 by task poc_feng_xue/524
+
+ Call Trace:
+ u32_init (net/sched/cls_u32.c:393)
+ tc_new_tfilter (net/sched/cls_api.c:2378)
+
+ Allocated by task 526:
+ u32_init (net/sched/cls_u32.c:378)
+ tc_new_tfilter (net/sched/cls_api.c:2378)
+
+ Freed by task 522:
+ kfree
+ u32_destroy (net/sched/cls_u32.c:662)
+ tcf_proto_destroy (net/sched/cls_api.c:446)
+ tcf_proto_put (net/sched/cls_api.c:459)
+ tc_new_tfilter (net/sched/cls_api.c:2459)
+
+Fix this by having tcf_proto_destroy() take rtnl_lock around
+tp->ops->destroy() for locked classifiers whenever rtnl is not held.
+
+To explain why I used a temp variable "not_lockless" I'd like to point to a
+semi-related note on rtnl_held vs TCF_PROTO_OPS_DOIT_UNLOCKED (adding here
+for future cleanup if deemed necessary):
+The rtnl_held parameter and the TCF_PROTO_OPS_DOIT_UNLOCKED flag are
+redundant sources of truth for whether rtnl_lock is held. Among the nine
+classifier destroy(..rtnl_held..) callbacks, only flower consults the
+rtnl_held parameter which it propagates to tc_setup_cb_destroy()
+and tc_setup_cb_call(). The other eight (u32, flow, bpf, cgroup, route, basic,
+fw, mall) ignore it entirely;-> those that call tc_setup_cb_destroy()
+(u32, bpf, mall) hardcode true always instead of forwarding the parameter.
+
+A future cleanup should remove the rtnl_held parameter from the destroy callback
+signature entirely and have callers rely solely on their knowledge whether
+they are running in an unlocked context.
+
+Fixes: 12db03b65c2b ("net: sched: extend proto ops to support unlocked classifiers")
+Reported-by: Feng Xue <feng.xue@outlook.com>
+Tested-by: Victor Nogueira <victor@mojatatu.com>
+Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260801125632.360365-1-jhs@mojatatu.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_api.c | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index 3b0a438977cd5..21a70cc9940ce 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -443,7 +443,22 @@ static void tcf_chain_put(struct tcf_chain *chain);
+ static void tcf_proto_destroy(struct tcf_proto *tp, bool rtnl_held,
+ bool sig_destroy, struct netlink_ext_ack *extack)
+ {
+- tp->ops->destroy(tp, rtnl_held, extack);
++ /* A locked classifier's destroy callback (e.g. u32_destroy) uses
++ * rtnl_dereference() and mutates shared structures (e.g. the
++ * tc_u_common hash list) that are only safe under rtnl_lock. When an
++ * unlocked classifier's request (e.g. flower on ingress) loses the
++ * tcf_chain_tp_insert_unique() race and ends up dropping the last
++ * reference on a locked classifier's proto, destroy() would run
++ * without rtnl held. Take it here in that case.
++ */
++ bool not_lockless = !rtnl_held &&
++ !(tp->ops->flags & TCF_PROTO_OPS_DOIT_UNLOCKED);
++
++ if (not_lockless)
++ rtnl_lock();
++ tp->ops->destroy(tp, rtnl_held || not_lockless, extack);
++ if (not_lockless)
++ rtnl_unlock();
+ tcf_proto_count_usesw(tp, false);
+ if (sig_destroy)
+ tcf_proto_signal_destroyed(tp->chain, tp);
+--
+2.53.0
+
--- /dev/null
+From 0a82a2f52684cf16105c80364e1c48e4b891c7f3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 05:44:11 -0400
+Subject: net/sched: cls_route: fix fastmap use-after-free on filter
+
+From: Jamal Hadi Salim <jhs@mojatatu.com>
+
+[ Upstream commit 47d7f7051253bdc02b1d245d87e38f16d31a74df ]
+
+The route4 classifier maintains a 16-slot fastmap cache that stores raw
+struct route4_filter pointers indexed by (id, iif). The reader
+(route4_classify) populates this cache via route4_set_fastmap() for every
+classified packet that hits a filter. The writer (route4_delete,
+route4_change) clears the cache via route4_reset_fastmap() before
+RCU-deferred kfree of the filter.
+
+This creates a UAF race:
+ 1. Reader walks the RCU-protected bucket chain, finds filter f
+ 2. Writer unlinks f, calls route4_reset_fastmap(), then tcf_queue_work()
+ 3. Reader calls route4_set_fastmap() and writes f into the cache
+ *after* the writer's reset, caching a pointer about to be freed
+ 4. After the RCU grace period, kfree(f) executes
+ 5. Next classified packet on the same (id, iif) tuple hits the stale
+ fastmap entry and reads f->res from freed memory
+
+Reproduced with an mdelay(100) accelerator in route4_set_fastmap() and a
+concurrent add/delete stress test (provided by both zdi and Santosh).
+Both triggered KASAN slab-use-after-free reports in the route4 fastmap
+paths.
+
+Fix:
+Introduce a per-filter boolean dying flag to suppress stale fastmap
+republishing by in-flight readers.
+
+Fixes: 1109c00547fc ("net: sched: RCU cls_route")
+Reported-by: zdi-disclosures@trendmicro.com
+Reported-by: Santosh Kalluri <santosh.kalluri129@gmail.com>
+Suggested-by: Paolo Abeni <pabeni@redhat.com>
+Tested-by: Victor Nogueira <victor@mojatatu.com>
+Tested-by: Santosh Kalluri <santosh.kalluri129@gmail.com>
+Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260729094411.46257-1-jhs@mojatatu.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_route.c | 35 ++++++++++++++++++++++++++---------
+ 1 file changed, 26 insertions(+), 9 deletions(-)
+
+diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
+index b9c58c040c305..38469cdcb22d6 100644
+--- a/net/sched/cls_route.c
++++ b/net/sched/cls_route.c
+@@ -52,6 +52,7 @@ struct route4_filter {
+ struct tcf_result res;
+ struct tcf_exts exts;
+ u32 handle;
++ bool dying;
+ struct route4_bucket *bkt;
+ struct tcf_proto *tp;
+ struct rcu_work rwork;
+@@ -66,9 +67,11 @@ static inline int route4_fastmap_hash(u32 id, int iif)
+
+ static DEFINE_SPINLOCK(fastmap_lock);
+ static void
+-route4_reset_fastmap(struct route4_head *head)
++route4_reset_fastmap(struct route4_head *head, struct route4_filter *f)
+ {
+ spin_lock_bh(&fastmap_lock);
++ if (f)
++ f->dying = true;
+ memset(head->fastmap, 0, sizeof(head->fastmap));
+ spin_unlock_bh(&fastmap_lock);
+ }
+@@ -81,9 +84,11 @@ route4_set_fastmap(struct route4_head *head, u32 id, int iif,
+
+ /* fastmap updates must look atomic to aling id, iff, filter */
+ spin_lock_bh(&fastmap_lock);
+- head->fastmap[h].id = id;
+- head->fastmap[h].iif = iif;
+- head->fastmap[h].filter = f;
++ if (f == ROUTE4_FAILURE || !f->dying) {
++ head->fastmap[h].id = id;
++ head->fastmap[h].iif = iif;
++ head->fastmap[h].filter = f;
++ }
+ spin_unlock_bh(&fastmap_lock);
+ }
+
+@@ -297,6 +302,13 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
+ next = rtnl_dereference(f->next);
+ RCU_INIT_POINTER(b->ht[h2], next);
+ tcf_unbind_filter(tp, &f->res);
++ /* Mark the filter dying under fastmap_lock so
++ * any in-flight reader that still holds it
++ * will skip the republish in route4_set_fastmap().
++ */
++ spin_lock_bh(&fastmap_lock);
++ f->dying = true;
++ spin_unlock_bh(&fastmap_lock);
+ if (tcf_exts_get_net(&f->exts))
+ route4_queue_work(f);
+ else
+@@ -307,6 +319,11 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
+ kfree_rcu(b, rcu);
+ }
+ }
++
++ /* All filters are unlinked and marked dying, so no in-flight
++ * reader can republish a stale entry after this reset.
++ */
++ route4_reset_fastmap(head, NULL);
+ kfree_rcu(head, rcu);
+ }
+
+@@ -334,11 +351,11 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,
+ /* unlink it */
+ RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
+
+- /* Remove any fastmap lookups that might ref filter
+- * notice we unlink'd the filter so we can't get it
+- * back in the fastmap.
++ /* Clear any fastmap entries that may ref this filter and
++ * mark it dying so in-flight readers can't republish it
++ * after the reset.
+ */
+- route4_reset_fastmap(head);
++ route4_reset_fastmap(head, f);
+
+ /* Delete it */
+ tcf_unbind_filter(tp, &f->res);
+@@ -558,7 +575,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
+ }
+ }
+
+- route4_reset_fastmap(head);
++ route4_reset_fastmap(head, fold);
+ *arg = f;
+ if (fold) {
+ tcf_unbind_filter(tp, &fold->res);
+--
+2.53.0
+
--- /dev/null
+From e5db135a91ef6f4e032eca151060bac30fa41a77 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 21:14:16 +0200
+Subject: net/sched: sch_cake: drop WARN_ON(1) for malformed packets in ACK
+ filter
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Toke Høiland-Jørgensen <toke@toke.dk>
+
+[ Upstream commit 2a33516f9ef59ad11844d4fc152f889449b5daf3 ]
+
+The sch_cake ACK filter parses packets to find the TCP header and filter
+duplicated ACKs if the flow is backlogged. The parsing code contains a
+WARN_ON(1) which can be triggered by a malformed IP header in certain
+cases. Depending on the system configuration, this leads either to
+either spamming dmesg with warnings, or a panic if panic_on_warn is set.
+
+The code already correctly skips the offending packet in the branch that
+triggers the warning, so the WARN_ON itself doesn't really serve any
+purpose. So just drop it altogether to avoid the inconvenient side
+effects.
+
+Fixes: 8b7138814f29 ("sch_cake: Add optional ACK filter")
+Reported-by: Zhiling Zou <zhilinz@nebusec.ai>
+Reported-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
+Link: https://patch.msgid.link/20260729191417.45665-1-toke@toke.dk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_cake.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c
+index c19eeed7e7cfb..e03fe7096b357 100644
+--- a/net/sched/sch_cake.c
++++ b/net/sched/sch_cake.c
+@@ -1268,7 +1268,6 @@ static struct sk_buff *cake_ack_filter(struct cake_sched_data *q,
+
+ seglen = ntohs(ipv6h_check->payload_len);
+ } else {
+- WARN_ON(1); /* shouldn't happen */
+ continue;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 8273786ed9a3f5ae6704d9f909ca84fb058f2c60 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:01:53 +0200
+Subject: net/smc: fix qentry overwrite for CONFIRM_LINK and ADD_LINK_CONT in
+ smc_llc_event_handler()
+
+From: Mahanta Jambigi <mjambigi@linux.ibm.com>
+
+[ Upstream commit 976245094925bab9bc39366b2e9ab44ffcde61d0 ]
+
+The SMC_LLC_CONFIRM_LINK / SMC_LLC_ADD_LINK_CONT branch in
+smc_llc_event_handler() stores an incoming qentry into the local LLC flow
+without first checking whether a qentry is already pending. If a malicious or
+buggy peer sends a second CONFIRM_LINK or ADD_LINK_CONT request while a flow is
+active and flow->qentry is already set, smc_llc_flow_qentry_set() overwrites the
+pointer without freeing the previous allocation, leaking one kmalloc-96 object
+per spurious message.
+
+The sibling SMC_LLC_DELETE_LINK branch already has the correct !flow->qentry
+guard. Apply the same guard to the CONFIRM_LINK/ADD_LINK_CONT branch so that a
+duplicate message when qentry is already occupied falls through to break and is
+freed by the kfree(qentry) at the out: label, rather than silently leaking the
+existing allocation.
+
+The response direction (smc_llc_rx_response()) is unaffected: it already guards
+with flow->qentry at the equivalent site and drops duplicate responses
+correctly.
+
+Fixes: 0fb0b02bd6fd ("net/smc: adapt SMC client code to use the LLC flow")
+Signed-off-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
+Reviewed-by: Hidayath Khan <hidayath@linux.ibm.com>
+Reviewed-by: Sidraya Jayagond <sidraya@linux.ibm.com>
+Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
+Link: https://patch.msgid.link/20260729130153.970800-1-mjambigi@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/smc_llc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c
+index f865c58c3aa77..28873ec06e3c1 100644
+--- a/net/smc/smc_llc.c
++++ b/net/smc/smc_llc.c
+@@ -1927,7 +1927,8 @@ static void smc_llc_event_handler(struct smc_llc_qentry *qentry)
+ return;
+ case SMC_LLC_CONFIRM_LINK:
+ case SMC_LLC_ADD_LINK_CONT:
+- if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) {
++ if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE &&
++ !lgr->llc_flow_lcl.qentry) {
+ /* a flow is waiting for this message */
+ smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry);
+ wake_up(&lgr->llc_msg_waiter);
+--
+2.53.0
+
--- /dev/null
+From 5bb2833c886f1d22a54be87ab492b935118e4dd0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 09:07:01 +0200
+Subject: net/smc: fix TOCTOU race between smc_listen_out() and listener close
+
+From: Sidraya Jayagond <sidraya@linux.ibm.com>
+
+[ Upstream commit 185a4caeecabc150106deda1da170b09f2ad803f ]
+
+smc_listen_out() reads lsmc->sk.sk_state without the listener lock,
+then acquires lock_sock_nested() only after the check passes. This
+opens a window where smc_close_active() can transition the listener
+to SMC_CLOSED, call smc_close_cleanup_listen() to drain the accept
+queue, and release the lock, all between the lockless read and the
+delayed lock acquisition:
+
+ smc_listen_work (smc_hs_wq) smc_close_active()
+ ------------------------------- -------------------------
+ release_sock(child)
+ if (sk_state == SMC_LISTEN) TRUE
+ lock_sock(listener)
+ sk_state = SMC_CLOSED
+ smc_close_cleanup_listen()
+ release_sock(listener)
+ flush_work(tcp_listen_work)
+ lock_sock_nested(listener)
+ smc_accept_enqueue(listener, child) /* child enqueued on dead listener */
+
+smc_close_active() flushes only tcp_listen_work. Work items already
+dispatched onto smc_hs_wq for the CLC handshake continue running
+unguarded. smc_accept_enqueue() takes a sock_hold() on the child that
+is never released, so the child smc_sock, its clcsock, and the
+reference all leak. A remote peer that opens TCP connections while the
+server calls close() can exhaust kernel memory.
+
+Move lock_sock_nested() to before the sk_state check so that the test
+and the enqueue are atomic under the listener lock.
+
+Fixes: fd57770dd198 ("net/smc: wait for pending work before clcsock release_sock")
+Reviewed-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
+Signed-off-by: Sidraya Jayagond <sidraya@linux.ibm.com>
+Reviewed-by: Breno Leitao <leitao@debian.org>
+Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
+Link: https://patch.msgid.link/20260803070701.126339-1-sidraya@linux.ibm.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/af_smc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
+index 47963eda478f6..bc7b4a33b7261 100644
+--- a/net/smc/af_smc.c
++++ b/net/smc/af_smc.c
+@@ -1935,11 +1935,12 @@ static void smc_listen_out(struct smc_sock *new_smc)
+ atomic_dec(&lsmc->queued_smc_hs);
+
+ release_sock(newsmcsk); /* lock in smc_listen_work() */
++ lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
+ if (lsmc->sk.sk_state == SMC_LISTEN) {
+- lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
+ smc_accept_enqueue(&lsmc->sk, newsmcsk);
+ release_sock(&lsmc->sk);
+ } else { /* no longer listening */
++ release_sock(&lsmc->sk);
+ smc_close_non_accepted(newsmcsk);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 7fd83da1105a04ce07766dff932c16e2dfb38723 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 11:51:56 +0200
+Subject: net: stmmac: resume PHY before hardware setup when opening the
+ interface
+
+From: Stefan Agner <stefan@agner.ch>
+
+[ Upstream commit 06232cb44bc8e81adc2f1d40a01bed830b607ea2 ]
+
+Since the referenced commit, changing the MTU on a running interface no
+longer disconnects and reconnects the PHY; __stmmac_release() merely
+stops phylink, which also suspends the PHY (BMCR power-down) when WoL
+is not enabled. __stmmac_open() then performs the DMA software reset in
+stmmac_hw_setup() before phylink_start() resumes the PHY again.
+
+IEEE 802.3 22.2.4.1.5 allows a PHY to stop its receive clock while
+powered down, and stmmac requires a running receive clock for the DMA
+software reset to complete (the phylink config sets mac_requires_rxc).
+On such setups, e.g. the RK3566-based Home Assistant Green with an
+RTL8211F-VD PHY in RGMII mode, any runtime MTU change now times out and
+leaves the interface dead:
+
+ rk_gmac-dwmac fe010000.ethernet end0: Failed to reset the dma
+ rk_gmac-dwmac fe010000.ethernet end0: stmmac_hw_setup: DMA engine initialization failed
+ rk_gmac-dwmac fe010000.ethernet end0: __stmmac_open: Hw setup failed
+ rk_gmac-dwmac fe010000.ethernet end0: failed reopening the interface after MTU change
+
+In the field this is triggered by NetworkManager applying an MTU while
+activating the connection, breaking networking entirely. The same
+regression has also been reported on i.MX8MP and reproduced on SoCFPGA
+based systems.
+
+Resume the PHY in __stmmac_open() before the hardware setup, making it
+the counterpart of the phylink_stop() in __stmmac_release(), like
+stmmac_resume() already does for the same reason. phylink_start() also
+resumes the PHY, but only after stmmac_hw_setup(), and it cannot be
+moved before the hardware setup since it may bring the link up
+immediately from a workqueue, racing with the initialization (see the
+comment in stmmac_resume()). For the regular ndo_open path the PHY has
+just been attached and is not suspended, in which case
+phylink_prepare_resume() does nothing.
+
+Fixes: db299a0c09e9 ("net: stmmac: move PHY handling out of __stmmac_open()/release()")
+Link: https://github.com/home-assistant/operating-system/issues/4858
+Tested-by: Alexander Stein <alexander.stein@ew.tq-group.com>
+Signed-off-by: Stefan Agner <stefan@agner.ch>
+Tested-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Link: https://patch.msgid.link/20260803095156.132827-1-stefan@agner.ch
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index bca81ed28e073..bf2fa56b861be 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -3893,6 +3893,15 @@ static int __stmmac_open(struct net_device *dev,
+ dma_conf->tx_queue[i].tbs = priv->dma_conf.tx_queue[i].tbs;
+ memcpy(&priv->dma_conf, dma_conf, sizeof(*dma_conf));
+
++ /* The PHY is suspended when the interface is reopened without
++ * disconnecting the PHY, e.g. on MTU change. IEEE 802.3 allows PHYs
++ * to stop their receive clock while powered down, but the DMA
++ * software reset in stmmac_hw_setup() requires a running receive
++ * clock, and phylink_start() below resumes the PHY only after the
++ * hardware setup. Resume a suspended PHY here first.
++ */
++ phylink_prepare_resume(priv->phylink);
++
+ stmmac_reset_queues_param(priv);
+
+ if (!(priv->plat->flags & STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP) &&
+--
+2.53.0
+
--- /dev/null
+From 080b6c6c90917a15935d807d1a70a1f58a762a6e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 14:38:50 +0000
+Subject: net: thunderbolt: Tear down DMA paths before stopping the rings
+
+From: Fan XinRan <shinjiangjiang@gmail.com>
+
+[ Upstream commit 68bf02b6b4ad3f748c6db71fd77b6c0402d252f4 ]
+
+tbnet_tear_down() stops both rings and frees their frame buffers before
+calling tb_xdomain_disable_paths(). tb_ring_stop() zeroes the ring's
+descriptor base and tbnet_free_buffers() unmaps and frees the pages the
+frames sit in, so by the time __tb_path_deactivate_hop() polls the hop's
+'pending' bit, anything still in flight has nowhere to drain to.
+
+The teardown sequence has been in this order since the driver was added.
+The setup path has not: commit ff7cd07f3064 ("net: thunderbolt: Enable
+DMA paths only after rings are enabled") moved the path enable to the end
+of tbnet_connected_work() and documented why:
+
+ /* Both logins successful so enable the rings, high-speed DMA
+ * paths and start the network device queue.
+ *
+ * Note we enable the DMA paths last to make sure we have primed
+ * the Rx ring before any incoming packets are allowed to
+ * arrive.
+ */
+
+Teardown was never updated to match, so the rings and the paths now come
+down in the same order they go up instead of in reverse.
+
+On an ASMedia ASM4242 host router the 'pending' bit then never clears:
+every teardown burns the full 500 ms timeout and
+__tb_path_deactivate_hop() returns -ETIMEDOUT. Raising the timeout to
+5 s does not help, so the hop is not slow to drain, it never drains
+at all.
+
+The failure is invisible above the thunderbolt core.
+__tb_path_deactivate_hops() is void and only calls tb_port_warn();
+tb_path_deactivate(), tb_tunnel_deactivate() and
+__tb_disconnect_xdomain_paths() are void as well, and
+tb_disconnect_xdomain_paths() ends in an unconditional "return 0". So
+tb_xdomain_disable_paths() reports success and the netdev_warn() below
+it never fires. Repeated teardowns eventually take the XDomain control
+channel down, after which the peer node is gone and only a power cycle
+brings the controller back.
+
+Deactivating the paths first fixes it. Measured with kretprobes on a
+stock v6.17 tree with no other patches applied, on a link that was up
+and had just carried traffic:
+
+ before: __tb_path_deactivate_hop() returns 0 for the first hop, then
+ -ETIMEDOUT for the second 500335 us later
+ after: 0 for both, 525 us apart
+
+Alternating the two orderings ABBA over three load levels, four
+teardowns per arm: every teardown failed before the change (21 of 21
+that ran), none failed after (0 of 24). The before arms ran short
+because the link died partway through. The same split shows up when
+the interface is enslaved to a bond instead of just brought down, which
+is how I ran into this in the first place. Throughput and latency after
+the change are unchanged.
+
+Hosts whose routers drain the hop despite the stale descriptor base see
+no functional difference, since the paths end up deactivated either way.
+
+Fixes: e69b6c02b4c3 ("net: Add support for networking over Thunderbolt cable")
+Signed-off-by: Fan XinRan <shinjiangjiang@gmail.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Link: https://patch.msgid.link/20260803-b4-tbnet-teardown-v2-1-27de6a13ca2d@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/thunderbolt/main.c | 20 +++++++++++++++-----
+ 1 file changed, 15 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c
+index 960839a651e51..ceaba08cd378a 100644
+--- a/drivers/net/thunderbolt/main.c
++++ b/drivers/net/thunderbolt/main.c
+@@ -389,11 +389,16 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)
+ break;
+ }
+
+- tb_ring_stop(net->rx_ring.ring);
+- tb_ring_stop(net->tx_ring.ring);
+- tbnet_free_buffers(&net->rx_ring);
+- tbnet_free_buffers(&net->tx_ring);
+-
++ /* Tear the paths down before stopping the rings. This mirrors
++ * tbnet_connected_work(), which enables the paths last so the
++ * Rx ring is primed before packets can arrive. Stopping a
++ * ring zeroes its descriptor base and tbnet_free_buffers()
++ * unmaps and frees the frame buffers, leaving anything still
++ * in flight with nowhere to drain to;
++ * __tb_path_deactivate_hop() then waits for the hop's
++ * 'pending' bit, which on some host routers never clears in
++ * that state.
++ */
+ ret = tb_xdomain_disable_paths(net->xd,
+ net->local_transmit_path,
+ net->tx_ring.ring->hop,
+@@ -402,6 +407,11 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)
+ if (ret)
+ netdev_warn(net->dev, "failed to disable DMA paths\n");
+
++ tb_ring_stop(net->rx_ring.ring);
++ tb_ring_stop(net->tx_ring.ring);
++ tbnet_free_buffers(&net->rx_ring);
++ tbnet_free_buffers(&net->tx_ring);
++
+ tb_xdomain_release_in_hopid(net->xd, net->remote_transmit_path);
+ net->remote_transmit_path = 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From 49a7a1d02e725ae2483dbb5b44c9741fa6d50a61 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Oct 2025 12:32:35 +0200
+Subject: netfilter: flowtable: consolidate xmit path
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit b5964aac51e0c286a50e68225e0dfcf11fb554cb ]
+
+Use dev_queue_xmit() for the XMIT_NEIGH case. Store the interface index
+of the real device behind the vlan/pppoe device, this introduces an
+extra lookup for the real device in the xmit path because rt->dst.dev
+provides the vlan/pppoe device.
+
+XMIT_NEIGH now looks more similar to XMIT_DIRECT but the check for stale
+dst and the neighbour lookup still remain in place which is convenient
+to deal with network topology changes.
+
+Note that nft_flow_route() needs to relax the check for _XMIT_NEIGH so
+the existing basic xfrm offload (which only works in one direction) does
+not break.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 8aecf0bbcc72 ("netfilter: nf_flow_table: drop existing skb dst before skb_dst_set_noref()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_flow_table.h | 1 +
+ net/netfilter/nf_flow_table_core.c | 1 +
+ net/netfilter/nf_flow_table_ip.c | 87 ++++++++++++++++-----------
+ net/netfilter/nf_flow_table_path.c | 7 +--
+ 4 files changed, 57 insertions(+), 39 deletions(-)
+
+diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
+index e9f72d2558e90..7c330caae52bf 100644
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -141,6 +141,7 @@ struct flow_offload_tuple {
+ union {
+ struct {
+ struct dst_entry *dst_cache;
++ u32 ifidx;
+ u32 dst_cookie;
+ };
+ struct {
+diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
+index d3104816b7f71..595a0f19d15e7 100644
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -132,6 +132,7 @@ static int flow_offload_fill_route(struct flow_offload *flow,
+ break;
+ case FLOW_OFFLOAD_XMIT_XFRM:
+ case FLOW_OFFLOAD_XMIT_NEIGH:
++ flow_tuple->ifidx = route->tuple[dir].out.ifindex;
+ flow_tuple->dst_cache = dst;
+ flow_tuple->dst_cookie = flow_offload_dst_cookie(flow_tuple);
+ break;
+diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
+index 8cd4cf7ae2112..eb4f6a11e779f 100644
+--- a/net/netfilter/nf_flow_table_ip.c
++++ b/net/netfilter/nf_flow_table_ip.c
+@@ -333,19 +333,18 @@ static void nf_flow_encap_pop(struct sk_buff *skb,
+ }
+ }
+
++struct nf_flow_xmit {
++ const void *dest;
++ const void *source;
++ struct net_device *outdev;
++};
++
+ static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb,
+- const struct flow_offload_tuple_rhash *tuplehash,
+- unsigned short type)
++ struct nf_flow_xmit *xmit)
+ {
+- struct net_device *outdev;
+-
+- outdev = dev_get_by_index_rcu(net, tuplehash->tuple.out.ifidx);
+- if (!outdev)
+- return NF_DROP;
+-
+- skb->dev = outdev;
+- dev_hard_header(skb, skb->dev, type, tuplehash->tuple.out.h_dest,
+- tuplehash->tuple.out.h_source, skb->len);
++ skb->dev = xmit->outdev;
++ dev_hard_header(skb, skb->dev, ntohs(skb->protocol),
++ xmit->dest, xmit->source, skb->len);
+ dev_queue_xmit(skb);
+
+ return NF_STOLEN;
+@@ -424,10 +423,10 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
+ struct nf_flowtable_ctx ctx = {
+ .in = state->in,
+ };
++ struct nf_flow_xmit xmit = {};
+ struct flow_offload *flow;
+- struct net_device *outdev;
++ struct neighbour *neigh;
+ struct rtable *rt;
+- __be32 nexthop;
+ int ret;
+
+ tuplehash = nf_flow_offload_lookup(&ctx, flow_table, skb);
+@@ -454,25 +453,34 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
+ switch (tuplehash->tuple.xmit_type) {
+ case FLOW_OFFLOAD_XMIT_NEIGH:
+ rt = dst_rtable(tuplehash->tuple.dst_cache);
+- outdev = rt->dst.dev;
+- skb->dev = outdev;
+- nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
++ xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.ifidx);
++ if (!xmit.outdev) {
++ flow_offload_teardown(flow);
++ return NF_DROP;
++ }
++ neigh = ip_neigh_gw4(rt->dst.dev, rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr));
++ if (IS_ERR(neigh)) {
++ flow_offload_teardown(flow);
++ return NF_DROP;
++ }
++ xmit.dest = neigh->ha;
+ skb_dst_set_noref(skb, &rt->dst);
+- neigh_xmit(NEIGH_ARP_TABLE, outdev, &nexthop, skb);
+- ret = NF_STOLEN;
+ break;
+ case FLOW_OFFLOAD_XMIT_DIRECT:
+- ret = nf_flow_queue_xmit(state->net, skb, tuplehash, ETH_P_IP);
+- if (ret == NF_DROP)
++ xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.out.ifidx);
++ if (!xmit.outdev) {
+ flow_offload_teardown(flow);
++ return NF_DROP;
++ }
++ xmit.dest = tuplehash->tuple.out.h_dest;
++ xmit.source = tuplehash->tuple.out.h_source;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+- ret = NF_DROP;
+- break;
++ return NF_DROP;
+ }
+
+- return ret;
++ return nf_flow_queue_xmit(state->net, skb, &xmit);
+ }
+ EXPORT_SYMBOL_GPL(nf_flow_offload_ip_hook);
+
+@@ -719,9 +727,9 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
+ struct nf_flowtable_ctx ctx = {
+ .in = state->in,
+ };
+- const struct in6_addr *nexthop;
++ struct nf_flow_xmit xmit = {};
+ struct flow_offload *flow;
+- struct net_device *outdev;
++ struct neighbour *neigh;
+ struct rt6_info *rt;
+ int ret;
+
+@@ -749,24 +757,33 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
+ switch (tuplehash->tuple.xmit_type) {
+ case FLOW_OFFLOAD_XMIT_NEIGH:
+ rt = dst_rt6_info(tuplehash->tuple.dst_cache);
+- outdev = rt->dst.dev;
+- skb->dev = outdev;
+- nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
++ xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.ifidx);
++ if (!xmit.outdev) {
++ flow_offload_teardown(flow);
++ return NF_DROP;
++ }
++ neigh = ip_neigh_gw6(rt->dst.dev, rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6));
++ if (IS_ERR(neigh)) {
++ flow_offload_teardown(flow);
++ return NF_DROP;
++ }
++ xmit.dest = neigh->ha;
+ skb_dst_set_noref(skb, &rt->dst);
+- neigh_xmit(NEIGH_ND_TABLE, outdev, nexthop, skb);
+- ret = NF_STOLEN;
+ break;
+ case FLOW_OFFLOAD_XMIT_DIRECT:
+- ret = nf_flow_queue_xmit(state->net, skb, tuplehash, ETH_P_IPV6);
+- if (ret == NF_DROP)
++ xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.out.ifidx);
++ if (!xmit.outdev) {
+ flow_offload_teardown(flow);
++ return NF_DROP;
++ }
++ xmit.dest = tuplehash->tuple.out.h_dest;
++ xmit.source = tuplehash->tuple.out.h_source;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+- ret = NF_DROP;
+- break;
++ return NF_DROP;
+ }
+
+- return ret;
++ return nf_flow_queue_xmit(state->net, skb, &xmit);
+ }
+ EXPORT_SYMBOL_GPL(nf_flow_offload_ipv6_hook);
+diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
+index 76d4ff1454398..da56fda2c2b39 100644
+--- a/net/netfilter/nf_flow_table_path.c
++++ b/net/netfilter/nf_flow_table_path.c
+@@ -213,11 +213,11 @@ static void nft_dev_forward_path(struct nf_flow_route *route,
+ }
+ route->tuple[!dir].in.num_encaps = info.num_encaps;
+ route->tuple[!dir].in.ingress_vlans = info.ingress_vlans;
++ route->tuple[dir].out.ifindex = info.outdev->ifindex;
+
+ if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
+ memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);
+ memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN);
+- route->tuple[dir].out.ifindex = info.outdev->ifindex;
+ route->tuple[dir].out.hw_ifindex = info.hw_outdev->ifindex;
+ route->tuple[dir].xmit_type = info.xmit_type;
+ }
+@@ -265,11 +265,10 @@ int nft_flow_route(const struct nft_pktinfo *pkt, const struct nf_conn *ct,
+ nft_default_forward_path(route, this_dst, dir);
+ nft_default_forward_path(route, other_dst, !dir);
+
+- if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH &&
+- route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
++ if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH)
+ nft_dev_forward_path(route, ct, dir, ft);
++ if (route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH)
+ nft_dev_forward_path(route, ct, !dir, ft);
+- }
+
+ return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From 1703eae1a67c3333688298d7f719689ee4bb5615 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 20:38:50 +0200
+Subject: netfilter: ipset: switch ext_size to atomic64_t
+
+From: Jozsef Kadlecsik <kadlec@netfilter.org>
+
+[ Upstream commit 712a6f545c359b427daa9a5a782e30d2f8331e25 ]
+
+The hash types do not acquire set->lock, they use 'region locking' where
+only part of the hash table is locked. Parallel inserts and deletes are
+possible and CPUs can race on ->ext_size update. Switch to atomic64_t.
+
+This leaves another bug unresolved: there still can be a race on
+comment extension re-init. This will be handled in a later commit
+when converting to rhashtable backend.
+
+Fixes: f66ee0410b1c ("netfilter: ipset: Fix "INFO: rcu detected stall in hash_xxx" reports")
+Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/netfilter/ipset/ip_set.h | 2 +-
+ net/netfilter/ipset/ip_set_bitmap_gen.h | 4 ++--
+ net/netfilter/ipset/ip_set_core.c | 6 +++---
+ net/netfilter/ipset/ip_set_hash_gen.h | 2 +-
+ net/netfilter/ipset/ip_set_list_set.c | 4 ++--
+ 5 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
+index b98331572ad29..cadae9b2578f1 100644
+--- a/include/linux/netfilter/ipset/ip_set.h
++++ b/include/linux/netfilter/ipset/ip_set.h
+@@ -273,7 +273,7 @@ struct ip_set {
+ /* Number of elements (vs timeout) */
+ u32 elements;
+ /* Size of the dynamic extensions (vs timeout) */
+- size_t ext_size;
++ atomic64_t ext_size;
+ /* Element data size */
+ size_t dsize;
+ /* Offsets to extensions in elements */
+diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h
+index 798c7993635e6..d99e2e2e58559 100644
+--- a/net/netfilter/ipset/ip_set_bitmap_gen.h
++++ b/net/netfilter/ipset/ip_set_bitmap_gen.h
+@@ -77,7 +77,7 @@ mtype_flush(struct ip_set *set)
+ mtype_ext_cleanup(set);
+ bitmap_zero(map->members, map->elements);
+ set->elements = 0;
+- set->ext_size = 0;
++ atomic64_set(&set->ext_size, 0);
+ }
+
+ /* Calculate the actual memory size of the set data */
+@@ -93,7 +93,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
+ {
+ const struct mtype *map = set->data;
+ struct nlattr *nested;
+- size_t memsize = mtype_memsize(map, set->dsize) + set->ext_size;
++ size_t memsize = mtype_memsize(map, set->dsize) + atomic64_read(&set->ext_size);
+
+ nested = nla_nest_start(skb, IPSET_ATTR_DATA);
+ if (!nested)
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index f51a1af31513c..29bf5ee74fe36 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -350,7 +350,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
+ size_t len = ext->comment ? strlen(ext->comment) : 0;
+
+ if (unlikely(c)) {
+- set->ext_size -= sizeof(*c) + strlen(c->str) + 1;
++ atomic64_sub(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
+ rcu_assign_pointer(comment->c, NULL);
+ kfree_rcu(c, rcu);
+ }
+@@ -362,7 +362,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
+ if (unlikely(!c))
+ return;
+ strscpy(c->str, ext->comment, len + 1);
+- set->ext_size += sizeof(*c) + strlen(c->str) + 1;
++ atomic64_add(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
+ rcu_assign_pointer(comment->c, c);
+ }
+ EXPORT_SYMBOL_GPL(ip_set_init_comment);
+@@ -392,7 +392,7 @@ ip_set_comment_free(struct ip_set *set, void *ptr)
+ c = rcu_dereference_protected(comment->c, 1);
+ if (unlikely(!c))
+ return;
+- set->ext_size -= sizeof(*c) + strlen(c->str) + 1;
++ atomic64_sub(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
+ rcu_assign_pointer(comment->c, NULL);
+ kfree_rcu(c, rcu);
+ }
+diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
+index 4c1082e38e3d1..81d7f601ed06a 100644
+--- a/net/netfilter/ipset/ip_set_hash_gen.h
++++ b/net/netfilter/ipset/ip_set_hash_gen.h
+@@ -1289,7 +1289,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
+ rcu_read_lock_bh();
+ t = rcu_dereference_bh(h->table);
+ mtype_ext_size(set, &elements, &ext_size);
+- memsize = mtype_ahash_memsize(h, t) + ext_size + set->ext_size;
++ memsize = mtype_ahash_memsize(h, t) + ext_size + atomic64_read(&set->ext_size);
+ htable_bits = t->htable_bits;
+ rcu_read_unlock_bh();
+
+diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
+index 34bb84d7b174c..7bb807b3c6282 100644
+--- a/net/netfilter/ipset/ip_set_list_set.c
++++ b/net/netfilter/ipset/ip_set_list_set.c
+@@ -421,7 +421,7 @@ list_set_flush(struct ip_set *set)
+ list_for_each_entry_safe(e, n, &map->members, list)
+ list_set_del(set, e);
+ set->elements = 0;
+- set->ext_size = 0;
++ atomic64_set(&set->ext_size, 0);
+ }
+
+ static void
+@@ -455,7 +455,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
+ {
+ const struct list_set *map = set->data;
+ struct nlattr *nested;
+- size_t memsize = list_set_memsize(map, set->dsize) + set->ext_size;
++ size_t memsize = list_set_memsize(map, set->dsize) + atomic64_read(&set->ext_size);
+
+ nested = nla_nest_start(skb, IPSET_ATTR_DATA);
+ if (!nested)
+--
+2.53.0
+
--- /dev/null
+From dd838483a282d1c937c2b629851cef55c798ad6a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 09:33:28 +0000
+Subject: netfilter: nf_flow_table: drop existing skb dst before
+ skb_dst_set_noref()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 8aecf0bbcc72605592134c917c222207d8f63ab0 ]
+
+Incoming skbs passing through netfilter flowtable offload hooks (or XFRM
+offload path) might already carry a ref-counted dst_entry assigned during
+earlier RX or routing steps.
+
+Calling skb_dst_set_noref() when skb already holds a ref-counted dst
+overwrites skb->_skb_refdst, leaking the previous dst_entry reference
+count and triggering a DEBUG_NET_WARN_ON_ONCE assertion in
+skb_dst_check_unset():
+
+ WARNING: at skb_dst_check_unset include/linux/skbuff.h:1170
+ WARNING: at skb_dst_set_noref include/linux/skbuff.h:1234
+ WARNING: at nf_flow_offload_ip_hook+0xf6c/0x2b60 net/netfilter/nf_flow_table_ip.c:864
+
+Drop any existing dst_entry reference with skb_dst_drop(skb) before
+setting the non-referenced flowtable destination.
+
+Fixes: 2a79fd3908ac ("netfilter: nf_flow_table: attach dst to skbs")
+Reported-by: syzbot+76d4e3a055aec3b007ec@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/6a71b141.9511d2ce.1fc5b9.033b.GAE@google.com/T/#u
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Link: https://patch.msgid.link/20260804093328.1831847-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_flow_table_ip.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
+index eb4f6a11e779f..4dcc30e7f9e5e 100644
+--- a/net/netfilter/nf_flow_table_ip.c
++++ b/net/netfilter/nf_flow_table_ip.c
+@@ -272,6 +272,7 @@ static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb,
+ struct dst_entry *dst)
+ {
+ skb_orphan(skb);
++ skb_dst_drop(skb);
+ skb_dst_set_noref(skb, dst);
+ dst_output(state->net, state->sk, skb);
+ return NF_STOLEN;
+@@ -464,6 +465,7 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
+ return NF_DROP;
+ }
+ xmit.dest = neigh->ha;
++ skb_dst_drop(skb);
+ skb_dst_set_noref(skb, &rt->dst);
+ break;
+ case FLOW_OFFLOAD_XMIT_DIRECT:
+@@ -768,6 +770,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
+ return NF_DROP;
+ }
+ xmit.dest = neigh->ha;
++ skb_dst_drop(skb);
+ skb_dst_set_noref(skb, &rt->dst);
+ break;
+ case FLOW_OFFLOAD_XMIT_DIRECT:
+--
+2.53.0
+
--- /dev/null
+From f4e6e5895b5ddc83aac2cc77db7ca6a121aeaec9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 30 Jun 2026 14:31:00 -0400
+Subject: NFS: Pin the 'struct nfs_server' during a FREE_STATEID call
+
+From: Anna Schumaker <anna.schumaker@hammerspace.com>
+
+[ Upstream commit cf616096a0f3a2b60f7d68b6b39674a6867ded9c ]
+
+Dan Aloni reports that he was able to hit a use-after-free bug if a
+FREE_STATEID operation gets delayed for whatever reason. Fix this by
+bumping the refcount of the 'struct nfs_server' object for the duration
+of the FREE_STATEID so it doesn't get cleaned up from underneath us
+while operations are still in flight.
+
+Reported-by: Dan Aloni <dan.aloni@vastdata.com>
+Fixes: 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call")
+Tested-by: Dan Aloni <dan.aloni@vastdata.com>
+Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/nfs4proc.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index 403f7f8dfea2b..66b8da741a06f 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -10634,6 +10634,7 @@ static void nfs41_free_stateid_release(void *calldata)
+ struct nfs_free_stateid_data *data = calldata;
+ struct nfs_client *clp = data->server->nfs_client;
+
++ nfs_sb_deactive(data->server->super);
+ nfs_put_client(clp);
+ kfree(calldata);
+ }
+@@ -10675,6 +10676,10 @@ static int nfs41_free_stateid(struct nfs_server *server,
+
+ if (!refcount_inc_not_zero(&clp->cl_count))
+ return -EIO;
++ if (!nfs_sb_active(server->super)) {
++ nfs_put_client(clp);
++ return -EIO;
++ }
+
+ nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
+ &task_setup.rpc_client, &msg);
+--
+2.53.0
+
--- /dev/null
+From 622571253e3085f96653236b4deda54a6021afa3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:41:30 +0200
+Subject: ovpn: add missing rtnl_link_ops->get_size callback
+
+From: Ralf Lici <ralf@mandelbit.com>
+
+[ Upstream commit 6e9f539e4f01153651dd77609b5ccadd44b74df8 ]
+
+ovpn_fill_info emits IFLA_OVPN_MODE inside IFLA_INFO_DATA, but
+ovpn_link_ops does not provide a get_size callback. Consequently,
+rtnetlink's size estimate for ovpn link messages does not include the
+nested mode attribute.
+
+Available skb tailroom may hide this mismatch. When the remaining space
+is insufficient, however, ovpn_fill_info returns -EMSGSIZE and message
+construction fails.
+
+Add the callback and account for IFLA_OVPN_MODE.
+
+Fixes: c2d950c4672a ("ovpn: add basic interface creation/destruction/management routines")
+Signed-off-by: Ralf Lici <ralf@mandelbit.com>
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/main.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
+index 3f76b1b0e5f60..47859e1e3ef12 100644
+--- a/drivers/net/ovpn/main.c
++++ b/drivers/net/ovpn/main.c
+@@ -210,6 +210,12 @@ static int ovpn_newlink(struct net_device *dev,
+ return register_netdevice(dev);
+ }
+
++static size_t ovpn_get_size(const struct net_device *dev)
++{
++ /* IFLA_OVPN_MODE */
++ return nla_total_size(sizeof(u8));
++}
++
+ static int ovpn_fill_info(struct sk_buff *skb, const struct net_device *dev)
+ {
+ struct ovpn_priv *ovpn = netdev_priv(dev);
+@@ -228,6 +234,7 @@ static struct rtnl_link_ops ovpn_link_ops = {
+ .policy = ovpn_policy,
+ .maxtype = IFLA_OVPN_MAX,
+ .newlink = ovpn_newlink,
++ .get_size = ovpn_get_size,
+ .fill_info = ovpn_fill_info,
+ };
+
+--
+2.53.0
+
--- /dev/null
+From 40440ca620174039934fd3f69fe7a114c3dd1eb5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 13:48:53 +0200
+Subject: ovpn: disable IPv4 redirects on MP interfaces
+
+From: Antonio Quartulli <antonio@openvpn.net>
+
+[ Upstream commit 0301aa324941698bec3dd455df1c5abc7afb10db ]
+
+ovpn_mp_alloc() tried to disable SEND_REDIRECTS on a multipeer
+interface, but it runs from ovpn_net_init() (->ndo_init), which
+register_netdevice() invokes before the NETDEV_REGISTER notifier
+chain. The IPv4 in_device is only created when that notifier reaches
+inetdev_event() -> inetdev_init(), so __in_dev_get_rtnl() always
+returned NULL at ndo_init time and the whole redirect-disabling block
+(both the per-device and the per-netns IPV4_DEVCONF_ALL write) was
+dead. MP interfaces therefore kept emitting ICMP redirects.
+
+Disabling redirects only once is not enough either: the IPv4
+in_device is destroyed and recreated when the interface is moved to a
+different network namespace (NETDEV_UNREGISTER/NETDEV_REGISTER), and
+the newly created in_device inherits the destination namespace
+defaults, silently re-enabling SEND_REDIRECTS.
+
+Disable redirects from ovpn_net_open() (->ndo_open) instead: it runs
+every time the interface is brought up, including after the in_device
+has been recreated, so the setting is always re-applied. This mirrors
+what wireguard does in wg_open(). RTNL is held on the ndo_open() path,
+so __in_dev_get_rtnl() is safe.
+
+Fixes: 05003b408c20 ("ovpn: implement multi-peer support")
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/main.c | 50 ++++++++++++++++++++++++++++-------------
+ 1 file changed, 35 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
+index 47859e1e3ef12..a3c15fc301d0d 100644
+--- a/drivers/net/ovpn/main.c
++++ b/drivers/net/ovpn/main.c
+@@ -35,25 +35,11 @@ static void ovpn_priv_free(struct net_device *net)
+
+ static int ovpn_mp_alloc(struct ovpn_priv *ovpn)
+ {
+- struct in_device *dev_v4;
+ int i;
+
+ if (ovpn->mode != OVPN_MODE_MP)
+ return 0;
+
+- dev_v4 = __in_dev_get_rtnl(ovpn->dev);
+- if (dev_v4) {
+- /* disable redirects as Linux gets confused by ovpn
+- * handling same-LAN routing.
+- * This happens because a multipeer interface is used as
+- * relay point between hosts in the same subnet, while
+- * in a classic LAN this would not be needed because the
+- * two hosts would be able to talk directly.
+- */
+- IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false);
+- IPV4_DEVCONF_ALL(dev_net(ovpn->dev), SEND_REDIRECTS) = false;
+- }
+-
+ /* the peer container is fairly large, therefore we allocate it only in
+ * MP mode
+ */
+@@ -97,9 +83,38 @@ static void ovpn_net_uninit(struct net_device *dev)
+ gro_cells_destroy(&ovpn->gro_cells);
+ }
+
++static int ovpn_net_open(struct net_device *dev)
++{
++ struct ovpn_priv *ovpn = netdev_priv(dev);
++ struct in_device *dev_v4;
++
++ /* the IPv4 in_device (and thus its config) is recreated whenever the
++ * interface is moved to a new netns, so redirects must be disabled on
++ * every bring-up rather than once at creation time, otherwise the
++ * setting is silently lost after such a move
++ */
++ if (ovpn->mode == OVPN_MODE_MP) {
++ dev_v4 = __in_dev_get_rtnl(dev);
++ if (dev_v4) {
++ /* disable redirects as Linux gets confused by ovpn
++ * handling same-LAN routing.
++ * This happens because a multipeer interface is used as
++ * relay point between hosts in the same subnet, while
++ * in a classic LAN this would not be needed because the
++ * two hosts would be able to talk directly.
++ */
++ IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false);
++ IPV4_DEVCONF_ALL(dev_net(dev), SEND_REDIRECTS) = false;
++ }
++ }
++
++ return 0;
++}
++
+ static const struct net_device_ops ovpn_netdev_ops = {
+ .ndo_init = ovpn_net_init,
+ .ndo_uninit = ovpn_net_uninit,
++ .ndo_open = ovpn_net_open,
+ .ndo_start_xmit = ovpn_net_xmit,
+ };
+
+@@ -183,6 +198,7 @@ static int ovpn_newlink(struct net_device *dev,
+ struct ovpn_priv *ovpn = netdev_priv(dev);
+ struct nlattr **data = params->data;
+ enum ovpn_mode mode = OVPN_MODE_P2P;
++ int ret;
+
+ if (data && data[IFLA_OVPN_MODE]) {
+ mode = nla_get_u8(data[IFLA_OVPN_MODE]);
+@@ -207,7 +223,11 @@ static int ovpn_newlink(struct net_device *dev,
+ else
+ netif_carrier_off(dev);
+
+- return register_netdevice(dev);
++ ret = register_netdevice(dev);
++ if (ret < 0)
++ return ret;
++
++ return 0;
+ }
+
+ static size_t ovpn_get_size(const struct net_device *dev)
+--
+2.53.0
+
--- /dev/null
+From 55a8eeb38f781ff5af3f719d22ba85bbde7c319a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 13:48:50 +0200
+Subject: ovpn: ensure socket is owned by ovpn before deref sk_user_data
+
+From: Antonio Quartulli <antonio@openvpn.net>
+
+[ Upstream commit 59aed1eb60d70678a53acccb0cb337a26ce6680e ]
+
+Some subsystems, like BPF SOCKMAP, set sk_user_data without
+actually setting the encap_type.
+
+For this reason, we must make sure that the type is the
+one ovpn expects before dereferencing sk_user_data.
+
+Failing to do so may lead to out-of-bounds reads.
+
+Fixes: f6226ae7a0cd ("ovpn: introduce the ovpn_socket object")
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/socket.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/net/ovpn/socket.c b/drivers/net/ovpn/socket.c
+index 448cee3b3f9fa..e40e320a6abf5 100644
+--- a/drivers/net/ovpn/socket.c
++++ b/drivers/net/ovpn/socket.c
+@@ -162,6 +162,15 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
+ rcu_read_lock();
+ ovpn_sock = rcu_dereference_sk_user_data(sk);
+ if (ovpn_sock) {
++ /* something else filled the sk_user_data without
++ * setting the encap_type. Reject the socket.
++ */
++ if (!type) {
++ ovpn_sock = ERR_PTR(-EBUSY);
++ rcu_read_unlock();
++ goto sock_release;
++ }
++
+ /* socket owned by another ovpn instance, we can't use it */
+ if (ovpn_sock->ovpn != peer->ovpn) {
+ ovpn_sock = ERR_PTR(-EBUSY);
+--
+2.53.0
+
--- /dev/null
+From cb8b183eea118ea7e7e5625f3f7d92c351d70752 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 13:48:54 +0200
+Subject: ovpn: ensure TCP vars are initialized first
+
+From: Antonio Quartulli <antonio@openvpn.net>
+
+[ Upstream commit 4680c0ebd958fc18e53c8b91d80436b236a8fc09 ]
+
+Netlink calls may access TCP global vars (i.e. when attaching
+a TCP socket), therefore we need to make sure the
+latters are initialized beforehand.
+
+For this reason move the global TCP initialization at the top
+of the module init function.
+
+Fixes: 11851cbd60ea ("ovpn: implement TCP transport")
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/main.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
+index a3c15fc301d0d..0262926449f2e 100644
+--- a/drivers/net/ovpn/main.c
++++ b/drivers/net/ovpn/main.c
+@@ -260,8 +260,11 @@ static struct rtnl_link_ops ovpn_link_ops = {
+
+ static int __init ovpn_init(void)
+ {
+- int err = rtnl_link_register(&ovpn_link_ops);
++ int err;
+
++ ovpn_tcp_init();
++
++ err = rtnl_link_register(&ovpn_link_ops);
+ if (err) {
+ pr_err("ovpn: can't register rtnl link ops: %d\n", err);
+ return err;
+@@ -273,8 +276,6 @@ static int __init ovpn_init(void)
+ goto unreg_rtnl;
+ }
+
+- ovpn_tcp_init();
+-
+ return 0;
+
+ unreg_rtnl:
+--
+2.53.0
+
--- /dev/null
+From 445050eef4ddad043b32be7ca30bcbd1688c505c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jul 2026 09:49:26 +0800
+Subject: ovpn: fix incorrect use of rcu_access_pointer()
+
+From: Qingfang Deng <qingfang.deng@linux.dev>
+
+[ Upstream commit 26ba17d845193dac4921ae1ab280d28d1938052e ]
+
+rcu_access_pointer() should only be used to test the value of a pointer,
+not to dereference it. As it's in a spin_lock_bh() critical section, use
+rcu_dereference_bh() instead, avoiding an extra rcu_read_lock().
+
+Fixes: f6226ae7a0cd ("ovpn: introduce the ovpn_socket object")
+Signed-off-by: Qingfang Deng <qingfang.deng@linux.dev>
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/peer.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
+index 9b647a327c468..412ef09abd5e7 100644
+--- a/drivers/net/ovpn/peer.c
++++ b/drivers/net/ovpn/peer.c
+@@ -1244,7 +1244,7 @@ static void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, struct sock *sk,
+ }
+
+ if (sk) {
+- ovpn_sock = rcu_access_pointer(peer->sock);
++ ovpn_sock = rcu_dereference_bh(peer->sock);
+ if (!ovpn_sock || ovpn_sock->sk != sk) {
+ spin_unlock_bh(&ovpn->lock);
+ return;
+--
+2.53.0
+
--- /dev/null
+From 4bacaecf06b752798d5539ab1e7381b58adf4533 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 13:48:52 +0200
+Subject: ovpn: hash floated peer by transport identity only
+
+From: Antonio Quartulli <antonio@openvpn.net>
+
+[ Upstream commit b47a52dcd598a50207a33df304acdf45348a690f ]
+
+The by_transp_addr table is keyed on the peer's remote transport
+address, but the float rehash hashed bind->remote directly, while the
+two other sites that touch the table build a clean key first:
+ovpn_peer_add_mp() and the lookup in ovpn_peer_get_by_transp_addr()
+both hash a sockaddr holding only family/address/port.
+
+For a link-local IPv6 peer, bind->remote carries sin6_scope_id (set
+from ipv6_iface_scope_id() when the endpoint is learned), and that
+field is folded into the jhash() over sizeof(struct sockaddr_in6).
+The lookup never sets sin6_scope_id, so after such a peer floats it is
+rehashed into a scope_id-dependent bucket that lookups (scope_id 0)
+never visit, making the peer unreachable through the by_transp_addr
+fallback. ovpn_peer_transp_match() only compares address and port, so
+the hash was keying on a field the match ignores.
+
+sin6_scope_id must stay in bind->remote because the TX path uses it as
+flowi6_oif, so it cannot just be cleared there. Instead build the hash
+key from family/address/port only, exactly like ovpn_peer_add_mp() and
+the lookup, so all three sites agree on the bucket.
+
+Fixes: f0281c1d3732 ("ovpn: add support for updating local or remote UDP endpoint")
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/peer.c | 25 +++++++++++++++++++++----
+ 1 file changed, 21 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
+index 3824ee1c2e40a..9b647a327c468 100644
+--- a/drivers/net/ovpn/peer.c
++++ b/drivers/net/ovpn/peer.c
+@@ -899,7 +899,10 @@ bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
+ static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
+ const struct ovpn_bind *bind)
+ {
++ struct sockaddr_storage sa = {};
+ struct hlist_nulls_head *nhead;
++ struct sockaddr_in6 *sa6;
++ struct sockaddr_in *sa4;
+ size_t salen;
+
+ lockdep_assert_held(&peer->ovpn->lock);
+@@ -915,12 +918,26 @@ static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
+ if (unlikely(hlist_unhashed(&peer->hash_entry_id)))
+ return;
+
++ /* Build the hash key from the transport identity only
++ * (family/address/port), matching ovpn_peer_add_mp() and the lookup
++ * in ovpn_peer_get_by_transp_addr(). Hashing bind->remote directly
++ * would fold in sin6_scope_id (set on the float path but never by the
++ * lookup), scattering the peer into a bucket lookups cannot reach.
++ */
+ switch (bind->remote.in4.sin_family) {
+ case AF_INET:
+- salen = sizeof(struct sockaddr_in);
++ sa4 = (struct sockaddr_in *)&sa;
++ sa4->sin_family = AF_INET;
++ sa4->sin_addr.s_addr = bind->remote.in4.sin_addr.s_addr;
++ sa4->sin_port = bind->remote.in4.sin_port;
++ salen = sizeof(*sa4);
+ break;
+ case AF_INET6:
+- salen = sizeof(struct sockaddr_in6);
++ sa6 = (struct sockaddr_in6 *)&sa;
++ sa6->sin6_family = AF_INET6;
++ sa6->sin6_addr = bind->remote.in6.sin6_addr;
++ sa6->sin6_port = bind->remote.in6.sin6_port;
++ salen = sizeof(*sa6);
+ break;
+ default:
+ return;
+@@ -929,8 +946,8 @@ static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
+ /* remove old hashing (no-op if entry is not currently linked) */
+ hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
+ /* re-add with current transport address */
+- nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
+- &bind->remote, salen);
++ nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr, &sa,
++ salen);
+ hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From f878351bc1bb8901897a14ba0aa7b2797d92d1ba Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 13:48:48 +0200
+Subject: ovpn: rehash peer in by_transp_addr table on CMD_PEER_SET
+
+From: Antonio Quartulli <antonio@openvpn.net>
+
+[ Upstream commit cc12f7240c8c4dee557749d33237542613992f14 ]
+
+When userspace updates a peer's remote endpoint via OVPN_CMD_PEER_SET,
+ovpn_nl_peer_modify() installs a new ovpn_bind through
+ovpn_peer_reset_sockaddr(), but ovpn_nl_peer_set_doit() only calls
+ovpn_peer_hash_vpn_ip() to refresh the VPN-IP hashtables. The peer is
+left in the bucket of peers->by_transp_addr corresponding to its old
+remote address.
+
+As a consequence, datagrams arriving at the UDP RX path from the newly
+configured remote hash to a different slot and the lockless lookup in
+ovpn_peer_get_by_transp_addr() (called from ovpn_udp_encap_recv()) does
+not find the peer, until either a float event or a peer re-add fixes
+the bucket.
+
+Introduce ovpn_peer_hash_transp_addr() (modeled after
+ovpn_peer_hash_vpn_ip()) and invoke it from ovpn_nl_peer_set_doit()
+whenever the request carried a new remote address. The helper bails
+out in P2P mode and on peers without a bind (TCP), and relies on
+hlist_nulls_del_init_rcu()'s pprev==NULL short-circuit to handle the
+case of an entry not currently linked in the table.
+
+Fixes: 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/netlink.c | 6 +++
+ drivers/net/ovpn/peer.c | 105 +++++++++++++++++++++++++------------
+ drivers/net/ovpn/peer.h | 1 +
+ 3 files changed, 79 insertions(+), 33 deletions(-)
+
+diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c
+index bdb56ef0c9040..0051166c59c75 100644
+--- a/drivers/net/ovpn/netlink.c
++++ b/drivers/net/ovpn/netlink.c
+@@ -527,6 +527,12 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
+ */
+ if (ret > 0)
+ ovpn_peer_hash_vpn_ip(peer);
++ /* if the remote endpoint was updated, the by_transp_addr hash bucket
++ * also needs to be refreshed, otherwise incoming packets from the new
++ * remote address would fail the lockless lookup
++ */
++ if (attrs[OVPN_A_PEER_REMOTE_IPV4] || attrs[OVPN_A_PEER_REMOTE_IPV6])
++ ovpn_peer_hash_transp_addr(peer);
+ spin_unlock_bh(&ovpn->lock);
+ ovpn_peer_put(peer);
+
+diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
+index 6b7e368f63f3a..f502f9c576f8f 100644
+--- a/drivers/net/ovpn/peer.c
++++ b/drivers/net/ovpn/peer.c
+@@ -185,6 +185,9 @@ int ovpn_peer_reset_sockaddr(struct ovpn_peer *peer,
+ &(*__tbl1)[ovpn_get_hash_slot(*__tbl1, _key, _key_len)];\
+ })
+
++static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
++ const struct ovpn_bind *bind);
++
+ /**
+ * ovpn_peer_endpoints_update - update remote or local endpoint for peer
+ * @peer: peer to update the remote endpoint for
+@@ -192,7 +195,6 @@ int ovpn_peer_reset_sockaddr(struct ovpn_peer *peer,
+ */
+ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
+ {
+- struct hlist_nulls_head *nhead;
+ struct sockaddr_storage ss;
+ struct sockaddr_in6 *sa6;
+ bool reset_cache = false;
+@@ -289,46 +291,23 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
+ spin_unlock_bh(&peer->lock);
+
+ /* rehashing is required only in MP mode as P2P has one peer
+- * only and thus there is no hashtable
++ * only and thus there is no hashtable.
++ *
++ * This function may be invoked concurrently, so re-read peer->bind
++ * under the proper locks and rehash against its current value.
+ */
+ if (peer->ovpn->mode != OVPN_MODE_MP)
+ return;
+
++ /* This function may be invoked concurrently, therefore another
++ * float may have happened in parallel: re-acquire the locks and
++ * rehash using the peer->bind->remote directly as key
++ */
+ spin_lock_bh(&peer->ovpn->lock);
+ spin_lock_bh(&peer->lock);
+ bind = rcu_dereference_protected(peer->bind,
+ lockdep_is_held(&peer->lock));
+- if (unlikely(!bind))
+- goto unlock2;
+-
+- /* peer may have been concurrently removed between the caller's
+- * initial lookup and our acquisition of ovpn->lock; skip the
+- * rehash so we don't re-insert a removed peer
+- */
+- if (unlikely(hlist_unhashed(&peer->hash_entry_id)))
+- goto unlock2;
+-
+- /* This function may be invoked concurrently, therefore another
+- * float may have happened in parallel: perform rehashing
+- * using the peer->bind->remote directly as key
+- */
+-
+- switch (bind->remote.in4.sin_family) {
+- case AF_INET:
+- salen = sizeof(*sa);
+- break;
+- case AF_INET6:
+- salen = sizeof(*sa6);
+- break;
+- }
+-
+- /* remove old hashing */
+- hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
+- /* re-add with new transport address */
+- nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
+- &bind->remote, salen);
+- hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
+-unlock2:
++ __ovpn_peer_hash_transp_addr(peer, bind);
+ spin_unlock_bh(&peer->lock);
+ spin_unlock_bh(&peer->ovpn->lock);
+ return;
+@@ -897,6 +876,66 @@ bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
+ return match;
+ }
+
++/* Move @peer to the by_transp_addr bucket matching its current bind.
++ *
++ * Caller must hold both peer->ovpn->lock and peer->lock, and must have
++ * already dereferenced a valid (non-NULL) peer->bind, passed in as @bind.
++ */
++static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
++ const struct ovpn_bind *bind)
++{
++ struct hlist_nulls_head *nhead;
++ size_t salen;
++
++ lockdep_assert_held(&peer->ovpn->lock);
++ lockdep_assert_held(&peer->lock);
++
++ if (WARN_ON_ONCE(!bind))
++ return;
++
++ /* peer may have been concurrently removed between the caller's
++ * initial lookup and our acquisition of ovpn->lock; skip the
++ * rehash so we don't re-insert a removed peer
++ */
++ if (unlikely(hlist_unhashed(&peer->hash_entry_id)))
++ return;
++
++ switch (bind->remote.in4.sin_family) {
++ case AF_INET:
++ salen = sizeof(struct sockaddr_in);
++ break;
++ case AF_INET6:
++ salen = sizeof(struct sockaddr_in6);
++ break;
++ default:
++ return;
++ }
++
++ /* remove old hashing (no-op if entry is not currently linked) */
++ hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
++ /* re-add with current transport address */
++ nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
++ &bind->remote, salen);
++ hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
++}
++
++void ovpn_peer_hash_transp_addr(struct ovpn_peer *peer)
++{
++ struct ovpn_bind *bind;
++
++ lockdep_assert_held(&peer->ovpn->lock);
++
++ /* rehashing makes sense only in multipeer mode */
++ if (peer->ovpn->mode != OVPN_MODE_MP)
++ return;
++
++ spin_lock_bh(&peer->lock);
++ bind = rcu_dereference_protected(peer->bind,
++ lockdep_is_held(&peer->lock));
++ __ovpn_peer_hash_transp_addr(peer, bind);
++ spin_unlock_bh(&peer->lock);
++}
++
+ void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer)
+ {
+ struct hlist_nulls_head *nhead;
+diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h
+index 4de5aeae33f7d..9a05a278e1cd0 100644
+--- a/drivers/net/ovpn/peer.h
++++ b/drivers/net/ovpn/peer.h
+@@ -148,6 +148,7 @@ struct ovpn_peer *ovpn_peer_get_by_id(struct ovpn_priv *ovpn, u32 peer_id);
+ struct ovpn_peer *ovpn_peer_get_by_dst(struct ovpn_priv *ovpn,
+ struct sk_buff *skb);
+ void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer);
++void ovpn_peer_hash_transp_addr(struct ovpn_peer *peer);
+ bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
+ struct ovpn_peer *peer);
+
+--
+2.53.0
+
--- /dev/null
+From 0eb6a27c132eb080761d78d1fc3fc3e5f0fc8c30 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 13:48:47 +0200
+Subject: ovpn: skip rehash for peers already removed from by_id
+
+From: Antonio Quartulli <antonio@openvpn.net>
+
+[ Upstream commit 33ec10567fe14456063daf549fdf1a4f53448e4c ]
+
+ovpn_nl_peer_set_doit() resolves the target peer via
+ovpn_peer_get_by_id() before taking ovpn->lock. In the window between
+the lookup (which only takes a refcount) and the subsequent
+spin_lock_bh(&ovpn->lock), a concurrent OVPN_CMD_PEER_DEL, keepalive
+expiry, or socket teardown can take ovpn->lock first, run
+ovpn_peer_remove() to unhash the peer from all four tables (by_id,
+by_vpn_addr4/6, by_transp_addr) and release the lock. set_doit then
+acquires ovpn->lock and calls ovpn_peer_hash_vpn_ip(), which
+re-inserts the now-removed peer back into the rehashing tables.
+
+The same race affects the float path: ovpn_peer_endpoints_update()
+holds only a refcount and acquires ovpn->lock very late (after async
+AEAD decrypt and a netlink notification), then rehashes the peer
+in the by_transp_addr table.
+
+The resurrected peer becomes reachable again from the RX lookup
+(ovpn_peer_get_by_transp_addr) and the TX VPN-IP lookup, even though
+userspace believes it is gone. Once the data-path refcount drops the
+peer is freed via call_rcu while the hash entries embedded in it
+remain linked, opening a UAF window.
+
+Bail out of the rehash when hash_entry_id is unhashed, mirroring
+the sentinel already used by ovpn_peer_remove() to detect the
+already-removed state. The check is safe under ovpn->lock, which
+serializes every mutation of hash_entry_id, and is a no-op for the
+add path because ovpn_peer_add_mp() inserts hash_entry_id before
+calling ovpn_peer_hash_vpn_ip().
+
+Fixes: 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/peer.c | 73 ++++++++++++++++++++++++-----------------
+ 1 file changed, 43 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
+index 85fa9bd475f45..6b7e368f63f3a 100644
+--- a/drivers/net/ovpn/peer.c
++++ b/drivers/net/ovpn/peer.c
+@@ -291,40 +291,46 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
+ /* rehashing is required only in MP mode as P2P has one peer
+ * only and thus there is no hashtable
+ */
+- if (peer->ovpn->mode == OVPN_MODE_MP) {
+- spin_lock_bh(&peer->ovpn->lock);
+- spin_lock_bh(&peer->lock);
+- bind = rcu_dereference_protected(peer->bind,
+- lockdep_is_held(&peer->lock));
+- if (unlikely(!bind)) {
+- spin_unlock_bh(&peer->lock);
+- spin_unlock_bh(&peer->ovpn->lock);
+- return;
+- }
++ if (peer->ovpn->mode != OVPN_MODE_MP)
++ return;
+
+- /* This function may be invoked concurrently, therefore another
+- * float may have happened in parallel: perform rehashing
+- * using the peer->bind->remote directly as key
+- */
++ spin_lock_bh(&peer->ovpn->lock);
++ spin_lock_bh(&peer->lock);
++ bind = rcu_dereference_protected(peer->bind,
++ lockdep_is_held(&peer->lock));
++ if (unlikely(!bind))
++ goto unlock2;
+
+- switch (bind->remote.in4.sin_family) {
+- case AF_INET:
+- salen = sizeof(*sa);
+- break;
+- case AF_INET6:
+- salen = sizeof(*sa6);
+- break;
+- }
++ /* peer may have been concurrently removed between the caller's
++ * initial lookup and our acquisition of ovpn->lock; skip the
++ * rehash so we don't re-insert a removed peer
++ */
++ if (unlikely(hlist_unhashed(&peer->hash_entry_id)))
++ goto unlock2;
+
+- /* remove old hashing */
+- hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
+- /* re-add with new transport address */
+- nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
+- &bind->remote, salen);
+- hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
+- spin_unlock_bh(&peer->lock);
+- spin_unlock_bh(&peer->ovpn->lock);
++ /* This function may be invoked concurrently, therefore another
++ * float may have happened in parallel: perform rehashing
++ * using the peer->bind->remote directly as key
++ */
++
++ switch (bind->remote.in4.sin_family) {
++ case AF_INET:
++ salen = sizeof(*sa);
++ break;
++ case AF_INET6:
++ salen = sizeof(*sa6);
++ break;
+ }
++
++ /* remove old hashing */
++ hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
++ /* re-add with new transport address */
++ nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
++ &bind->remote, salen);
++ hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
++unlock2:
++ spin_unlock_bh(&peer->lock);
++ spin_unlock_bh(&peer->ovpn->lock);
+ return;
+ unlock:
+ spin_unlock_bh(&peer->lock);
+@@ -901,6 +907,13 @@ void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer)
+ if (peer->ovpn->mode != OVPN_MODE_MP)
+ return;
+
++ /* peer may have been concurrently removed between the caller's
++ * initial lookup and our acquisition of ovpn->lock; skip the
++ * rehash so we don't re-insert a removed peer
++ */
++ if (hlist_unhashed(&peer->hash_entry_id))
++ return;
++
+ if (peer->vpn_addrs.ipv4.s_addr != htonl(INADDR_ANY)) {
+ /* remove potential old hashing */
+ hlist_nulls_del_init_rcu(&peer->hash_entry_addr4);
+--
+2.53.0
+
--- /dev/null
+From b86375bc7a97bb870b966e1d260187ea400e9af3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 13:48:51 +0200
+Subject: ovpn: zero-initialize sockaddr before learning a floated endpoint
+
+From: Antonio Quartulli <antonio@openvpn.net>
+
+[ Upstream commit 3f012bdbabe211ccbc0c50ea5a1dbc60f8af1532 ]
+
+ovpn_peer_endpoints_update() builds the new remote endpoint in an
+on-stack struct sockaddr_storage that is left uninitialized. For IPv4
+only sin_family/sin_addr/sin_port are written, leaving the 8-byte
+sin_zero padding as stack garbage (for IPv6, sin6_flowinfo is left
+uninitialized likewise).
+
+ovpn_peer_reset_sockaddr() -> ovpn_bind_from_sockaddr() then memcpy()s
+sizeof(struct sockaddr_in)/sizeof(struct sockaddr_in6) bytes - padding
+included - into bind->remote. That buffer is later hashed with jhash()
+over the same length to place the peer in the by_transp_addr table, so
+the garbage padding lands the floated peer in an essentially random
+bucket. Lockless lookups in ovpn_peer_get_by_transp_addr() build their
+key from a zero-initialized sockaddr_storage, compute a different bucket
+and fail to find the peer.
+
+This is also a plain use of uninitialized stack memory in jhash().
+
+Build the floated endpoint with a designated initializer so the
+padding (sin_zero for IPv4, sin6_flowinfo for IPv6) is zeroed as part
+of the assignment. This keeps the padding out of the by_transp_addr
+hash key without memset-ing the whole sockaddr_storage on every
+received packet.
+
+Fixes: f0281c1d3732 ("ovpn: add support for updating local or remote UDP endpoint")
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/peer.c | 31 +++++++++++++++++++++++--------
+ 1 file changed, 23 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
+index f502f9c576f8f..3824ee1c2e40a 100644
+--- a/drivers/net/ovpn/peer.c
++++ b/drivers/net/ovpn/peer.c
+@@ -218,9 +218,16 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
+ */
+ local_ip = &ip_hdr(skb)->daddr;
+ sa = (struct sockaddr_in *)&ss;
+- sa->sin_family = AF_INET;
+- sa->sin_addr.s_addr = ip_hdr(skb)->saddr;
+- sa->sin_port = udp_hdr(skb)->source;
++ /* use a designated initializer so the sin_zero padding
++ * is zeroed (it ends up in the by_transp_addr hash key)
++ * without memset-ing the whole sockaddr_storage on the
++ * RX fast path
++ */
++ *sa = (struct sockaddr_in) {
++ .sin_family = AF_INET,
++ .sin_addr.s_addr = ip_hdr(skb)->saddr,
++ .sin_port = udp_hdr(skb)->source,
++ };
+ salen = sizeof(*sa);
+ reset_cache = true;
+ break;
+@@ -246,11 +253,19 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
+ */
+ local_ip = &ipv6_hdr(skb)->daddr;
+ sa6 = (struct sockaddr_in6 *)&ss;
+- sa6->sin6_family = AF_INET6;
+- sa6->sin6_addr = ipv6_hdr(skb)->saddr;
+- sa6->sin6_port = udp_hdr(skb)->source;
+- sa6->sin6_scope_id = ipv6_iface_scope_id(&ipv6_hdr(skb)->saddr,
+- skb->skb_iif);
++ /* use a designated initializer so the sin6_flowinfo
++ * padding is zeroed (it ends up in the by_transp_addr
++ * hash key) without memset-ing the whole
++ * sockaddr_storage on the RX fast path
++ */
++ *sa6 = (struct sockaddr_in6) {
++ .sin6_family = AF_INET6,
++ .sin6_addr = ipv6_hdr(skb)->saddr,
++ .sin6_port = udp_hdr(skb)->source,
++ .sin6_scope_id =
++ ipv6_iface_scope_id(&ipv6_hdr(skb)->saddr,
++ skb->skb_iif),
++ };
+ salen = sizeof(*sa6);
+ reset_cache = true;
+ break;
+--
+2.53.0
+
--- /dev/null
+From 884aa49e157bf14ac7f79502cbf920348b8041ae Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 17:00:30 +0000
+Subject: pds_core: cancel pending PCI reset work on AER recovery
+
+From: Nikhil P. Rao <nikhil.rao@amd.com>
+
+[ Upstream commit 57d635329d799b79096155cdf47ee0013d6780d1 ]
+
+pdsc_check_pci_health() queues pci_reset_work when it sees a broken PCI
+connection, and nothing cancels it. When the PCI core starts AER
+recovery, pdsc_pci_error_detected() runs pdsc_reset_prepare() and
+recovers the device, but a pci_reset_work queued just before is left
+pending. If it runs after recovery released the device lock, it resets a
+device the driver now considers healthy, bouncing the link for no reason.
+
+Cancel pci_reset_work in pdsc_pci_error_detected() after
+pdsc_reset_prepare(), which has already stopped the health thread so it
+cannot requeue the work. cancel_work_sync() is safe under the device
+lock here because pdsc_pci_reset_thread() uses pci_try_reset_function(),
+which returns instead of blocking on the lock. Only PFs initialize
+pci_reset_work, so guard the cancel with !is_virtfn.
+
+Fixes: 81665adf25d2 ("pds_core: Fix pdsc_check_pci_health function to use work thread")
+Reported-by: sashiko-bot <sashiko-bot@kernel.org>
+Closes: https://sashiko.dev/#/patchset/20260714180223.1642792-2-nikhil.rao%40amd.com?part=1
+Signed-off-by: Nikhil P. Rao <nikhil.rao@amd.com>
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Link: https://patch.msgid.link/20260727170030.361116-1-nikhil.rao@amd.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/amd/pds_core/main.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c
+index dad7fd03287db..61be6def50b1c 100644
+--- a/drivers/net/ethernet/amd/pds_core/main.c
++++ b/drivers/net/ethernet/amd/pds_core/main.c
+@@ -562,7 +562,11 @@ static pci_ers_result_t pdsc_pci_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t error)
+ {
+ if (error == pci_channel_io_frozen) {
++ struct pdsc *pdsc = pci_get_drvdata(pdev);
++
+ pdsc_reset_prepare(pdev);
++ if (!pdev->is_virtfn)
++ cancel_work_sync(&pdsc->pci_reset_work);
+ return PCI_ERS_RESULT_NEED_RESET;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 1db3da527cdd7c78345e3f374a490511bed9a356 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 16:45:48 +0000
+Subject: pds_core: keep the health thread stopped during reset
+
+From: Nikhil P. Rao <nikhil.rao@amd.com>
+
+[ Upstream commit cd09971dcc1c499ae0879010a00e9dba87abdc4f ]
+
+Commit d9407ff11809 ("pds_core: Prevent health thread from running
+during reset/remove") stops the health thread with cancel_work_sync()
+before a reset, but a devcmd timeout during pdsc_fw_down() re-queues
+health_work, so pdsc_health_thread() runs again mid-reset and double
+allocates the core DMA queues via pdsc_fw_up().
+
+Only the reset path is affected: on remove PDSC_S_STOPPING_DRIVER gates
+the health thread and the workqueue is destroyed.
+
+Use disable_work_sync() to cancel health_work and block further
+queue_work() on it, and enable_work() in pdsc_restart_health_thread() to
+re-allow it after the reset.
+
+disable_work_sync() keeps a disable depth, so every disable must be
+matched by one enable. pdsc_reset_prepare() stops the health thread and
+pdsc_reset_done() restarts it. On the AER path pdsc_pci_error_detected()
+calls pdsc_reset_prepare(), then pdsc_pci_error_resume() re-inits via
+pci_reset_function_locked() (pds_core has no .slot_reset handler), which
+runs the pair again - stopping the thread twice but restarting it once.
+Gate the disable and enable on a health_stopped flag so each fires at
+most once per stopped/running transition.
+
+Fixes: d9407ff11809 ("pds_core: Prevent health thread from running during reset/remove")
+Reported-by: sashiko-bot <sashiko-bot@kernel.org>
+Closes: https://sashiko.dev/#/patchset/20260629200358.2626129-1-nikhil.rao%40amd.com?part=2
+Signed-off-by: Nikhil P. Rao <nikhil.rao@amd.com>
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Link: https://patch.msgid.link/20260727164548.359562-1-nikhil.rao@amd.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/amd/pds_core/core.h | 1 +
+ drivers/net/ethernet/amd/pds_core/main.c | 10 ++++++++--
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h
+index 0b53a1fab46d0..e2a86ef581dfc 100644
+--- a/drivers/net/ethernet/amd/pds_core/core.h
++++ b/drivers/net/ethernet/amd/pds_core/core.h
+@@ -171,6 +171,7 @@ struct pdsc {
+ struct timer_list wdtimer;
+ unsigned int wdtimer_period;
+ struct work_struct health_work;
++ bool health_stopped;
+ struct devlink_health_reporter *fw_reporter;
+ u32 fw_recoveries;
+
+diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c
+index a4962dba3140b..dad7fd03287db 100644
+--- a/drivers/net/ethernet/amd/pds_core/main.c
++++ b/drivers/net/ethernet/amd/pds_core/main.c
+@@ -471,8 +471,10 @@ static void pdsc_stop_health_thread(struct pdsc *pdsc)
+ return;
+
+ timer_shutdown_sync(&pdsc->wdtimer);
+- if (pdsc->health_work.func)
+- cancel_work_sync(&pdsc->health_work);
++ if (pdsc->health_work.func && !pdsc->health_stopped) {
++ disable_work_sync(&pdsc->health_work);
++ pdsc->health_stopped = true;
++ }
+ }
+
+ static void pdsc_restart_health_thread(struct pdsc *pdsc)
+@@ -480,6 +482,10 @@ static void pdsc_restart_health_thread(struct pdsc *pdsc)
+ if (pdsc->pdev->is_virtfn)
+ return;
+
++ if (pdsc->health_stopped) {
++ enable_work(&pdsc->health_work);
++ pdsc->health_stopped = false;
++ }
+ timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0);
+ mod_timer(&pdsc->wdtimer, jiffies + 1);
+ }
+--
+2.53.0
+
--- /dev/null
+From 50f1d566604c4da03cf2f95dbd7abdce9bc428a6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 19 Jul 2026 15:35:59 +0200
+Subject: pinctrl: qcom: ipq806x: mark gpio as a GPIO pin function
+
+From: Hans Ulli Kroll <linux@ulli-kroll.de>
+
+[ Upstream commit 687f39faccba29ab26de965411db37e849af8ec2 ]
+
+The qcom pinctrl core supports marking functions that represent GPIO mode
+via PINCTRL_GPIO_PINFUNCTION(), so that strict pinmuxing does not reject
+GPIO requests for pins that are muxed to the GPIO function.
+
+Add a IPQ_GPIO_PIN_FUNCTION() helper and use it for the ipq806x gpio
+function, matching how the msm-based qcom drivers handle this.
+
+This allows ipq806x to keep the GPIO-related configuration in DTS
+without tripping over strict pinmux ownership
+checks.
+
+Fixes: cc85cb96e2e4 ("pinctrl: qcom: make the pinmuxing strict")
+Signed-off-by: Hans Ulli Kroll <linux@ulli-kroll.de>
+Acked-by: Linus Walleij <linusw@kernel.org>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260719134548.8830-2-linux@ulli-kroll.de
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pinctrl/qcom/pinctrl-ipq8064.c | 2 +-
+ drivers/pinctrl/qcom/pinctrl-msm.h | 5 +++++
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/pinctrl/qcom/pinctrl-ipq8064.c b/drivers/pinctrl/qcom/pinctrl-ipq8064.c
+index 0a9e357e64c60..c1651f112950e 100644
+--- a/drivers/pinctrl/qcom/pinctrl-ipq8064.c
++++ b/drivers/pinctrl/qcom/pinctrl-ipq8064.c
+@@ -480,7 +480,7 @@ static const char * const ps_hold_groups[] = {
+ };
+
+ static const struct pinfunction ipq8064_functions[] = {
+- IPQ_PIN_FUNCTION(gpio),
++ IPQ_GPIO_PIN_FUNCTION(gpio),
+ IPQ_PIN_FUNCTION(mdio),
+ IPQ_PIN_FUNCTION(ssbi),
+ IPQ_PIN_FUNCTION(spmi),
+diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h
+index 120217012a9f6..33d8b17f2e559 100644
+--- a/drivers/pinctrl/qcom/pinctrl-msm.h
++++ b/drivers/pinctrl/qcom/pinctrl-msm.h
+@@ -24,6 +24,11 @@ struct pinctrl_pin_desc;
+ fname##_groups, \
+ ARRAY_SIZE(fname##_groups))
+
++#define IPQ_GPIO_PIN_FUNCTION(fname) \
++ [IPQ_MUX_##fname] = PINCTRL_GPIO_PINFUNCTION(#fname, \
++ fname##_groups, \
++ ARRAY_SIZE(fname##_groups))
++
+ #define MSM_PIN_FUNCTION(fname) \
+ [msm_mux_##fname] = PINCTRL_PINFUNCTION(#fname, \
+ fname##_groups, \
+--
+2.53.0
+
--- /dev/null
+From eced0e0c1d916d59fe09ecfe4ef2c394ec6d0fdc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 19 Jul 2026 15:36:00 +0200
+Subject: pinctrl: qcom: ipq806x: mark pci reset as a GPIO pin function
+
+From: Hans Ulli Kroll <linux@ulli-kroll.de>
+
+[ Upstream commit fd46760956509f580f7d3d25db4de10e7c6f949b ]
+
+The qcom pinctrl core supports marking functions that represent GPIO mode
+via PINCTRL_GPIO_PINFUNCTION(), so that strict pinmuxing does not reject
+GPIO requests for pins that are muxed to the GPIO function.
+
+Mark PCIe reset as GPIO pin function
+
+This allows ipq806x to keep the PCIe-reset related configuration in DTS
+without tripping over strict pinmux ownership checks.
+
+Fixes: cc85cb96e2e4 ("pinctrl: qcom: make the pinmuxing strict")
+Signed-off-by: Hans Ulli Kroll <linux@ulli-kroll.de>
+Acked-by: Linus Walleij <linusw@kernel.org>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260719134548.8830-3-linux@ulli-kroll.de
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pinctrl/qcom/pinctrl-ipq8064.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/pinctrl/qcom/pinctrl-ipq8064.c b/drivers/pinctrl/qcom/pinctrl-ipq8064.c
+index c1651f112950e..f35dbe07ab6fe 100644
+--- a/drivers/pinctrl/qcom/pinctrl-ipq8064.c
++++ b/drivers/pinctrl/qcom/pinctrl-ipq8064.c
+@@ -507,19 +507,19 @@ static const struct pinfunction ipq8064_functions[] = {
+ IPQ_PIN_FUNCTION(usb2_hsic),
+ IPQ_PIN_FUNCTION(rgmii2),
+ IPQ_PIN_FUNCTION(sata),
+- IPQ_PIN_FUNCTION(pcie1_rst),
++ IPQ_GPIO_PIN_FUNCTION(pcie1_rst),
+ IPQ_PIN_FUNCTION(pcie1_prsnt),
+ IPQ_PIN_FUNCTION(pcie1_pwren_n),
+ IPQ_PIN_FUNCTION(pcie1_pwren),
+ IPQ_PIN_FUNCTION(pcie1_pwrflt),
+ IPQ_PIN_FUNCTION(pcie1_clk_req),
+- IPQ_PIN_FUNCTION(pcie2_rst),
++ IPQ_GPIO_PIN_FUNCTION(pcie2_rst),
+ IPQ_PIN_FUNCTION(pcie2_prsnt),
+ IPQ_PIN_FUNCTION(pcie2_pwren_n),
+ IPQ_PIN_FUNCTION(pcie2_pwren),
+ IPQ_PIN_FUNCTION(pcie2_pwrflt),
+ IPQ_PIN_FUNCTION(pcie2_clk_req),
+- IPQ_PIN_FUNCTION(pcie3_rst),
++ IPQ_GPIO_PIN_FUNCTION(pcie3_rst),
+ IPQ_PIN_FUNCTION(pcie3_prsnt),
+ IPQ_PIN_FUNCTION(pcie3_pwren_n),
+ IPQ_PIN_FUNCTION(pcie3_pwren),
+--
+2.53.0
+
--- /dev/null
+From 66615729bc455a5c238a8a00bc2e94161aced88d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 12:29:48 +0000
+Subject: Revert "net: thunderbolt: Enable end-to-end flow control also in
+ transmit"
+
+From: Fan Ye <fy15309206903@gmail.com>
+
+[ Upstream commit 1881f2efbf7f78dc0a79a387b29fde6ff56d3731 ]
+
+This reverts commit a8065af3346ebd7c76ebc113451fb3ba94cf7769.
+
+Per the USB4 spec, a Transmit Descriptor Ring with E2E flow control
+disabled does not require any credits to be available before the Host
+Interface Adapter Layer transmits a tunneled packet from it. Once E2E is
+enabled on that ring the controller must first obtain end-to-end
+credits.
+
+The ASMedia ASM4242 USB4 host router (PCI 1b21:2425) never delivers
+those credits. The controller does accept the configuration: reading the
+ring OPTIONS register back right after tb_ring_start() returns exactly
+what was written, including RING_FLAG_E2E_FLOW_CONTROL (bit 28) and the
+E2E HopID field. No credit ever arrives though, so the Tx ring's
+hardware consumer index never advances and the link carries no traffic
+at all.
+
+Measured on two hosts connected point to point, onboard ASM4242 on MSI
+X870E and X870, v6.17, stock drivers/net/thunderbolt/main.c with only
+this revert applied on top:
+
+ before: 100% packet loss to the peer; thunderbolt0 is up and the
+ XDomain handshake completes ("new host found"), but iperf3
+ fails with "No route to host" once the neighbour entry
+ expires
+ after: 0% packet loss, 0.28 ms RTT; iperf3 4.21 Gb/s one way and
+ 5.17 Gb/s the other (5 runs each, stddev <= 0.02), 1
+ retransmit in 10 s
+
+An instrumented build additionally showed a frozen-Tx-consumer watchdog
+firing ~30k times in a 10 s window before this change.
+
+Rx-side E2E is not touched by this revert, so peers that do return
+credits keep receive-side flow control.
+
+ASMedia does not look like an isolated case. The out-of-tree
+thunderbolt-ibverbs project disables native E2E on AMD NHI by default,
+noting that "Strix Halo has reproduced TX completion wedges with
+multiple native E2E rings active" -- the same failure mode, on a
+different vendor. Since the driver has no way to tell in advance which
+host router returns the credits, going back to the previous behaviour
+looks safer than adding a quirk per affected part; Tx-side E2E can be
+reintroduced as an opt-in for controllers that are known to implement
+the credit return.
+
+Note that the reverted commit was not fixing a reported problem, it was
+derived from the spec wording alone, so this revert is not expected to
+regress a known workload. Cc'ing the original author in case there was
+one.
+
+Fixes: a8065af3346e ("net: thunderbolt: Enable end-to-end flow control also in transmit")
+Cc: zhangjianrong <zhangjianrong5@huawei.com>
+Signed-off-by: Fan Ye <fy15309206903@gmail.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Link: https://patch.msgid.link/20260727123002.25225-1-fy15309206903@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/thunderbolt/main.c | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c
+index 5d7d11d75b0b8..960839a651e51 100644
+--- a/drivers/net/thunderbolt/main.c
++++ b/drivers/net/thunderbolt/main.c
+@@ -928,12 +928,8 @@ static int tbnet_open(struct net_device *dev)
+
+ netif_carrier_off(dev);
+
+- flags = RING_FLAG_FRAME;
+- /* Only enable full E2E if the other end supports it too */
+- if (tbnet_e2e && net->svc->prtcstns & TBNET_E2E)
+- flags |= RING_FLAG_E2E;
+-
+- ring = tb_ring_alloc_tx(xd->tb->nhi, -1, TBNET_RING_SIZE, flags);
++ ring = tb_ring_alloc_tx(xd->tb->nhi, -1, TBNET_RING_SIZE,
++ RING_FLAG_FRAME);
+ if (!ring) {
+ netdev_err(dev, "failed to allocate Tx ring\n");
+ return -ENOMEM;
+@@ -952,6 +948,11 @@ static int tbnet_open(struct net_device *dev)
+ sof_mask = BIT(TBIP_PDF_FRAME_START);
+ eof_mask = BIT(TBIP_PDF_FRAME_END);
+
++ flags = RING_FLAG_FRAME;
++ /* Only enable full E2E if the other end supports it too */
++ if (tbnet_e2e && net->svc->prtcstns & TBNET_E2E)
++ flags |= RING_FLAG_E2E;
++
+ ring = tb_ring_alloc_rx(xd->tb->nhi, -1, TBNET_RING_SIZE, flags,
+ net->tx_ring.ring->hop, sof_mask,
+ eof_mask, tbnet_start_poll, net);
+--
+2.53.0
+
--- /dev/null
+From c700d726caf538a73ac46a4f5177250ce019fa6a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 15:10:43 +0200
+Subject: s390/ism: Fix UAF of sba and ieq during ism_dev_exit()
+
+From: Alexandra Winter <wintera@linux.ibm.com>
+
+[ Upstream commit b1896543ce59c4258625a35cf41e23a9a1f80ea2 ]
+
+A ism interrupt handler can be active in parallel with ism_dev_exit(),
+accessing freed data structures.
+
+No new interrupts will be generated after unregister_ieq(). Drain ongoing
+interrupt handlers by free_irq(), before freeing ism data structures.
+
+Fixes: 684b89bc39ce ("s390/ism: add device driver for internal shared memory")
+Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
+Link: https://patch.msgid.link/20260805131043.954639-1-wintera@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/s390/net/ism_drv.c | 19 +++++++++++++++----
+ 1 file changed, 15 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
+index f84aa2e676e9b..b842410cf41cc 100644
+--- a/drivers/s390/net/ism_drv.c
++++ b/drivers/s390/net/ism_drv.c
+@@ -149,13 +149,16 @@ static int unregister_sba(struct ism_dev *ism)
+ if (ret && ret != ISM_ERROR)
+ return -EIO;
+
++ return 0;
++}
++
++static void ism_free_sba(struct ism_dev *ism)
++{
+ dma_free_coherent(&ism->pdev->dev, PAGE_SIZE,
+ ism->sba, ism->sba_dma_addr);
+
+ ism->sba = NULL;
+ ism->sba_dma_addr = 0;
+-
+- return 0;
+ }
+
+ static int unregister_ieq(struct ism_dev *ism)
+@@ -169,13 +172,16 @@ static int unregister_ieq(struct ism_dev *ism)
+ if (ret && ret != ISM_ERROR)
+ return -EIO;
+
++ return 0;
++}
++
++static void ism_free_ieq(struct ism_dev *ism)
++{
+ dma_free_coherent(&ism->pdev->dev, PAGE_SIZE,
+ ism->ieq, ism->ieq_dma_addr);
+
+ ism->ieq = NULL;
+ ism->ieq_dma_addr = 0;
+-
+- return 0;
+ }
+
+ static int ism_read_local_gid(struct dibs_dev *dibs)
+@@ -574,6 +580,7 @@ static int ism_dev_init(struct ism_dev *ism)
+
+ unreg_sba:
+ unregister_sba(ism);
++ ism_free_sba(ism);
+ free_irq:
+ free_irq(pci_irq_vector(pdev, 0), ism);
+ free_vectors:
+@@ -586,9 +593,13 @@ static void ism_dev_exit(struct ism_dev *ism)
+ {
+ struct pci_dev *pdev = ism->pdev;
+
++ /* ism will only generate new IRQs while ieq & sba are registered */
+ unregister_ieq(ism);
+ unregister_sba(ism);
++ /* drain ongoing irpt handlers */
+ free_irq(pci_irq_vector(pdev, 0), ism);
++ ism_free_ieq(ism);
++ ism_free_sba(ism);
+ pci_free_irq_vectors(pdev);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 00537ea419ca796773b9ca4883ed23d9e095f27b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 11:18:40 -0400
+Subject: sctp: clear control chunk transport if it is being removed
+
+From: Xin Long <lucien.xin@gmail.com>
+
+[ Upstream commit c9158ceaf27780ef64534ad72f44ffde3f8ccc49 ]
+
+sctp_make_heartbeat_ack() caches the destination transport in
+chunk->transport without taking a reference. When src_out_of_asoc_ok is
+enabled, the HEARTBEAT ACK may remain queued on control_chunk_list instead
+of being transmitted immediately.
+
+If the peer transport is removed while the chunk is still queued,
+sctp_assoc_rm_peer() drops the transport and schedules it for RCU freeing,
+but only clears cached transport pointers in out_chunk_list. The queued
+control chunk therefore retains a dangling transport pointer.
+
+Once an ASCONF_ACK clears the suppression and the queued control chunk is
+transmitted, SCTP dereferences the stale transport pointer, leading to a
+use-after-free.
+
+Fix this by also clearing chunk->transport for queued control chunks in
+control_chunk_list when removing the transport.
+
+Fixes: 8a07eb0a50ae ("sctp: Add ASCONF operation on the single-homed host")
+Reported-by: Daniele Linguaglossa <danielelinguaglossa@gmail.com>
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/7e1168cb722132152a29d47e5eafaeac4a3bf6f3.1785943120.git.lucien.xin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/associola.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/net/sctp/associola.c b/net/sctp/associola.c
+index e560f7ee4adb3..9fff11115b417 100644
+--- a/net/sctp/associola.c
++++ b/net/sctp/associola.c
+@@ -573,6 +573,10 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
+ if (ch->transport == peer)
+ ch->transport = NULL;
+
++ list_for_each_entry(ch, &asoc->outqueue.control_chunk_list, list)
++ if (ch->transport == peer)
++ ch->transport = NULL;
++
+ asoc->peer.transport_count--;
+
+ sctp_ulpevent_notify_peer_addr_change(peer, SCTP_ADDR_REMOVED, 0);
+--
+2.53.0
+
--- /dev/null
+From a676a8861312848d181a8f11f169642523a26535 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 10:55:14 +0800
+Subject: sctp: fix addip_serial increment on ASCONF_ACK allocation failure
+
+From: Qing Luo <luoqing@kylinos.cn>
+
+[ Upstream commit aa2e13ae8d3cbe2c15ef4f7e971b2de0832794aa ]
+
+In sctp_process_asconf(), when sctp_make_asconf_ack() fails to allocate
+the ASCONF_ACK chunk due to memory pressure, the code jumps to the
+done label where asoc->peer.addip_serial is unconditionally incremented.
+
+This leaves the peer's ASCONF (serial N) unacknowledged while the local
+endpoint now expects serial N+1. When the peer retransmits serial N, it
+falls into the serial < addip_serial + 1 branch ,
+which attempts to look up a cached ACK for serial N. No cached ACK
+exists since the allocation failed, so the retransmission is silently
+discarded. The peer eventually times out and ABORTs the association.
+
+Move the addip_serial increment inside the if (asconf_ack) block so that
+the serial number is only advanced when the ASCONF_ACK is successfully
+created and cached. This way, on allocation failure, the serial number
+is unchanged and the peer's retransmitted ASCONF will be correctly
+re-processed.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Qing Luo <luoqing@kylinos.cn>
+Acked-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/20260804025514.241767-1-l1138897701@163.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/sm_make_chunk.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
+index 721e147091a97..757aff3e917dc 100644
+--- a/net/sctp/sm_make_chunk.c
++++ b/net/sctp/sm_make_chunk.c
+@@ -3336,12 +3336,11 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
+ goto done;
+ }
+ done:
+- asoc->peer.addip_serial++;
+-
+ /* If we are sending a new ASCONF_ACK hold a reference to it in assoc
+ * after freeing the reference to old asconf ack if any.
+ */
+ if (asconf_ack) {
++ asoc->peer.addip_serial++;
+ sctp_chunk_hold(asconf_ack);
+ list_add_tail(&asconf_ack->transmitted_list,
+ &asoc->asconf_ack_list);
+--
+2.53.0
+
--- /dev/null
+From 277b423d991c08381f4f213fdda7662f33e38c16 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 21:46:35 +0200
+Subject: selftests/ftrace: refactor eprobes test to fix argument checks
+
+From: Martin Kaiser <martin@kaiser.cx>
+
+[ Upstream commit 6e3abef2a27e7402a94111c9eff85d887e64a309 ]
+
+The add/remove eprobe test installs an eprobe for the openat syscall and
+runs ls. It checks the filenames that were opened by ls against a
+whitelist and a blacklist.
+
+Commit 206b25c09080 ("tracing: eprobe: read the complete FILTER_PTR_STRING
+pointer") fixed access to some string fields in eprobes. This triggers
+test failures as the blacklist does not allow relative paths for the
+openat parameters.
+
+What makes this test unstable is the fact that the openat calls vary a
+lot between different systems.
+
+Refactor the test to make it more robust. "cd <directory>" will issue a
+chdir syscall with the target directory as parameter. Set an eprobe on
+the sys_enter_chdir event and filter for the exact directory name. Allow
+(fault) as fallback.
+
+Link: https://lore.kernel.org/all/20260804194705.760893-1-martin@kaiser.cx/
+
+Fixes: 206b25c09080 ("tracing: eprobe: read the complete FILTER_PTR_STRING pointer")
+Reported-by: kernel test robot <oliver.sang@intel.com>
+Closes: https://lore.kernel.org/oe-lkp/202607151010.b68428e1-lkp@intel.com
+Signed-off-by: Martin Kaiser <martin@kaiser.cx>
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ftrace/test.d/dynevent/add_remove_eprobe.tc | 16 +++++-----------
+ 1 file changed, 5 insertions(+), 11 deletions(-)
+
+diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
+index c300eb0202620..e2322693d0c32 100644
+--- a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
++++ b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
+@@ -1,16 +1,16 @@
+ #!/bin/sh
+ # SPDX-License-Identifier: GPL-2.0
+ # description: Generic dynamic event - add/remove eprobe events
+-# requires: dynamic_events events/syscalls/sys_enter_openat "<attached-group>.<attached-event> [<args>]":README
++# requires: dynamic_events events/syscalls/sys_enter_chdir "<attached-group>.<attached-event> [<args>]":README
+
+ echo 0 > events/enable
+
+ clear_dynamic_events
+
+ SYSTEM="syscalls"
+-EVENT="sys_enter_openat"
++EVENT="sys_enter_chdir"
+ FIELD="filename"
+-EPROBE="eprobe_open"
++EPROBE="eprobe_chdir"
+ OPTIONS="file=+0(\$filename):ustring"
+ echo "e:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
+
+@@ -18,20 +18,14 @@ grep -q "$EPROBE" dynamic_events
+ test -d events/eprobes/$EPROBE
+
+ echo 1 > events/eprobes/$EPROBE/enable
+-ls
++cd /sys/kernel/tracing
+ echo 0 > events/eprobes/$EPROBE/enable
+
+-content=`grep '^ *ls-' trace | grep 'file='`
+-nocontent=`grep '^ *ls-' trace | grep 'file=' | grep -v -e '"/' -e '"."' -e '(fault)' ` || true
+-
++content=`grep -e 'file="/sys/kernel/tracing"\|(fault)' trace`
+ if [ -z "$content" ]; then
+ exit_fail
+ fi
+
+-if [ ! -z "$nocontent" ]; then
+- exit_fail
+-fi
+-
+ echo "-:$EPROBE" >> dynamic_events
+
+ ! grep -q "$EPROBE" dynamic_events
+--
+2.53.0
+
--- /dev/null
+From f568f0154a0abdf922768ea44088083cb82f6ef9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jul 2026 09:59:55 +0000
+Subject: selftests/sched_ext: Handle sleeping task affinity changes in numa
+ test
+
+From: Kuba Piecuch <jpiecuch@google.com>
+
+[ Upstream commit d4a00d61a5c2c24973175ace5368d1f6acf9bb0a ]
+
+When a sleeping task's affinity is changed, task_cpu(p) can be outside
+of p->cpus_ptr until after select_task_rq() selects a new runqueue for
+the task during wakeup.
+
+Thus, the task's NUMA node determined by numa_select_cpu() can be
+completely outside of the task's cpumask, leading to
+scx_pick_{idle,any}_cpu_node() failing to find an eligible CPU and
+returning -EBUSY. This leads to the numa.bpf.c scheduler abnormally
+exiting with the following message in dmesg:
+
+sched_ext: numa: invalid CPU -16
+ scx_bpf_cpu_node+0x120/0x190
+ bpf_prog_0a34b8e0f515771f_numa_select_cpu+0x108/0x14e
+ bpf__sched_ext_ops_select_cpu+0x4f/0xb4
+ select_task_rq_scx+0xb0/0x210
+ select_task_rq+0xa0/0xd0
+ __try_to_wake_up+0x196/0x650
+ complete_all+0x76/0x100
+ migration_cpu_stop+0x22b/0x300
+ cpu_stopper_thread+0xc1/0x180
+ smpboot_thread_fn+0x16b/0x230
+ kthread+0x2d7/0x350
+ ret_from_fork+0x1c2/0x350
+ ret_from_fork_asm+0x1a/0x30
+
+Make numa_select_cpu() robust against this case by returning @prev_cpu
+if no CPU could be found in the selected NUMA node _and_ we have reason
+to believe that the task's affinity was changed while it was sleeping.
+
+Fixes: 5ae5161820e5 ("selftests/sched_ext: Add NUMA-aware scheduler test")
+Signed-off-by: Kuba Piecuch <jpiecuch@google.com>
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/sched_ext/numa.bpf.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/tools/testing/selftests/sched_ext/numa.bpf.c b/tools/testing/selftests/sched_ext/numa.bpf.c
+index a79d86ed54a1b..0ebb6170331bf 100644
+--- a/tools/testing/selftests/sched_ext/numa.bpf.c
++++ b/tools/testing/selftests/sched_ext/numa.bpf.c
+@@ -34,7 +34,8 @@ static bool is_cpu_idle(s32 cpu, int node)
+ s32 BPF_STRUCT_OPS(numa_select_cpu,
+ struct task_struct *p, s32 prev_cpu, u64 wake_flags)
+ {
+- int node = __COMPAT_scx_bpf_cpu_node(scx_bpf_task_cpu(p));
++ s32 task_cpu = scx_bpf_task_cpu(p);
++ int node = __COMPAT_scx_bpf_cpu_node(task_cpu);
+ s32 cpu;
+
+ /*
+@@ -48,6 +49,16 @@ s32 BPF_STRUCT_OPS(numa_select_cpu,
+ cpu = __COMPAT_scx_bpf_pick_any_cpu_node(p->cpus_ptr, node,
+ __COMPAT_SCX_PICK_IDLE_IN_NODE);
+
++ /*
++ * @task_cpu may be outside of p->cpus_ptr if @p's affinity
++ * changed while it was sleeping. This means it's possible for
++ * p->cpus_ptr to not include any CPUs from @node.
++ * If we failed to find a cpu in @node, check if @task_cpu
++ * is outside of p->cpus_ptr and just return @prev_cpu if it is.
++ */
++ if (cpu < 0 && !bpf_cpumask_test_cpu(task_cpu, p->cpus_ptr))
++ return prev_cpu;
++
+ if (is_cpu_idle(cpu, node))
+ scx_bpf_error("CPU %d should be marked as busy", cpu);
+
+--
+2.53.0
+
drm-amd-display-add-av-mute-wait-frames-to-dce110_se.patch
drm-amd-display-check-for-tg-ops-in-dce110_set_avmut.patch
sched-fair-separate-se-vlag-from-se-vprot.patch
+arm64-dts-qcom-rename-x1e80100-to-hamoa.patch
+arm64-dts-qcom-rework-x1-based-asus-zenbook-a14-s-di.patch
+arm64-dts-qcom-rename-x1p42100-to-purwa.patch
+arm64-dts-qcom-purwa-fix-gpu-iommu-property.patch
+arm64-dts-qcom-sdm850-lenovo-yoga-c630-lower-psci-cl.patch
+nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch
+arm64-dts-broadcom-bcm2712-remove-non-functional-el2.patch
+xfs-handle-null-b_addr-in-xfs_buf_free.patch
+arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch
+selftests-sched_ext-handle-sleeping-task-affinity-ch.patch
+pinctrl-qcom-ipq806x-mark-gpio-as-a-gpio-pin-functio.patch
+pinctrl-qcom-ipq806x-mark-pci-reset-as-a-gpio-pin-fu.patch
+ovpn-add-missing-rtnl_link_ops-get_size-callback.patch
+arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch
+ovpn-skip-rehash-for-peers-already-removed-from-by_i.patch
+ovpn-rehash-peer-in-by_transp_addr-table-on-cmd_peer.patch
+ovpn-ensure-socket-is-owned-by-ovpn-before-deref-sk_.patch
+ovpn-zero-initialize-sockaddr-before-learning-a-floa.patch
+ovpn-hash-floated-peer-by-transport-identity-only.patch
+ovpn-disable-ipv4-redirects-on-mp-interfaces.patch
+ovpn-ensure-tcp-vars-are-initialized-first.patch
+ovpn-fix-incorrect-use-of-rcu_access_pointer.patch
+drm-bridge-ps8640-propagate-aux-transfer-register-er.patch
+net-hns3-fix-speed-configuration-residue-after-drive.patch
+revert-net-thunderbolt-enable-end-to-end-flow-contro.patch
+bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch
+enic-fix-tx_hang_reset-use-after-free-on-device-remo.patch
+net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch
+pds_core-keep-the-health-thread-stopped-during-reset.patch
+pds_core-cancel-pending-pci-reset-work-on-aer-recove.patch
+netfilter-ipset-switch-ext_size-to-atomic64_t.patch
+ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch
+ipvs-return-the-csum-validation-for-forward-hook.patch
+watchdog-bd96801_wdt-fix-timeout-for-enabled-wdg.patch
+btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch
+btrfs-update-the-kconfig-string-for-config_btrfs_exp.patch
+btrfs-move-large-data-folios-out-of-experimental-fea.patch
+btrfs-disable-bs-ps-support-if-no-transparent-hugepa.patch
+bpf-preserve-pointer-state-for-commuted-arithmetic.patch
+bpf-split-check_reg_sane_offset-in-two-parts.patch
+bpf-propagate-untrusted-pointer-state-in-commuted-ar.patch
+net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch
+net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch
+net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch
+devlink-fix-net-namespace-reference-leak-in-reload.patch
+net-mlx5-fw_tracer-return-null-on-create-error.patch
+counter-microchip-tcb-capture-fix-dt-channel-validat.patch
+bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch
+vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch
+vdpa-mlx5-fix-buffer-length-in-create_direct_keys.patch
+hwmon-pmbus_core-use-guard-for-mutex-protection.patch
+hwmon-pmbus-fix-type-confusion-in-notification-logic.patch
+tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch
+bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch
+net-reduce-indent-of-struct-netdev_queue_mgmt_ops-me.patch
+net-add-bare-bone-queue-configs.patch
+net-pass-queue-rx-page-size-from-memory-provider.patch
+eth-bnxt-store-rx-buffer-size-per-queue.patch
+eth-bnxt-support-qcfg-provided-rx-page-size.patch
+bnxt-fix-memory-leak-in-bnxt_queue_mem_alloc-error-c.patch
+xsk-require-at-least-16-bytes-of-tx-metadata.patch
+xsk-pass-tx-metadata-pointer-by-reference.patch
+xsk-clear-metadata-pointer-when-no-timestamp-is-requ.patch
+xsk-validate-launch-time-metadata-size.patch
+xsk-move-xsk_tx_metadata_request-to-xdp_sock_drv.h.patch
+xsk-validate-metadata-when-processing-requests.patch
+udp-fix-potential-use-after-free-in-tunnel-segmentat.patch
+net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch
+vhost-scsi-validate-t10-pi-scatterlist-counts.patch
+vhost-scsi-reject-feature-changes-after-endpoint.patch
+net-openvswitch-check-ethernet-header-length-in-key_.patch
+net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch
+drm-xe-uc-apply-rcs-ccs-yield-policy-to-sr-iov-vfs.patch
+hwmon-nzxt-smart2-check-return-value-of-init_device-.patch
+hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch
+selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch
+net-stmmac-resume-phy-before-hardware-setup-when-ope.patch
+bnge-use-int-for-bnge_fix_rings_count-return-value.patch
+net-mlx5e-fix-bql-reset-on-sq-re-activation.patch
+bnxt_en-move-rss-table-fill-outside-__bnxt_hwrm_vnic.patch
+bnxt_en-determine-and-store-default-rx-ring-in-vnic-.patch
+bnxt_en-refresh-vnic-default-ring-on-queue-restart-i.patch
+bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch
+bnxt_en-fix-ptp-pps-setting-bug.patch
+sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch
+tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch
+netfilter-flowtable-consolidate-xmit-path.patch
+netfilter-nf_flow_table-drop-existing-skb-dst-before.patch
+net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch
+net-prestera-validate-firmware-header-length.patch
+net-remove-warn_on_once-from-sk_mc_loop.patch
+net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch
+net-thunderbolt-tear-down-dma-paths-before-stopping-.patch
+ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch
+bnge-fix-resource-leak-in-bnge_init_nic-error-path.patch
+s390-ism-fix-uaf-of-sba-and-ieq-during-ism_dev_exit.patch
+net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch
+sctp-clear-control-chunk-transport-if-it-is-being-re.patch
+tls-don-t-abort-the-connection-on-signal-interrupted.patch
+watchdog-at91sam9_wdt-prevent-timer-rearm-during-tea.patch
+hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch
+hwmon-ads7828-fix-external-vref-regulator-handling.patch
+hwmon-ltc4282-avoid-overflow-in-maximum-power-calcul.patch
+hwmon-ltc4282-clamp-negative-current-limits.patch
+hwmon-ltc4282-fix-parsing-adi-current-limit-sense-mi.patch
--- /dev/null
+From 96a6f0678c70b43bf0fa845a1f0d2f8ad095406e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jul 2026 20:08:06 -0700
+Subject: tcp: do not change rcv_ssthresh in tcp_measure_rcv_mss()
+
+From: Nathan Gao <zcgao@amazon.com>
+
+[ Upstream commit 0e125ecfe20c077625cf0be8d750d5c3abc0dce9 ]
+
+Commit f5da7c45188e ("tcp: adjust rcvq_space after updating scaling
+ratio") replaced the direct window_clamp update in tcp_measure_rcv_mss()
+with a call to tcp_set_window_clamp(), a helper that implements the
+TCP_WINDOW_CLAMP setsockopt. As a side effect, the helper also shrinks
+rcv_ssthresh via __tcp_adjust_rcv_ssthresh().
+
+As a result, each scaling_ratio decrease detected by
+tcp_measure_rcv_mss() also cuts rcv_ssthresh. Elsewhere in TCP,
+rcv_ssthresh is usually cut under memory pressure and grows via
+tcp_grow_window().
+
+Flows whose segment sizes vary keep scaling_ratio oscillating, which
+leads to an unstable rcv_ssthresh: a dip of rcv_ssthresh only recovers
+via tcp_grow_window(), keeping the advertised window at a relatively
+low level even after the ratio itself has recovered, and can even stall
+the sender.
+
+Observed on a customer's proxy gateway after upgrading from kernel 6.1
+to 6.12: in the worst case, rcv_ssthresh was cut in half by a
+scaling_ratio dip. P99 latency jumped from <10ms on 6.1 to ~100ms on
+6.12, and almost returned to the 6.1 level with this patch applied.
+
+Restore the plain WRITE_ONCE() update of window_clamp, as introduced
+in commit a2cbb1603943 ("tcp: Update window clamping condition"), and
+keep the rcvq_space.space adjustment. Now rcv_ssthresh is decoupled from
+scaling_ratio changes in tcp_measure_rcv_mss().
+
+Fixes: f5da7c45188e ("tcp: adjust rcvq_space after updating scaling ratio")
+Signed-off-by: Nathan Gao <zcgao@amazon.com>
+Link: https://patch.msgid.link/20260725030806.28135-1-zcgao@amazon.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_input.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
+index 8c74fbeb771d5..c1769031a9e93 100644
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -252,7 +252,7 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb)
+ struct tcp_sock *tp = tcp_sk(sk);
+
+ val = tcp_win_from_space(sk, sk->sk_rcvbuf);
+- tcp_set_window_clamp(sk, val);
++ WRITE_ONCE(tp->window_clamp, val);
+
+ if (tp->window_clamp < tp->rcvq_space.space)
+ tp->rcvq_space.space = tp->window_clamp;
+--
+2.53.0
+
--- /dev/null
+From 7e86e9b8110ceababbb04802bcc19451390ca755 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 14:17:38 +0800
+Subject: tcp: fix TFO max_qlen accounting across reuseport migration
+
+From: Jiayuan Chen <jiayuan.chen@linux.dev>
+
+[ Upstream commit a0ab2ba83e35159d81cec830a92e885ecf8139be ]
+
+A listener's TCP_FASTOPEN max_qlen stops being accurate and lets through
+far more pending Fast Open requests than it was configured for.
+
+This only shows up with SO_REUSEPORT listener migration, where closing a
+listener hands its still-pending TFO children over to a surviving one.
+
+fastopenq.qlen is charged in tcp_fastopen_create_child() when the child
+is created and uncharged in reqsk_fastopen_remove() when the handshake
+completes. The uncharge follows rsk_listener of the request the child
+points at, and inet_reqsk_clone() has repointed the child at a new
+request owned by the new listener, so the ++ and the -- land on two
+different sockets. The new listener's qlen drifts negative and its
+limit no longer binds.
+
+Charge the new listener during migration, like reqsk_queue_migrated()
+already does for queue->young and queue->qlen.
+
+Fixes: 54b92e841937 ("tcp: Migrate TCP_ESTABLISHED/TCP_SYN_RECV sockets in accept queues.")
+Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260803061739.134737-1-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/inet_connection_sock.c | 20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
+index 1679bfefa560d..5db36e323e683 100644
+--- a/net/ipv4/inet_connection_sock.c
++++ b/net/ipv4/inet_connection_sock.c
+@@ -964,11 +964,23 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req,
+
+ nreq->rsk_listener = sk;
+
+- /* We need not acquire fastopenq->lock
+- * because the child socket is locked in inet_csk_listen_stop().
+- */
+- if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener)
++ if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener) {
++ struct fastopen_queue *fastopenq;
++
++ /* reqsk_fastopen_remove() will uncharge nreq->rsk_listener,
++ * that is @sk, so charge it here. Unlike the listener
++ * being closed, @sk is live and needs its lock.
++ */
++ fastopenq = &inet_csk(sk)->icsk_accept_queue.fastopenq;
++ spin_lock_bh(&fastopenq->lock);
++ fastopenq->qlen++;
++ spin_unlock_bh(&fastopenq->lock);
++
++ /* We need not acquire fastopenq->lock
++ * because the child socket is locked in inet_csk_listen_stop().
++ */
+ rcu_assign_pointer(tcp_sk(nreq->sk)->fastopen_rsk, nreq);
++ }
+
+ return nreq;
+ }
+--
+2.53.0
+
--- /dev/null
+From b75da59a45af8c4dc2ffcfbe98aa66511fde66c0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 08:22:48 +0200
+Subject: tls: don't abort the connection on signal-interrupted sends
+
+From: Maximilian Immanuel Brandtner <maxbr@linux.ibm.com>
+
+[ Upstream commit af0e5cdd031f4f4a8f6d4160bfbda4f36872b0ed ]
+
+When a signal interrupts a blocking send, tls_tx_records() treats the
+resulting -ERESTARTSYS as a transmission failure and marks the socket
+errored via tls_err_abort() with the raw error code. Later syscalls
+return the kernel-internal errno 512 (ERESTARTSYS) to userspace, as the
+signal it stems from is no longer pending during syscall exit and thus
+never translated.
+
+An interrupted send is not a connection error: the partially sent record
+stays queued and is resent later. Interrupt error codes are therefore
+excluded from the abort in the same way as -EAGAIN.
+
+Fixes: b341ca51d267 ("tls: Fix tls_sw_sendmsg error handling")
+Signed-off-by: Maximilian Immanuel Brandtner <maxbr@linux.ibm.com>
+Link: https://patch.msgid.link/20260805063109.1772314-1-maxbr@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tls/tls_sw.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
+index f19b504efa5d0..0bb710c5fa601 100644
+--- a/net/tls/tls_sw.c
++++ b/net/tls/tls_sw.c
+@@ -458,7 +458,7 @@ int tls_tx_records(struct sock *sk, int flags)
+ }
+
+ tx_err:
+- if (rc < 0 && rc != -EAGAIN)
++ if (rc < 0 && rc != -EAGAIN && rc != -EINTR && rc != -ERESTARTSYS)
+ tls_err_abort(sk, rc);
+
+ return rc;
+--
+2.53.0
+
--- /dev/null
+From 1c1642d941c8de9becfd7650f85cd40847ebee29 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 17:35:54 +0800
+Subject: udp: fix potential use-after-free in tunnel segmentation
+
+From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+
+[ Upstream commit d0f86fb36eb260abd10007b62c9dcc1028e03e61 ]
+
+__skb_udp_tunnel_segment() gets the UDP header before ensuring the
+tunnel header is in the skb head. If the pull reallocates skb->head,
+the saved UDP header pointer is no longer valid.
+
+Get the UDP header after the pull to avoid a potential use-after-free.
+
+Fixes: dbef491ebe7f ("udp: Use uh->len instead of skb->len to compute checksum in segmentation")
+Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+Reviewed-by: Antoine Tenart <atenart@kernel.org>
+Link: https://patch.msgid.link/20260730093554.68127-1-xuanqiang.luo@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/udp_offload.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
+index 589456bd8b5f1..4f7ae02df8d3a 100644
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -178,17 +178,19 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
+ int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
+ bool remcsum, need_csum, offload_csum, gso_partial;
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+- struct udphdr *uh = udp_hdr(skb);
+ u16 mac_offset = skb->mac_header;
+ __be16 protocol = skb->protocol;
+ u16 mac_len = skb->mac_len;
+ int udp_offset, outer_hlen;
++ struct udphdr *uh;
+ __wsum partial;
+ bool need_ipsec;
+
+ if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
+ goto out;
+
++ uh = udp_hdr(skb);
++
+ /* Adjust partial header checksum to negate old length.
+ * We cannot rely on the value contained in uh->len as it is
+ * possible that the actual value exceeds the boundaries of the
+--
+2.53.0
+
--- /dev/null
+From 27b0de378d91ed8119b23b8c4d238ccc68d973a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 6 Jul 2026 16:15:37 +0200
+Subject: vdpa/mlx5: Fix buffer length in create_direct_keys()
+
+From: Christian Borntraeger <borntraeger@linux.ibm.com>
+
+[ Upstream commit 727e1f569855df83579edbd73dcb4a0723543a12 ]
+
+We have seen in our CI the following KASAN message:
+BUG: KASAN: slab-out-of-bounds in cmd_exec+0x550/0xca0 [mlx5_core]
+Read of size 272 at addr 0000000176795020 by task qemu-system-s39/82764
+[...]
+[<000011388ab3a7a0>] cmd_exec+0x550/0xca0 [mlx5_core]
+[<000011388ab3b61c>] mlx5_cmd_exec_cb+0x25c/0x4f0 [mlx5_core]
+[<000011388b21e82e>] mlx5_vdpa_exec_async_cmds+0x22e/0x5e0 [mlx5_vdpa]
+[<000011388b21fd44>] create_direct_keys+0x954/0xef0 [mlx5_vdpa]
+[...]
+The buggy address is located 4128 bytes inside of
+allocated 4384-byte region [0000000176794000, 0000000176795120)
+
+So in essence we read 16 bytes beyond 4384-byte allocation.
+create_direct_keys calculates the pointer and length for in and out
+buffers.
+The size calculation for in includes the entire structure
+size (out + in + mtt[]) but the pointer passed to cmd_exec points only
+to the 'in' field, skipping the 'out' field.
+
+This causes mlx5_copy_to_msg() to read beyond the allocated buffer
+by sizeof(out) bytes when copying command data.
+
+Properly calculate the input size to match the pointer and allocation size.
+
+Fixes: 0071b138d44a ("vdpa/mlx5: Create direct MKEYs in parallel")
+Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
+Tested-by: Dragos Tatulea <dtatulea@nvidia.com>
+Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Message-ID: <20260706141537.3510294-1-borntraeger@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vdpa/mlx5/core/mr.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c
+index 8870a7169267e..2450440dae2e1 100644
+--- a/drivers/vdpa/mlx5/core/mr.c
++++ b/drivers/vdpa/mlx5/core/mr.c
+@@ -234,7 +234,8 @@ static int create_direct_keys(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *
+ cmds[i].out = cmd_mem->out;
+ cmds[i].outlen = sizeof(cmd_mem->out);
+ cmds[i].in = cmd_mem->in;
+- cmds[i].inlen = struct_size(cmd_mem, mtt, mttcount);
++ cmds[i].inlen = struct_size(cmd_mem, mtt, mttcount) -
++ offsetof(struct mlx5_create_mkey_mem, in);
+
+ fill_create_direct_mr(mvdev, dmr, cmd_mem);
+
+--
+2.53.0
+
--- /dev/null
+From a3a430f3c447e06a0c139c2ebe5c66e1dbd71b35 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 26 Jul 2026 22:43:14 +0800
+Subject: vhost-scsi: reject feature changes after endpoint
+
+From: Jia Jia <physicalmtea@gmail.com>
+
+[ Upstream commit 42bc45df5905e2b7dccb72adaf7730f66cfbe03f ]
+
+vhost_scsi_setup_vq_cmds() runs from VHOST_SCSI_SET_ENDPOINT and allocates
+each command's protection scatterlist array (prot_sgl) according to the
+acknowledged VIRTIO_SCSI_F_T10_PI bit. The command pools are not rebuilt
+when VHOST_SET_FEATURES changes that bit later.
+
+Although virtio feature bits must not change after feature negotiation,
+vhost_scsi_set_features() currently accepts such a request after the
+endpoint is active and updates acked_features. Enabling T10-PI after
+endpoint setup therefore leaves prot_sgl NULL while the I/O path follows
+the new feature bit.
+
+For a 129-page protection payload, vhost_scsi_mapal() passes the missing
+first chunk to sg_alloc_table_chained():
+
+ sg_alloc_table_chained(table, 129, first_chunk=NULL,
+ nents_first_chunk=inline_sg_cnt)
+
+sg_pool_index() then hits:
+
+ BUG_ON(nents > SG_CHUNK_SIZE); /* 129 > 128 */
+
+The kernel reported the following call trace and register state:
+
+ Call Trace:
+ <TASK>
+ ? __sg_alloc_table+0x1d8/0x250
+ ? __pfx_vhost_run_work_list+0x10/0x10 [vhost]
+ sg_alloc_table_chained+0x59/0xf0
+ ? __pfx_sg_pool_alloc+0x10/0x10
+ ? vhost_scsi_calc_sgls.constprop.0+0x43/0x60 [vhost_scsi]
+ vhost_scsi_handle_vq+0xf02/0x1700 [vhost_scsi]
+ ? __pfx_vhost_scsi_handle_vq+0x10/0x10 [vhost_scsi]
+ vhost_scsi_handle_kick+0x37/0x50 [vhost_scsi]
+ vhost_run_work_list+0x8e/0xd0 [vhost]
+ vhost_task_fn+0xe1/0x210
+ ret_from_fork+0x348/0x540
+ </TASK>
+
+ RIP: 0010:0x4
+ CR2 = 0x4
+ RSP: 0018:ffffc90000dbf940 EFLAGS: 00010202
+ RAX: ffffffff82396810 RBX: ffff88811dc28b80 RCX: 0000000000000000
+ RDX: 0000000000000000 RSI: 0000000000000820 RDI: 0000000000000081
+
+VHOST_F_LOG_ALL is a vhost-specific runtime feature and remains the only
+exception.
+
+Reject changes to any feature other than VHOST_F_LOG_ALL while the
+endpoint is active. This preserves the existing runtime log toggle while
+preventing feature-dependent command resources and data-path state from
+becoming inconsistent. Userspace must clear the endpoint before changing
+any other negotiated feature and set the endpoint up again afterward.
+
+Fixes: bf2d650391be ("vhost-scsi: Allocate T10 PI structs only when enabled")
+Signed-off-by: Jia Jia <physicalmtea@gmail.com>
+Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Message-ID: <20260726144314.1652934-1-physicalmtea@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vhost/scsi.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
+index 65a57de0080ef..29716ce714554 100644
+--- a/drivers/vhost/scsi.c
++++ b/drivers/vhost/scsi.c
+@@ -2231,6 +2231,7 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
+ {
+ struct vhost_virtqueue *vq;
+ bool is_log, was_log;
++ u64 old_features;
+ int i;
+
+ if (features & ~VHOST_SCSI_FEATURES)
+@@ -2246,6 +2247,14 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
+ if (!vs->dev.nvqs)
+ goto out;
+
++ old_features = vs->vqs[0].vq.acked_features;
++ if (vs->vs_tpg &&
++ ((features ^ old_features) &
++ ~(1ULL << VHOST_F_LOG_ALL))) {
++ mutex_unlock(&vs->dev.mutex);
++ return -EBUSY;
++ }
++
+ is_log = features & (1 << VHOST_F_LOG_ALL);
+ /*
+ * All VQs should have same feature.
+--
+2.53.0
+
--- /dev/null
+From de1ecc4d02139e98f84174a4139e1997337d605c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 16:18:41 +0800
+Subject: vhost-scsi: Validate T10 PI scatterlist counts
+
+From: Linfeng Sun <slf@hdu.edu.cn>
+
+[ Upstream commit d876c493fc4b811941bfeb4c80beb2dfc4bf025e ]
+
+When T10 PI is negotiated, vhost-scsi splits protection bytes from
+the data iterator before mapping the request scatterlists. A malformed
+request can claim protection bytes that cover or exceed the full payload
+length. The former leaves no data bytes to map, while the latter
+underflows exp_data_len before advancing the iterator. Both cases can let
+a zero data SGL count reach sg_alloc_table_chained(), which triggers
+BUG_ON(!nents).
+
+Reject protection lengths that cover or exceed the payload before
+subtracting prot_bytes and advancing the iterator. Also propagate
+negative errors from the protection SGL calculation before calling the
+allocator, matching the data SGL path.
+
+Fixes: bca939d5bcd0 ("vhost-scsi: Dynamically allocate scatterlists")
+Suggested-by: Jia Jia <physicalmtea@gmail.com>
+Signed-off-by: Jia Jia <physicalmtea@gmail.com>
+Assisted-by: OpenAI-Codex:GPT-5
+Signed-off-by: Linfeng Sun <linfeng.sun.dev@gmail.com>
+Message-ID: <20260727081841.923151-1-slf@hdu.edu.cn>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vhost/scsi.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
+index 98e4f68f4e3cb..65a57de0080ef 100644
+--- a/drivers/vhost/scsi.c
++++ b/drivers/vhost/scsi.c
+@@ -971,6 +971,9 @@ vhost_scsi_mapal(struct vhost_scsi *vs, struct vhost_scsi_cmd *cmd,
+ if (prot_bytes) {
+ sgl_count = vhost_scsi_calc_sgls(prot_iter, prot_bytes,
+ VHOST_SCSI_PREALLOC_PROT_SGLS);
++ if (sgl_count < 0)
++ return sgl_count;
++
+ cmd->prot_table.sgl = cmd->prot_sgl;
+ ret = sg_alloc_table_chained(&cmd->prot_table, sgl_count,
+ cmd->prot_table.sgl,
+@@ -1416,6 +1419,11 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
+ * actual data payload length.
+ */
+ if (prot_bytes) {
++ if (prot_bytes >= exp_data_len) {
++ vq_err(vq, "Protection data exceeds payload length\n");
++ goto err;
++ }
++
+ exp_data_len -= prot_bytes;
+ prot_iter = data_iter;
+ iov_iter_truncate(&prot_iter, prot_bytes);
+--
+2.53.0
+
--- /dev/null
+From ac480eb9d1cc42e8a00eb58acd9b0e7df24e0e8c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Jun 2026 15:02:02 -0700
+Subject: vhost/vdpa: reject overflowing PA map page counts on 32-bit
+
+From: Yousef Alhouseen <alhouseenyousef@gmail.com>
+
+[ Upstream commit 0619aaa34c0c2a2dcb07f0e9c8a34e7efb8c4cdf ]
+
+vhost_vdpa_pa_map() adds the IOVA page offset to the user-controlled map
+size before computing the number of pages to pin. On 32-bit systems,
+where unsigned long is narrower than u64, that addition can overflow and
+the code can pin and map fewer pages than the requested IOTLB range.
+
+Reject sizes that overflow the unsigned long page-count calculation.
+
+Fixes: 22af48cf91aa ("vdpa: factor out vhost_vdpa_pa_map() and vhost_vdpa_pa_unmap()")
+Acked-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Message-ID: <CAMuQ4bX-iDvcUOPPY+NLz95tkRJYwWqvzAr=U48uNaub_HZLGw@mail.gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vhost/vdpa.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
+index a6c6c28bf2d9d..4c988f30a55c3 100644
+--- a/drivers/vhost/vdpa.c
++++ b/drivers/vhost/vdpa.c
+@@ -1100,6 +1100,7 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
+ unsigned int gup_flags = FOLL_LONGTERM;
+ unsigned long npages, cur_base, map_pfn, last_pfn = 0;
+ unsigned long lock_limit, sz2pin, nchunks, i;
++ unsigned long page_offset;
+ u64 start = iova;
+ long pinned;
+ int ret = 0;
+@@ -1112,7 +1113,13 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
+ if (perm & VHOST_ACCESS_WO)
+ gup_flags |= FOLL_WRITE;
+
+- npages = PFN_UP(size + (iova & ~PAGE_MASK));
++ page_offset = iova & ~PAGE_MASK;
++ if (size > ULONG_MAX - page_offset) {
++ ret = -EINVAL;
++ goto free;
++ }
++
++ npages = PFN_UP(size + page_offset);
+ if (!npages) {
+ ret = -EINVAL;
+ goto free;
+--
+2.53.0
+
--- /dev/null
+From 91152754adf84a760e52e3146a7b1c425ce9c7d4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 14:06:13 +0800
+Subject: watchdog: at91sam9_wdt: prevent timer rearm during teardown
+
+From: Hongyan Xu <getshell@seu.edu.cn>
+
+[ Upstream commit 8444d66aa6b6e7fe0a26fa1a00a11cb4d0523783 ]
+
+at91_ping() rearms the watchdog timer from its callback. timer_delete()
+neither waits for a running callback nor prevents it from rearming the
+timer, so probe failure or driver removal can leave the timer accessing the
+devm-allocated at91wdt after it has been freed.
+
+Use timer_shutdown_sync() on both teardown paths. It waits for a running
+callback and rejects any attempt by the callback to rearm the timer.
+
+Fixes: 5161b31dc39a ("watchdog: at91sam9_wdt: better watchdog support")
+Signed-off-by: Hongyan Xu <getshell@seu.edu.cn>
+Link: https://lore.kernel.org/r/20260806060613.1830-1-getshell@seu.edu.cn
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/watchdog/at91sam9_wdt.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
+index aba66b8e9d033..80ba04df54adf 100644
+--- a/drivers/watchdog/at91sam9_wdt.c
++++ b/drivers/watchdog/at91sam9_wdt.c
+@@ -242,7 +242,7 @@ static int at91_wdt_init(struct platform_device *pdev, struct at91wdt *wdt)
+ return 0;
+
+ out_stop_timer:
+- timer_delete(&wdt->timer);
++ timer_shutdown_sync(&wdt->timer);
+ return err;
+ }
+
+@@ -378,7 +378,7 @@ static void at91wdt_remove(struct platform_device *pdev)
+ watchdog_unregister_device(&wdt->wdd);
+
+ pr_warn("I quit now, hardware will probably reboot!\n");
+- timer_delete(&wdt->timer);
++ timer_shutdown_sync(&wdt->timer);
+ }
+
+ #if defined(CONFIG_OF)
+--
+2.53.0
+
--- /dev/null
+From e15d0c58114a685cc347911a36b06033976ddfe5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:36:28 +0300
+Subject: watchdog: bd96801_wdt: Fix timeout for enabled WDG
+
+From: Matti Vaittinen <mazziesaccount@gmail.com>
+
+[ Upstream commit 1246aa2b6ccc8944676bd24ff3e37cc56b93b51b ]
+
+When watchdog is enabled at the probe time, the bd96801 driver retrieves
+the timeout configuration from the registers to set-up the heart-beat
+values.
+
+As Sashiko pointed out at
+https://lore.kernel.org/all/20260722085819.495211F000E9@smtp.kernel.org/
+the timeout values are incorrectly computed in driver, resulting wrong
+heartbeat. This leads to devere problems if watchdog was enabled at probe
+time.
+
+According to the data-sheet, the "too fast" ping limit is configured as
+multiple of FASTNG_MIN. Furthermore, the "too slow" ping limit is
+configured as multiples of "too fast" timeout. The FASTNG_MIN is set to
+11, meaning 1.1 mS and "too fast" and "too slow" limits are computed from
+this. Hence, converting the limits to mS should be done by dividing by 10,
+not by dividing by USEC_PER_MSEC.
+
+Fix this by dividing the timeout values with correct scaling factor.
+
+While at it, fix whitespace problem (double empty line).
+
+Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>
+Fixes: 09dad69757b6 ("watchdog: ROHM BD96801 PMIC WDG driver")
+Link: https://lore.kernel.org/r/amxskHmQbi9v-8_l@mva-rohm
+[groeck: Added reference to whitespace change to description]
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/watchdog/bd96801_wdt.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/watchdog/bd96801_wdt.c b/drivers/watchdog/bd96801_wdt.c
+index 12b74fd2bc052..a25b7cf1488b2 100644
+--- a/drivers/watchdog/bd96801_wdt.c
++++ b/drivers/watchdog/bd96801_wdt.c
+@@ -169,7 +169,6 @@ static int bd96801_set_wdt_mode(struct wdtbd96801 *w, unsigned int hw_margin,
+ int fastng, slowng, type, ret, reg, mask;
+ struct device *dev = w->dev;
+
+-
+ if (hw_margin_min * 1000 > FASTNG_MAX_US) {
+ dev_err(dev, "Unsupported fast timeout %u uS [max %u]\n",
+ hw_margin_min * 1000, FASTNG_MAX_US);
+@@ -258,10 +257,10 @@ static int bd96801_set_heartbeat_from_hw(struct wdtbd96801 *w,
+ fast = FASTNG_MIN << sel;
+
+ sel = (val & BD96801_WD_RATIO_MASK) + 1;
+- w->wdt.max_hw_heartbeat_ms = (fast << sel) / USEC_PER_MSEC;
++ w->wdt.max_hw_heartbeat_ms = (fast << sel) / 10;
+
+ if ((conf_reg & BD96801_WD_TYPE_MASK) == BD96801_WD_TYPE_WIN)
+- w->wdt.min_hw_heartbeat_ms = fast / USEC_PER_MSEC;
++ w->wdt.min_hw_heartbeat_ms = fast / 10;
+
+ return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From dfde8f3107af91bc697d1bb1ad7ffc7e3fd31309 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 19 Jul 2026 23:11:24 +0800
+Subject: xfs: handle NULL b_addr in xfs_buf_free
+
+From: Yun Zhou <yun.zhou@windriver.com>
+
+[ Upstream commit d852729c5f4f830fbe7413df032e29459b3daf83 ]
+
+When xfs_buf_alloc_backing_mem() fails, xfs_buf_free() is called with
+bp->b_addr still NULL. The code falls through to the folio_put path
+which calls virt_to_folio(NULL), dereferencing an invalid address and
+causing a kernel crash.
+
+ Call Trace:
+ xfs_buf_free+0x25f/0x510
+ xfs_buf_alloc+0xc98/0x19b0
+ xfs_buf_find_insert+0x55/0x14d0
+ xfs_buf_get_map+0x122b/0x17c0
+ xfbtree_init_leaf_block+0x11c/0x4a0
+ xfbtree_init+0x1bb/0x460
+ xrep_rmap_setup_scan+0x100/0x1f0
+ xrep_rmapbt+0x41/0xc0
+
+Fix this by skipping folio_put() when bp->b_addr is NULL.
+
+Fixes: 5076a6040ca1 ("xfs: support in-memory buffer cache targets")
+Reported-by: syzbot+94c22d92f72f5a235b7d@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=94c22d92f72f5a235b7d
+Signed-off-by: Yun Zhou <yun.zhou@windriver.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Carlos Maiolino <cem@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/xfs/xfs_buf.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
+index 1ca95ef46a73d..441631c736c1c 100644
+--- a/fs/xfs/xfs_buf.c
++++ b/fs/xfs/xfs_buf.c
+@@ -117,7 +117,7 @@ xfs_buf_free(
+ vfree(bp->b_addr);
+ else if (bp->b_flags & _XBF_KMEM)
+ kfree(bp->b_addr);
+- else
++ else if (bp->b_addr)
+ folio_put(virt_to_folio(bp->b_addr));
+
+ call_rcu(&bp->b_rcu, xfs_buf_free_callback);
+--
+2.53.0
+
--- /dev/null
+From a41dd9dbb3f50c2e46cd72c66491ba36c3179b14 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 09:19:56 -0700
+Subject: xsk: clear metadata pointer when no timestamp is requested
+
+From: Stanislav Fomichev <sdf.kernel@gmail.com>
+
+[ Upstream commit 9f60a67df8d3c862503bee62bada8e7089cba438 ]
+
+User space can change metadata flags after request processing. Rereading
+them during completion can therefore make the kernel write a timestamp
+that was not requested when the packet was submitted.
+
+Clear the metadata pointer during request processing unless timestamp
+completion is requested. Completion handling can then use the pointer
+itself instead of rereading the flags.
+
+On the mlx5 multi-packet WQE path metadata is evaluated per batch:
+xsk_tx_metadata_request() runs only for the descriptor that starts a
+session, just like the checksum offload that is applied once through the
+shared WQE. Only that descriptor's pointer is reset, so completion
+handling can record a timestamp for the other descriptors of the session
+regardless of their own XDP_TXMD_FLAGS_TIMESTAMP bit. The write stays
+inside the metadata area; the single-WQE, other zero-copy, and generic
+paths reset the pointer per descriptor and are unaffected.
+
+Fixes: ca4419f15abd ("xsk: Add launch time hardware offload support to XDP Tx metadata")
+Cc: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
+Link: https://patch.msgid.link/20260727161959.885642-4-sdf@fomichev.me
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/xdp_sock.h | 14 ++++++++++----
+ net/xdp/xsk.c | 2 ++
+ 2 files changed, 12 insertions(+), 4 deletions(-)
+
+diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h
+index b93d6bd368d00..e14e575178940 100644
+--- a/include/net/xdp_sock.h
++++ b/include/net/xdp_sock.h
+@@ -140,13 +140,16 @@ void __xsk_map_flush(struct list_head *flush_list);
+ static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta,
+ struct xsk_tx_metadata_compl *compl)
+ {
++ compl->tx_timestamp = NULL;
++
+ if (!meta)
+ return;
+
+- if (meta->flags & XDP_TXMD_FLAGS_TIMESTAMP)
+- compl->tx_timestamp = &meta->completion.tx_timestamp;
+- else
+- compl->tx_timestamp = NULL;
++ /* we can only arrive here if the completion timestamp has been
++ * requested via XDP_TXMD_FLAGS_TIMESTAMP, see xsk_tx_metadata_request
++ */
++
++ compl->tx_timestamp = &meta->completion.tx_timestamp;
+ }
+
+ /**
+@@ -181,6 +184,9 @@ static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
+ if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM)
+ ops->tmo_request_checksum(meta->request.csum_start,
+ meta->request.csum_offset, priv);
++
++ if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
++ *pmeta = NULL;
+ }
+
+ /**
+diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
+index 70c57c5d8e1da..3b82fb850bee3 100644
+--- a/net/xdp/xsk.c
++++ b/net/xdp/xsk.c
+@@ -730,6 +730,8 @@ static int xsk_skb_metadata(struct sk_buff *skb, void *buffer,
+
+ if (meta->flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
+ skb->skb_mstamp_ns = meta->request.launch_time;
++ if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
++ meta = NULL;
+ xsk_tx_metadata_to_compl(meta, &skb_shinfo(skb)->xsk_meta);
+
+ return 0;
+--
+2.53.0
+
--- /dev/null
+From abcfa6d57a0bacd1d65dd67279105ab9cae86a0d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 09:19:58 -0700
+Subject: xsk: move xsk_tx_metadata_request() to xdp_sock_drv.h
+
+From: Stanislav Fomichev <sdf.kernel@gmail.com>
+
+[ Upstream commit ddd0d6c5bfe2fef7c7cf31f62265f29b7b9eb9ef ]
+
+xsk_tx_metadata_request() must validate metadata with
+xsk_buff_valid_tx_metadata(), which is defined in xdp_sock_drv.h. Move the
+helper there before adding that dependency. All callers already include
+the destination header, so this has no functional effect.
+
+Fixes: ca4419f15abd ("xsk: Add launch time hardware offload support to XDP Tx metadata")
+Cc: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
+Link: https://patch.msgid.link/20260727161959.885642-6-sdf@fomichev.me
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/xdp_sock.h | 43 --------------------------------------
+ include/net/xdp_sock_drv.h | 43 ++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 43 insertions(+), 43 deletions(-)
+
+diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h
+index e14e575178940..8bf17ba6c3bd7 100644
+--- a/include/net/xdp_sock.h
++++ b/include/net/xdp_sock.h
+@@ -152,43 +152,6 @@ static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta,
+ compl->tx_timestamp = &meta->completion.tx_timestamp;
+ }
+
+-/**
+- * xsk_tx_metadata_request - Evaluate AF_XDP TX metadata at submission
+- * and call appropriate xsk_tx_metadata_ops operation.
+- * @pmeta: pointer to pointer to AF_XDP metadata area
+- * @ops: pointer to struct xsk_tx_metadata_ops
+- * @priv: pointer to driver-private aread
+- *
+- * This function should be called by the networking device when
+- * it prepares AF_XDP egress packet.
+- */
+-static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
+- const struct xsk_tx_metadata_ops *ops,
+- void *priv)
+-{
+- const struct xsk_tx_metadata *meta = *pmeta;
+-
+- if (!meta)
+- return;
+-
+- if (ops->tmo_request_launch_time)
+- if (meta->flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
+- ops->tmo_request_launch_time(meta->request.launch_time,
+- priv);
+-
+- if (ops->tmo_request_timestamp)
+- if (meta->flags & XDP_TXMD_FLAGS_TIMESTAMP)
+- ops->tmo_request_timestamp(priv);
+-
+- if (ops->tmo_request_checksum)
+- if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM)
+- ops->tmo_request_checksum(meta->request.csum_start,
+- meta->request.csum_offset, priv);
+-
+- if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
+- *pmeta = NULL;
+-}
+-
+ /**
+ * xsk_tx_metadata_complete - Evaluate AF_XDP TX metadata at completion
+ * and call appropriate xsk_tx_metadata_ops operation.
+@@ -232,12 +195,6 @@ static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta,
+ {
+ }
+
+-static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
+- const struct xsk_tx_metadata_ops *ops,
+- void *priv)
+-{
+-}
+-
+ static inline void xsk_tx_metadata_complete(struct xsk_tx_metadata_compl *compl,
+ const struct xsk_tx_metadata_ops *ops,
+ void *priv)
+diff --git a/include/net/xdp_sock_drv.h b/include/net/xdp_sock_drv.h
+index ce8315f049684..6d4f65b0ed53a 100644
+--- a/include/net/xdp_sock_drv.h
++++ b/include/net/xdp_sock_drv.h
+@@ -267,6 +267,43 @@ xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool,
+ return !(*flags & ~XDP_TXMD_FLAGS_VALID);
+ }
+
++/**
++ * xsk_tx_metadata_request - Evaluate AF_XDP TX metadata at submission
++ * and call appropriate xsk_tx_metadata_ops operation.
++ * @pmeta: pointer to pointer to AF_XDP metadata area
++ * @ops: pointer to struct xsk_tx_metadata_ops
++ * @priv: pointer to driver-private aread
++ *
++ * This function should be called by the networking device when
++ * it prepares AF_XDP egress packet.
++ */
++static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
++ const struct xsk_tx_metadata_ops *ops,
++ void *priv)
++{
++ const struct xsk_tx_metadata *meta = *pmeta;
++
++ if (!meta)
++ return;
++
++ if (ops->tmo_request_launch_time)
++ if (meta->flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
++ ops->tmo_request_launch_time(meta->request.launch_time,
++ priv);
++
++ if (ops->tmo_request_timestamp)
++ if (meta->flags & XDP_TXMD_FLAGS_TIMESTAMP)
++ ops->tmo_request_timestamp(priv);
++
++ if (ops->tmo_request_checksum)
++ if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM)
++ ops->tmo_request_checksum(meta->request.csum_start,
++ meta->request.csum_offset, priv);
++
++ if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
++ *pmeta = NULL;
++}
++
+ static inline struct xsk_tx_metadata *
+ __xsk_buff_get_metadata(const struct xsk_buff_pool *pool, void *data)
+ {
+@@ -479,6 +516,12 @@ xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool,
+ return false;
+ }
+
++static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
++ const struct xsk_tx_metadata_ops *ops,
++ void *priv)
++{
++}
++
+ static inline struct xsk_tx_metadata *
+ __xsk_buff_get_metadata(const struct xsk_buff_pool *pool, void *data)
+ {
+--
+2.53.0
+
--- /dev/null
+From 4ef0c56635e67b82407fc88eb2f91af4381ae332 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 09:19:55 -0700
+Subject: xsk: pass TX metadata pointer by reference
+
+From: Stanislav Fomichev <sdf.kernel@gmail.com>
+
+[ Upstream commit 19366db6dfccac9b0867a151678cd7b89fb8fd99 ]
+
+Completion handling needs to know whether a timestamp was requested when
+the metadata was processed. Let xsk_tx_metadata_request() update the
+caller's metadata pointer so that decision can be carried forward without
+rereading user-controlled flags.
+
+This only changes the interface; behavior remains unchanged.
+
+Fixes: ca4419f15abd ("xsk: Add launch time hardware offload support to XDP Tx metadata")
+Cc: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
+Link: https://patch.msgid.link/20260727161959.885642-3-sdf@fomichev.me
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/igc/igc_main.c | 2 +-
+ drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 +-
+ drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c | 14 +++++++++-----
+ drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h | 4 ++--
+ .../net/ethernet/mellanox/mlx5/core/en/xsk/tx.c | 2 +-
+ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +-
+ include/net/libeth/xsk.h | 2 +-
+ include/net/xdp_sock.h | 8 +++++---
+ 8 files changed, 21 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
+index 4ca242ebf3e34..f69523e35ac10 100644
+--- a/drivers/net/ethernet/intel/igc/igc_main.c
++++ b/drivers/net/ethernet/intel/igc/igc_main.c
+@@ -3082,7 +3082,7 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring)
+ meta_req.tx_buffer = bi;
+ meta_req.meta = meta;
+ meta_req.used_desc = 0;
+- xsk_tx_metadata_request(meta, &igc_xsk_tx_metadata_ops,
++ xsk_tx_metadata_request(&meta, &igc_xsk_tx_metadata_ops,
+ &meta_req);
+
+ /* xsk_tx_metadata_request() may have updated next_to_use */
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
+index 3d8276a0692fc..91653b69328ee 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
+@@ -477,7 +477,7 @@ typedef int (*mlx5e_fp_xmit_xdp_frame_check)(struct mlx5e_xdpsq *);
+ typedef bool (*mlx5e_fp_xmit_xdp_frame)(struct mlx5e_xdpsq *,
+ struct mlx5e_xmit_data *,
+ int,
+- struct xsk_tx_metadata *);
++ struct xsk_tx_metadata **);
+
+ struct mlx5e_xdpsq {
+ /* data path */
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+index 5322964214b22..e467a7b067c7a 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+@@ -451,11 +451,11 @@ INDIRECT_CALLABLE_SCOPE int mlx5e_xmit_xdp_frame_check_mpwqe(struct mlx5e_xdpsq
+
+ INDIRECT_CALLABLE_SCOPE bool
+ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
+- int check_result, struct xsk_tx_metadata *meta);
++ int check_result, struct xsk_tx_metadata **meta);
+
+ INDIRECT_CALLABLE_SCOPE bool
+ mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
+- int check_result, struct xsk_tx_metadata *meta)
++ int check_result, struct xsk_tx_metadata **meta)
+ {
+ struct mlx5e_tx_mpwqe *session = &sq->mpwqe;
+ struct mlx5e_xdpsq_stats *stats = sq->stats;
+@@ -503,7 +503,10 @@ mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptx
+ * and it's safe to complete it at any time.
+ */
+ mlx5e_xdp_mpwqe_session_start(sq);
+- xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, &session->wqe->eth);
++ if (meta)
++ xsk_tx_metadata_request(meta,
++ &mlx5e_xsk_tx_metadata_ops,
++ &session->wqe->eth);
+ }
+
+ mlx5e_xdp_mpwqe_add_dseg(sq, p, stats);
+@@ -534,7 +537,7 @@ INDIRECT_CALLABLE_SCOPE int mlx5e_xmit_xdp_frame_check(struct mlx5e_xdpsq *sq)
+
+ INDIRECT_CALLABLE_SCOPE bool
+ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
+- int check_result, struct xsk_tx_metadata *meta)
++ int check_result, struct xsk_tx_metadata **meta)
+ {
+ struct mlx5e_xmit_data_frags *xdptxdf =
+ container_of(xdptxd, struct mlx5e_xmit_data_frags, xd);
+@@ -648,7 +651,8 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
+
+ sq->pc += num_wqebbs;
+
+- xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, eseg);
++ if (meta)
++ xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, eseg);
+
+ sq->doorbell_cseg = cseg;
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
+index 46ab0a9e8cddb..1a9eb77981cc3 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
+@@ -113,11 +113,11 @@ extern const struct xsk_tx_metadata_ops mlx5e_xsk_tx_metadata_ops;
+ INDIRECT_CALLABLE_DECLARE(bool mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq,
+ struct mlx5e_xmit_data *xdptxd,
+ int check_result,
+- struct xsk_tx_metadata *meta));
++ struct xsk_tx_metadata **meta));
+ INDIRECT_CALLABLE_DECLARE(bool mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq,
+ struct mlx5e_xmit_data *xdptxd,
+ int check_result,
+- struct xsk_tx_metadata *meta));
++ struct xsk_tx_metadata **meta));
+ INDIRECT_CALLABLE_DECLARE(int mlx5e_xmit_xdp_frame_check_mpwqe(struct mlx5e_xdpsq *sq));
+ INDIRECT_CALLABLE_DECLARE(int mlx5e_xmit_xdp_frame_check(struct mlx5e_xdpsq *sq));
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
+index a59199ed590da..827538d92ac23 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
+@@ -103,7 +103,7 @@ bool mlx5e_xsk_tx(struct mlx5e_xdpsq *sq, unsigned int budget)
+
+ ret = INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe,
+ mlx5e_xmit_xdp_frame, sq, &xdptxd,
+- check_result, meta);
++ check_result, &meta);
+ if (unlikely(!ret)) {
+ if (sq->mpwqe.wqe)
+ mlx5e_xdp_mpwqe_complete(sq);
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index 3be0b79532496..3380ce960de24 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -2574,7 +2574,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
+ meta_req.set_ic = &set_ic;
+ meta_req.tbs = tx_q->tbs;
+ meta_req.edesc = &tx_q->dma_entx[entry];
+- xsk_tx_metadata_request(meta, &stmmac_xsk_tx_metadata_ops,
++ xsk_tx_metadata_request(&meta, &stmmac_xsk_tx_metadata_ops,
+ &meta_req);
+ if (set_ic) {
+ tx_q->tx_count_frames = 0;
+diff --git a/include/net/libeth/xsk.h b/include/net/libeth/xsk.h
+index 481a7b28e6f24..1a55daa32cf16 100644
+--- a/include/net/libeth/xsk.h
++++ b/include/net/libeth/xsk.h
+@@ -205,7 +205,7 @@ __libeth_xsk_xmit_fill_buf_md(const struct xdp_desc *xdesc,
+ BUILD_BUG_ON(!__builtin_constant_p(tmo == libeth_xsktmo));
+ tmo = tmo == libeth_xsktmo ? &__libeth_xsktmo : tmo;
+
+- xsk_tx_metadata_request(ctx.meta, tmo, &desc);
++ xsk_tx_metadata_request(&ctx.meta, tmo, &desc);
+
+ return desc;
+ }
+diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h
+index 8a0967af8f0c4..b93d6bd368d00 100644
+--- a/include/net/xdp_sock.h
++++ b/include/net/xdp_sock.h
+@@ -152,17 +152,19 @@ static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta,
+ /**
+ * xsk_tx_metadata_request - Evaluate AF_XDP TX metadata at submission
+ * and call appropriate xsk_tx_metadata_ops operation.
+- * @meta: pointer to AF_XDP metadata area
++ * @pmeta: pointer to pointer to AF_XDP metadata area
+ * @ops: pointer to struct xsk_tx_metadata_ops
+ * @priv: pointer to driver-private aread
+ *
+ * This function should be called by the networking device when
+ * it prepares AF_XDP egress packet.
+ */
+-static inline void xsk_tx_metadata_request(const struct xsk_tx_metadata *meta,
++static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
+ const struct xsk_tx_metadata_ops *ops,
+ void *priv)
+ {
++ const struct xsk_tx_metadata *meta = *pmeta;
++
+ if (!meta)
+ return;
+
+@@ -224,7 +226,7 @@ static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta,
+ {
+ }
+
+-static inline void xsk_tx_metadata_request(struct xsk_tx_metadata *meta,
++static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
+ const struct xsk_tx_metadata_ops *ops,
+ void *priv)
+ {
+--
+2.53.0
+
--- /dev/null
+From 2a16becdb05a95ddae2dd899f162164424231361 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 09:19:54 -0700
+Subject: xsk: require at least 16 bytes of TX metadata
+
+From: Stanislav Fomichev <sdf.kernel@gmail.com>
+
+[ Upstream commit 1bb30b181d9f0484e141f8411e15ed906d5c6780 ]
+
+AF_XDP accepts a TX metadata length as small as eight bytes, but every
+supported request needs the flags plus at least one eight-byte request
+field. Such short metadata also lets the kernel read beyond the registered
+area.
+
+Require 16 bytes rather than sizeof(struct xsk_tx_metadata) to preserve
+compatibility with applications that do not use launch-time metadata.
+
+Fixes: 341ac980eab9 ("xsk: Support tx_metadata_len")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Reported-by: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Link: https://lore.kernel.org/netdev/20260720155210.34229-1-blbllhy@gmail.com/
+Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
+Link: https://patch.msgid.link/20260727161959.885642-2-sdf@fomichev.me
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/xdp/xdp_umem.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c
+index 9ec7bd948acc7..81ffda5501078 100644
+--- a/net/xdp/xdp_umem.c
++++ b/net/xdp/xdp_umem.c
+@@ -209,6 +209,8 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
+ if (mr->flags & XDP_UMEM_TX_METADATA_LEN) {
+ if (mr->tx_metadata_len >= 256 || mr->tx_metadata_len % 8)
+ return -EINVAL;
++ if (mr->tx_metadata_len < 16)
++ return -EINVAL;
+ umem->tx_metadata_len = mr->tx_metadata_len;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From cfd011a88a3249cdfe4769db8f037c6d218dddb0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 09:19:57 -0700
+Subject: xsk: validate launch-time metadata size
+
+From: Stanislav Fomichev <sdf.kernel@gmail.com>
+
+[ Upstream commit 439ce2dddf3d22129b9113a7881637256a35e936 ]
+
+Launch-time metadata extends beyond the first 16 bytes of struct
+xsk_tx_metadata. Reject the request when the registered metadata area does
+not contain the complete field.
+
+Snapshot the validated flags for the generic transmit path and use that
+snapshot for request and completion processing, avoiding inconsistent
+decisions if user space changes the flags concurrently.
+
+Note that only xsk_skb_metadata is properly using the flags,
+__xsk_buff_get_metadata ignores them. Next commits address that.
+
+Fixes: ca4419f15abd ("xsk: Add launch time hardware offload support to XDP Tx metadata")
+Cc: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
+Link: https://patch.msgid.link/20260727161959.885642-5-sdf@fomichev.me
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/xdp_sock_drv.h | 17 +++++++++++++----
+ net/xdp/xsk.c | 11 ++++++-----
+ 2 files changed, 19 insertions(+), 9 deletions(-)
+
+diff --git a/include/net/xdp_sock_drv.h b/include/net/xdp_sock_drv.h
+index dd1d3a6e1b780..ce8315f049684 100644
+--- a/include/net/xdp_sock_drv.h
++++ b/include/net/xdp_sock_drv.h
+@@ -256,21 +256,28 @@ xsk_buff_raw_get_ctx(const struct xsk_buff_pool *pool, u64 addr)
+ 0)
+
+ static inline bool
+-xsk_buff_valid_tx_metadata(const struct xsk_tx_metadata *meta)
++xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool,
++ const struct xsk_tx_metadata *meta, u64 *flags)
+ {
+- return !(meta->flags & ~XDP_TXMD_FLAGS_VALID);
++ *flags = READ_ONCE(meta->flags);
++ if (*flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
++ if (pool->tx_metadata_len <
++ offsetofend(struct xsk_tx_metadata, request.launch_time))
++ return false;
++ return !(*flags & ~XDP_TXMD_FLAGS_VALID);
+ }
+
+ static inline struct xsk_tx_metadata *
+ __xsk_buff_get_metadata(const struct xsk_buff_pool *pool, void *data)
+ {
+ struct xsk_tx_metadata *meta;
++ u64 flags;
+
+ if (!pool->tx_metadata_len)
+ return NULL;
+
+ meta = data - pool->tx_metadata_len;
+- if (unlikely(!xsk_buff_valid_tx_metadata(meta)))
++ if (unlikely(!xsk_buff_valid_tx_metadata(pool, meta, &flags)))
+ return NULL; /* no way to signal the error to the user */
+
+ return meta;
+@@ -465,7 +472,9 @@ xsk_buff_raw_get_ctx(const struct xsk_buff_pool *pool, u64 addr)
+ return (struct xdp_desc_ctx){ };
+ }
+
+-static inline bool xsk_buff_valid_tx_metadata(struct xsk_tx_metadata *meta)
++static inline bool
++xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool,
++ const struct xsk_tx_metadata *meta, u64 *flags)
+ {
+ return false;
+ }
+diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
+index 3b82fb850bee3..ff93fd7ac6317 100644
+--- a/net/xdp/xsk.c
++++ b/net/xdp/xsk.c
+@@ -699,15 +699,16 @@ static int xsk_skb_metadata(struct sk_buff *skb, void *buffer,
+ {
+ struct xsk_tx_metadata *meta = NULL;
+ u16 csum_start, csum_offset;
++ u64 flags;
+
+ if (unlikely(pool->tx_metadata_len == 0))
+ return -EINVAL;
+
+ meta = buffer - pool->tx_metadata_len;
+- if (unlikely(!xsk_buff_valid_tx_metadata(meta)))
++ if (unlikely(!xsk_buff_valid_tx_metadata(pool, meta, &flags)))
+ return -EINVAL;
+
+- if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM) {
++ if (flags & XDP_TXMD_FLAGS_CHECKSUM) {
+ csum_start = READ_ONCE(meta->request.csum_start);
+ csum_offset = READ_ONCE(meta->request.csum_offset);
+
+@@ -728,9 +729,9 @@ static int xsk_skb_metadata(struct sk_buff *skb, void *buffer,
+ }
+ }
+
+- if (meta->flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
+- skb->skb_mstamp_ns = meta->request.launch_time;
+- if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
++ if (flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
++ skb->skb_mstamp_ns = READ_ONCE(meta->request.launch_time);
++ if (!(flags & XDP_TXMD_FLAGS_TIMESTAMP))
+ meta = NULL;
+ xsk_tx_metadata_to_compl(meta, &skb_shinfo(skb)->xsk_meta);
+
+--
+2.53.0
+
--- /dev/null
+From 5afc7703d0517d79788630ecac877e73a2eed699 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 09:19:59 -0700
+Subject: xsk: validate metadata when processing requests
+
+From: Stanislav Fomichev <sdf.kernel@gmail.com>
+
+[ Upstream commit 849b1664dbda1cf6c63e0fd4f9dec23782b8c851 ]
+
+The zero-copy path validates TX metadata while obtaining the descriptor
+context, then reads it again later when preparing the hardware request.
+User space can change the metadata between those operations and bypass the
+original validation.
+
+Validate the metadata in xsk_tx_metadata_request() and use the resulting
+flags snapshot for every feature check. Read request fields once so all
+zero-copy drivers process only values observed after successful
+validation.
+
+Fixes: ca4419f15abd ("xsk: Add launch time hardware offload support to XDP Tx metadata")
+Cc: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
+Link: https://patch.msgid.link/20260727161959.885642-7-sdf@fomichev.me
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/igc/igc_main.c | 2 +-
+ .../net/ethernet/mellanox/mlx5/core/en/xdp.c | 5 +-
+ .../net/ethernet/stmicro/stmmac/stmmac_main.c | 4 +-
+ include/net/libeth/xsk.h | 2 +-
+ include/net/xdp_sock_drv.h | 51 ++++++++++---------
+ net/xdp/xsk_buff_pool.c | 6 +--
+ 6 files changed, 37 insertions(+), 33 deletions(-)
+
+diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
+index f69523e35ac10..99a414440bcaa 100644
+--- a/drivers/net/ethernet/intel/igc/igc_main.c
++++ b/drivers/net/ethernet/intel/igc/igc_main.c
+@@ -3082,7 +3082,7 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring)
+ meta_req.tx_buffer = bi;
+ meta_req.meta = meta;
+ meta_req.used_desc = 0;
+- xsk_tx_metadata_request(&meta, &igc_xsk_tx_metadata_ops,
++ xsk_tx_metadata_request(pool, &meta, &igc_xsk_tx_metadata_ops,
+ &meta_req);
+
+ /* xsk_tx_metadata_request() may have updated next_to_use */
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+index e467a7b067c7a..2f52e04b28de2 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+@@ -504,7 +504,7 @@ mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptx
+ */
+ mlx5e_xdp_mpwqe_session_start(sq);
+ if (meta)
+- xsk_tx_metadata_request(meta,
++ xsk_tx_metadata_request(sq->xsk_pool, meta,
+ &mlx5e_xsk_tx_metadata_ops,
+ &session->wqe->eth);
+ }
+@@ -652,7 +652,8 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
+ sq->pc += num_wqebbs;
+
+ if (meta)
+- xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, eseg);
++ xsk_tx_metadata_request(sq->xsk_pool, meta,
++ &mlx5e_xsk_tx_metadata_ops, eseg);
+
+ sq->doorbell_cseg = cseg;
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index 3380ce960de24..bca81ed28e073 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -2574,8 +2574,8 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
+ meta_req.set_ic = &set_ic;
+ meta_req.tbs = tx_q->tbs;
+ meta_req.edesc = &tx_q->dma_entx[entry];
+- xsk_tx_metadata_request(&meta, &stmmac_xsk_tx_metadata_ops,
+- &meta_req);
++ xsk_tx_metadata_request(pool, &meta,
++ &stmmac_xsk_tx_metadata_ops, &meta_req);
+ if (set_ic) {
+ tx_q->tx_count_frames = 0;
+ stmmac_set_tx_ic(priv, tx_desc);
+diff --git a/include/net/libeth/xsk.h b/include/net/libeth/xsk.h
+index 1a55daa32cf16..23eb240d5ba72 100644
+--- a/include/net/libeth/xsk.h
++++ b/include/net/libeth/xsk.h
+@@ -205,7 +205,7 @@ __libeth_xsk_xmit_fill_buf_md(const struct xdp_desc *xdesc,
+ BUILD_BUG_ON(!__builtin_constant_p(tmo == libeth_xsktmo));
+ tmo = tmo == libeth_xsktmo ? &__libeth_xsktmo : tmo;
+
+- xsk_tx_metadata_request(&ctx.meta, tmo, &desc);
++ xsk_tx_metadata_request(sq->pool, &ctx.meta, tmo, &desc);
+
+ return desc;
+ }
+diff --git a/include/net/xdp_sock_drv.h b/include/net/xdp_sock_drv.h
+index 6d4f65b0ed53a..d74ca548d4d6a 100644
+--- a/include/net/xdp_sock_drv.h
++++ b/include/net/xdp_sock_drv.h
+@@ -241,7 +241,7 @@ static inline void *xsk_buff_raw_get_data(struct xsk_buff_pool *pool, u64 addr)
+ * details.
+ *
+ * Return: new &xdp_desc_ctx struct containing desc's DMA address and metadata
+- * pointer, if it is present and valid (initialized to %NULL otherwise).
++ * pointer, if it is present (initialized to %NULL otherwise).
+ */
+ static inline struct xdp_desc_ctx
+ xsk_buff_raw_get_ctx(const struct xsk_buff_pool *pool, u64 addr)
+@@ -270,54 +270,56 @@ xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool,
+ /**
+ * xsk_tx_metadata_request - Evaluate AF_XDP TX metadata at submission
+ * and call appropriate xsk_tx_metadata_ops operation.
++ * @pool: pointer to AF_XDP buffer pool, used to validate the metadata
+ * @pmeta: pointer to pointer to AF_XDP metadata area
+ * @ops: pointer to struct xsk_tx_metadata_ops
+- * @priv: pointer to driver-private aread
++ * @priv: pointer to driver-private area
+ *
+ * This function should be called by the networking device when
+ * it prepares AF_XDP egress packet.
+ */
+-static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
+- const struct xsk_tx_metadata_ops *ops,
+- void *priv)
++static inline void
++xsk_tx_metadata_request(const struct xsk_buff_pool *pool,
++ struct xsk_tx_metadata **pmeta,
++ const struct xsk_tx_metadata_ops *ops, void *priv)
+ {
+ const struct xsk_tx_metadata *meta = *pmeta;
++ u64 flags;
+
+ if (!meta)
+ return;
+
++ if (unlikely(!xsk_buff_valid_tx_metadata(pool, meta, &flags))) {
++ *pmeta = NULL;
++ return; /* no way to signal the error to the user */
++ }
++
+ if (ops->tmo_request_launch_time)
+- if (meta->flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
+- ops->tmo_request_launch_time(meta->request.launch_time,
+- priv);
++ if (flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
++ ops->tmo_request_launch_time(
++ READ_ONCE(meta->request.launch_time), priv);
+
+ if (ops->tmo_request_timestamp)
+- if (meta->flags & XDP_TXMD_FLAGS_TIMESTAMP)
++ if (flags & XDP_TXMD_FLAGS_TIMESTAMP)
+ ops->tmo_request_timestamp(priv);
+
+ if (ops->tmo_request_checksum)
+- if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM)
+- ops->tmo_request_checksum(meta->request.csum_start,
+- meta->request.csum_offset, priv);
++ if (flags & XDP_TXMD_FLAGS_CHECKSUM)
++ ops->tmo_request_checksum(
++ READ_ONCE(meta->request.csum_start),
++ READ_ONCE(meta->request.csum_offset), priv);
+
+- if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
++ if (!(flags & XDP_TXMD_FLAGS_TIMESTAMP))
+ *pmeta = NULL;
+ }
+
+ static inline struct xsk_tx_metadata *
+ __xsk_buff_get_metadata(const struct xsk_buff_pool *pool, void *data)
+ {
+- struct xsk_tx_metadata *meta;
+- u64 flags;
+-
+ if (!pool->tx_metadata_len)
+ return NULL;
+
+- meta = data - pool->tx_metadata_len;
+- if (unlikely(!xsk_buff_valid_tx_metadata(pool, meta, &flags)))
+- return NULL; /* no way to signal the error to the user */
+-
+- return meta;
++ return data - pool->tx_metadata_len;
+ }
+
+ static inline struct xsk_tx_metadata *
+@@ -516,9 +518,10 @@ xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool,
+ return false;
+ }
+
+-static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
+- const struct xsk_tx_metadata_ops *ops,
+- void *priv)
++static inline void
++xsk_tx_metadata_request(const struct xsk_buff_pool *pool,
++ struct xsk_tx_metadata **pmeta,
++ const struct xsk_tx_metadata_ops *ops, void *priv)
+ {
+ }
+
+diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c
+index c9688735b643c..772fe1838cfb3 100644
+--- a/net/xdp/xsk_buff_pool.c
++++ b/net/xdp/xsk_buff_pool.c
+@@ -769,11 +769,11 @@ EXPORT_SYMBOL(xp_raw_get_dma);
+ * @addr: desc address (from userspace)
+ *
+ * Helper for getting desc's DMA address and metadata pointer, if present.
+- * Saves one call on hotpath, double calculation of the actual address,
+- * and inline checks for metadata presence and sanity.
++ * Saves one call on hotpath and double calculation of the actual address.
++ * Metadata is validated later by xsk_tx_metadata_request().
+ *
+ * Return: new &xdp_desc_ctx struct containing desc's DMA address and metadata
+- * pointer, if it is present and valid (initialized to %NULL otherwise).
++ * pointer, if it is present (initialized to %NULL otherwise).
+ */
+ struct xdp_desc_ctx xp_raw_get_ctx(const struct xsk_buff_pool *pool, u64 addr)
+ {
+--
+2.53.0
+
--- /dev/null
+From 4c5e419746faf443d57a8f7d942011207af9192f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 25 Jul 2026 14:57:22 -0700
+Subject: ARM: dts: BCM5301X: fix PCIe controller 2 second interrupt
+
+From: Rosen Penev <rosenp@gmail.com>
+
+[ Upstream commit bab4d538f8485e0d48538fcb82b285df3779278e ]
+
+PCIe controller 2 has interrupts 0-4 mapping to GIC SPI 138-142. The
+mapping for interrupt 1 was incorrectly set to 138 due to a copy-paste
+error. Fix it to 139.
+
+Assisted-by: opencode:big-pickle
+Signed-off-by: Rosen Penev <rosenp@gmail.com>
+Link: https://lore.kernel.org/r/20260725215722.9323-1-rosenp@gmail.com
+Fixes: 3b3e35b279be ("ARM: dts: BCM5301X: Relicense AXI interrupts code to the GPL 2.0+ / MIT")
+Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/boot/dts/broadcom/bcm-ns.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/broadcom/bcm-ns.dtsi b/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
+index 88fda18af1f8e..06acd72f9835a 100644
+--- a/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
+@@ -131,7 +131,7 @@ axi@18000000 {
+
+ /* PCIe Controller 2 */
+ <0x00014000 0 &gic GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
+- <0x00014000 1 &gic GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00014000 1 &gic GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 2 &gic GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 3 &gic GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 4 &gic GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+--
+2.53.0
+
--- /dev/null
+From 164e8b22112f23dc119a8f72ab3bee69b2146793 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 24 May 2026 23:38:46 -0400
+Subject: ARM: npcm: Fix OF node refcount leaks in SMP setup
+
+From: Yuho Choi <dbgh9129@gmail.com>
+
+[ Upstream commit 8eb052f48331474c2789d07b7f11165c323bd2f9 ]
+
+npcm7xx_smp_boot_secondary() and npcm7xx_smp_prepare_cpus() look up
+the GCR and SCU nodes with of_find_compatible_node(). The returned
+nodes are used for of_iomap(), but the node references are never
+released.
+
+of_iomap() does not consume the device node reference, and iounmap()
+only releases the MMIO mapping. Drop each node reference after the
+corresponding mapping attempt.
+
+Fixes: 7bffa14c9aed ("arm: npcm: add basic support for Nuvoton BMCs")
+Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
+Reviewed-by: Avi Fishman <avifishman70@gmail.com>
+Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/mach-npcm/platsmp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arm/mach-npcm/platsmp.c b/arch/arm/mach-npcm/platsmp.c
+index 41891d3aa1247..4c1fc9983746c 100644
+--- a/arch/arm/mach-npcm/platsmp.c
++++ b/arch/arm/mach-npcm/platsmp.c
+@@ -32,6 +32,7 @@ static int npcm7xx_smp_boot_secondary(unsigned int cpu,
+ goto out;
+ }
+ gcr_base = of_iomap(gcr_np, 0);
++ of_node_put(gcr_np);
+ if (!gcr_base) {
+ pr_err("could not iomap gcr");
+ ret = -ENOMEM;
+@@ -60,6 +61,7 @@ static void __init npcm7xx_smp_prepare_cpus(unsigned int max_cpus)
+ return;
+ }
+ scu_base = of_iomap(scu_np, 0);
++ of_node_put(scu_np);
+ if (!scu_base) {
+ pr_err("could not iomap scu");
+ return;
+--
+2.53.0
+
--- /dev/null
+From 32fe4d76959b548d832f3ad3415a25a4040de6f6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Apr 2026 01:27:12 +0300
+Subject: arm64: dts: qcom: sdm850-lenovo-yoga-c630: lower PSCI cluster idle
+
+From: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+
+[ Upstream commit 07db10de262f4150e24fd631a7a6c428f7bf80c9 ]
+
+With the default PSCI suspend value for cluster idle state Lenovo Yoga
+C630 isn't stable enough. For example it might reset if display device
+isn't probed early enough. Drop the bit 0x4000 from the PSCI suspend
+value to make C630 work in stable way. The bit was found by
+expertimenting with the cluster idle PSCI value. Most likely it results
+in the less deep sleep and more energy beign spent in the suspend state,
+but it's better than the non-stable system behaviour.
+
+Fixes: a1ade6cac5a2 ("arm64: dts: qcom: sdm845: Switch PSCI cpu idle states from PC to OSI")
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Reviewed-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
+Link: https://lore.kernel.org/r/20260429-c630-fix-idle-v2-1-ac867dad6f21@oss.qualcomm.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
+index fe5c12da666e4..f757a02de7ab5 100644
+--- a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
++++ b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
+@@ -347,6 +347,10 @@ &cdsp_pas {
+ status = "okay";
+ };
+
++&cluster_sleep_0 {
++ arm,psci-suspend-param = <0x41008244>;
++};
++
+ &gcc {
+ protected-clocks = <GCC_QSPI_CORE_CLK>,
+ <GCC_QSPI_CORE_CLK_SRC>,
+--
+2.53.0
+
--- /dev/null
+From d767bb78e56f0355095f01e8e284faa41c5bb594 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 14:06:28 +0800
+Subject: ata: pata_sl82c105: fix bridge revision use-after-free
+
+From: Hongyan Xu <getshell@seu.edu.cn>
+
+[ Upstream commit 7700a31039cdc6715cb6cce7e7a664ee4e945f67 ]
+
+pci_get_slot() returns a referenced PCI device. Commit 44c10138fd4b
+("PCI: Change all drivers to use pci_device->revision") replaced a
+configuration-space read with direct access to the cached revision field,
+but left that access after pci_dev_put(). The bridge may therefore be freed
+before its revision is read.
+
+Read the revision before dropping the reference.
+
+Fixes: 44c10138fd4b ("PCI: Change all drivers to use pci_device->revision")
+Signed-off-by: Hongyan Xu <getshell@seu.edu.cn>
+Reviewed-by: Niklas Cassel <cassel@kernel.org>
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ata/pata_sl82c105.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
+index 93882e976ede4..2a5ce46af5a0a 100644
+--- a/drivers/ata/pata_sl82c105.c
++++ b/drivers/ata/pata_sl82c105.c
+@@ -264,6 +264,7 @@ static struct ata_port_operations sl82c105_port_ops = {
+ static int sl82c105_bridge_revision(struct pci_dev *pdev)
+ {
+ struct pci_dev *bridge;
++ u8 revision;
+
+ /*
+ * The bridge should be part of the same device, but function 0.
+@@ -285,8 +286,9 @@ static int sl82c105_bridge_revision(struct pci_dev *pdev)
+ /*
+ * We need to find function 0's revision, not function 1
+ */
++ revision = bridge->revision;
+ pci_dev_put(bridge);
+- return bridge->revision;
++ return revision;
+ }
+
+ static void sl82c105_fixup(struct pci_dev *pdev)
+--
+2.53.0
+
--- /dev/null
+From 68ad54d85e8926aed69e357bbdf3610c452e17ac Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:36 -0700
+Subject: bnxt_en: Disable EOP for TPA on all chips to prevent data corruption
+
+From: Michael Chan <michael.chan@broadcom.com>
+
+[ Upstream commit c3faf548a00f4c17100cc9204746975fa46a73b9 ]
+
+EOP (End of frame padding) on the AGG ring may cause overlapping of
+zero padding at the end of one segment with the next segment's data.
+If Relaxed Ordering (RO) is enabled, the zero padding may overwrite
+valid data in the next segment and corrupt the data. Older chips
+(P5 and older) do not automatically disable RO when EOP is enabled.
+On some ARM systems, data corruption was reported on 57508 (P5)
+chips with RO enabled.
+
+Always disable EOP on all chips on the AGG rings when TPA is enabled
+to fix the data corruption.
+
+Fixes: bfcd8d791ec1 ("bnxt_en: Add fast path logic for TPA on 57500 chips.")
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-5-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 9fa9c634b9b27..e305b02b775e3 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -3717,11 +3717,14 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr)
+ type = ((u32)BNXT_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
+ RX_BD_TYPE_RX_AGG_BD;
+
+- /* On P7, setting EOP will cause the chip to disable
+- * Relaxed Ordering (RO) for TPA data. Disable EOP for
+- * potentially higher performance with RO.
++ /* Disable EOP if TPA is enabled to prevent overlapping zero
++ * padding with the next segment's data. On P7_PLUS, EOP will
++ * automatically disable Relaxed Ordering (RO) to prevent
++ * potential data corruption (and may degrade performance). On
++ * older chips, RO will not be automatically disabled and may
++ * cause corruption.
+ */
+- if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
++ if (!(bp->flags & BNXT_FLAG_TPA))
+ type |= RX_BD_FLAGS_AGG_EOP;
+
+ bnxt_init_rxbd_pages(ring, type);
+--
+2.53.0
+
--- /dev/null
+From 736828f51287f39241f06aaa0f3119db678b4b38 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Nov 2025 13:56:46 -0800
+Subject: bnxt_en: Do not set EOP on RX AGG BDs on 5760X chips
+
+From: Michael Chan <michael.chan@broadcom.com>
+
+[ Upstream commit 30f253f8d9a01d532fdb7ec6c8a9d4c15fe29241 ]
+
+With End-of-Packet padding (EOP) set, the chip will disable Relaxed
+Ordering (RO) of TPA data packets. A TPA segment with EOP set will be
+padded to the next cache boundary and can potentially overwrite the
+beginning bytes of the next TPA segment when RO is enabled on 5760X.
+To prevent that, the chip disables RO for TPA when EOP is set.
+
+To take advantge of RO and higher performance, do not set EOP on
+5760X chips when TPA is enabled. Define a proper RX_BD_FLAGS_AGG_EOP
+constant to make it clear that we are setting EOP.
+
+Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
+Reviewed-by: Somnath Kotur <somnath.kotur@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20251126215648.1885936-6-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: c3faf548a00f ("bnxt_en: Disable EOP for TPA on all chips to prevent data corruption")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 ++++++++-
+ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
+ 2 files changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index afe700575f530..9fa9c634b9b27 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -3715,7 +3715,14 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr)
+
+ if ((bp->flags & BNXT_FLAG_AGG_RINGS)) {
+ type = ((u32)BNXT_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
+- RX_BD_TYPE_RX_AGG_BD | RX_BD_FLAGS_SOP;
++ RX_BD_TYPE_RX_AGG_BD;
++
++ /* On P7, setting EOP will cause the chip to disable
++ * Relaxed Ordering (RO) for TPA data. Disable EOP for
++ * potentially higher performance with RO.
++ */
++ if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
++ type |= RX_BD_FLAGS_AGG_EOP;
+
+ bnxt_init_rxbd_pages(ring, type);
+ }
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+index bc1ff1085da7f..739ed9d0b5ab5 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+@@ -104,6 +104,7 @@ struct rx_bd {
+ #define RX_BD_TYPE_48B_BD_SIZE (2 << 4)
+ #define RX_BD_TYPE_64B_BD_SIZE (3 << 4)
+ #define RX_BD_FLAGS_SOP (1 << 6)
++ #define RX_BD_FLAGS_AGG_EOP (1 << 6)
+ #define RX_BD_FLAGS_EOP (1 << 7)
+ #define RX_BD_FLAGS_BUFFERS (3 << 8)
+ #define RX_BD_FLAGS_1_BUFFER_PACKET (0 << 8)
+--
+2.53.0
+
--- /dev/null
+From 76a14183e5bc55749810fc18628fa351f389d6fb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:37 -0700
+Subject: bnxt_en: Fix PTP PPS setting bug
+
+From: Keegan Freyhof <keegan.freyhof@broadcom.com>
+
+[ Upstream commit 80eaf88efec33ac77ed7726d066c4f2f932cc329 ]
+
+The existing driver logic is always turning on PTP_CLK_REQ_PPS
+regardless of the "on" parameter passed to bnxt_ptp_enable().
+During shutdown, PTP_CLK_REQ_PPS may be turned off and this
+bug will do the opposite and may trigger a PCIe PTM request TLP.
+On some systems this can trigger a PCIe AER.
+
+Fix it by properly configuring PTP_CLK_REQ_PPS based on the "on"
+parameter.
+
+Fixes: 9e518f25802c ("bnxt_en: 1PPS functions to configure TSIO pins")
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Keegan Freyhof <keegan.freyhof@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-6-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
+index 404b433f1bc08..d8f39776481b6 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
+@@ -475,12 +475,15 @@ static int bnxt_ptp_enable(struct ptp_clock_info *ptp_info,
+ return rc;
+ case PTP_CLK_REQ_PPS:
+ /* Configure PHC PPS IN */
+- rc = bnxt_ptp_cfg_pin(bp, 0, BNXT_PPS_PIN_PPS_IN);
++ pin_id = 0;
++ if (!on)
++ break;
++ rc = bnxt_ptp_cfg_pin(bp, pin_id, BNXT_PPS_PIN_PPS_IN);
+ if (rc)
+ return rc;
+ rc = bnxt_ptp_cfg_event(bp, BNXT_PPS_EVENT_INTERNAL);
+ if (!rc)
+- ptp->pps_info.pins[0].event = BNXT_PPS_EVENT_INTERNAL;
++ ptp->pps_info.pins[pin_id].event = BNXT_PPS_EVENT_INTERNAL;
+ return rc;
+ default:
+ netdev_err(ptp->bp->dev, "Unrecognized PIN function\n");
+--
+2.53.0
+
--- /dev/null
+From c802dc61a0ad5325870acce50d36621ae334c949 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 25 Jul 2026 23:39:30 +0000
+Subject: bonding: alb: re-check primary_is_promisc under RTNL in
+ bond_alb_monitor
+
+From: Xiang Mei (Microsoft) <xmei5@asu.edu>
+
+[ Upstream commit 683c6ba6e58e6ed1037831ea97dd58d9c0e76b8d ]
+
+bond_alb_monitor() reads primary_is_promisc under RCU, then drops RCU and
+takes RTNL via rtnl_trylock() before undoing the promiscuity it set on the
+active slave. In that window the active slave can change under RTNL
+(RTM_DELLINK -> __bond_release_one() -> bond_alb_handle_active_change()),
+which already drops the promiscuity and clears primary_is_promisc. The
+monitor still acts on the stale decision: if the slave was removed with no
+failover, curr_active_slave is now NULL and the deref faults; if it failed
+over, the stale dev_set_promiscuity(-1) underflows the new slave's
+promiscuity counter and pins it in IFF_PROMISC.
+
+ Oops: general protection fault, probably for non-canonical address ...
+ KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
+ Workqueue: b42 bond_alb_monitor
+ RIP: 0010:bond_alb_monitor (drivers/net/bonding/bond_alb.c:1600)
+ process_one_work (kernel/workqueue.c:3322)
+ worker_thread (kernel/workqueue.c:3486)
+ kthread (kernel/kthread.c:436)
+ ret_from_fork (arch/x86/kernel/process.c:158)
+ Kernel panic - not syncing: Fatal exception
+
+Re-check primary_is_promisc (and curr_active_slave) after taking RTNL so
+the monitor only undoes an increment it still owns. The other bonding
+monitors already re-read state under RTNL in their commit phase
+(bond_miimon_commit/bond_ab_arp_commit); bond_alb_monitor() was the only
+one acting on the pre-trylock decision.
+
+Fixes: d0e81b7e2246 ("bonding: Acquire correct locks in alb for promisc change")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
+Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
+Acked-by: Jay Vosburgh <jv@jvosburgh.net>
+Link: https://patch.msgid.link/20260725233930.2957317-1-xmei5@asu.edu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/bonding/bond_alb.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
+index 7edf0fd58c346..ce6a3a0a2e153 100644
+--- a/drivers/net/bonding/bond_alb.c
++++ b/drivers/net/bonding/bond_alb.c
+@@ -1535,8 +1535,8 @@ void bond_alb_monitor(struct work_struct *work)
+ struct bonding *bond = container_of(work, struct bonding,
+ alb_work.work);
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
++ struct slave *slave, *curr;
+ struct list_head *iter;
+- struct slave *slave;
+
+ if (!bond_has_slaves(bond)) {
+ atomic_set(&bond_info->tx_rebalance_counter, 0);
+@@ -1598,9 +1598,11 @@ void bond_alb_monitor(struct work_struct *work)
+ * because a slave was disabled then
+ * it can now leave promiscuous mode.
+ */
+- dev_set_promiscuity(rtnl_dereference(bond->curr_active_slave)->dev,
+- -1);
+- bond_info->primary_is_promisc = 0;
++ curr = rtnl_dereference(bond->curr_active_slave);
++ if (bond_info->primary_is_promisc && curr) {
++ dev_set_promiscuity(curr->dev, -1);
++ bond_info->primary_is_promisc = 0;
++ }
+
+ rtnl_unlock();
+ rcu_read_lock();
+--
+2.53.0
+
--- /dev/null
+From 9e2aa98c292385d44b63b7726c7846dc17e68711 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:18:28 +0000
+Subject: bpf: Preserve pointer state for commuted arithmetic
+
+From: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+
+[ Upstream commit a4c6f804b44c5c790269b25e0e61cf4e9f117c86 ]
+
+When scalar += pointer is handled in adjust_ptr_min_max_vals(), the
+destination register inherits the pointer state from the source pointer.
+Copying only selected fields is fragile because pointer provenance is
+tracked by several bpf_reg_state fields.
+
+Use the caller's temporary offset register to preserve the scalar operand
+while replacing the destination with the full pointer state. This preserves
+the frame number for PTR_TO_STACK registers and keeps parent identity
+fields consistent.
+
+Fixes: f4d7e40a5b71 ("bpf: introduce function calls (verification)")
+Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+Tested-by: Daniel Wade <danjwade95@gmail.com>
+Acked-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-2-8ee297e2346b@mails.tsinghua.edu.cn
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 5e094c12fc94c..ad679bc42427c 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -12657,11 +12657,12 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ break;
+ }
+
+- /* In case of 'scalar += pointer', dst_reg inherits pointer type and id.
+- * The id may be overwritten later if we create a new variable offset.
++ /* For 'scalar += pointer', dst_reg inherits the complete pointer
++ * register state. Individual fields may be adjusted later by pointer
++ * arithmetic. Callers guarantee that below does not overwrite off_reg.
+ */
+- dst_reg->type = ptr_reg->type;
+- dst_reg->id = ptr_reg->id;
++ if (dst_reg != ptr_reg)
++ *dst_reg = *ptr_reg;
+
+ if (!check_reg_sane_offset(env, off_reg, ptr_reg->type) ||
+ !check_reg_sane_offset(env, ptr_reg, ptr_reg->type))
+@@ -12729,7 +12730,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ }
+ break;
+ case BPF_SUB:
+- if (dst_reg == off_reg) {
++ if (dst_reg != ptr_reg) {
+ /* scalar -= pointer. Creates an unknown scalar */
+ verbose(env, "R%d tried to subtract pointer from scalar\n",
+ dst);
+@@ -13588,8 +13589,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
+ err = mark_chain_precision(env, insn->dst_reg);
+ if (err)
+ return err;
+- return adjust_ptr_min_max_vals(env, insn,
+- src_reg, dst_reg);
++ off_reg = *dst_reg;
++ return adjust_ptr_min_max_vals(env, insn, src_reg, &off_reg);
+ }
+ } else if (ptr_reg) {
+ /* pointer += scalar */
+--
+2.53.0
+
--- /dev/null
+From 0b22bcc51249d8fb83ee576a96ba6207e24619c4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Jul 2025 11:09:09 -0700
+Subject: bpf: tcp: Avoid socket skips and repeats during iteration
+
+From: Jordan Rife <jordan@jrife.io>
+
+[ Upstream commit f5080f612a1c587bf636bb23d2a2f4de276d60e4 ]
+
+Replace the offset-based approach for tracking progress through a bucket
+in the TCP table with one based on socket cookies. Remember the cookies
+of unprocessed sockets from the last batch and use this list to
+pick up where we left off or, in the case that the next socket
+disappears between reads, find the first socket after that point that
+still exists in the bucket and resume from there.
+
+This approach guarantees that all sockets that existed when iteration
+began and continue to exist throughout will be visited exactly once.
+Sockets that are added to the table during iteration may or may not be
+seen, but if they are they will be seen exactly once.
+
+Signed-off-by: Jordan Rife <jordan@jrife.io>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 147 ++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 115 insertions(+), 32 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index a826d137c86b4..e9f191315593c 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -58,6 +58,7 @@
+ #include <linux/times.h>
+ #include <linux/slab.h>
+ #include <linux/sched.h>
++#include <linux/sock_diag.h>
+
+ #include <net/net_namespace.h>
+ #include <net/icmp.h>
+@@ -2778,6 +2779,7 @@ static int tcp4_seq_show(struct seq_file *seq, void *v)
+ #ifdef CONFIG_BPF_SYSCALL
+ union bpf_tcp_iter_batch_item {
+ struct sock *sk;
++ __u64 cookie;
+ };
+
+ struct bpf_tcp_iter_state {
+@@ -2808,10 +2810,19 @@ static int tcp_prog_seq_show(struct bpf_prog *prog, struct bpf_iter_meta *meta,
+
+ static void bpf_iter_tcp_put_batch(struct bpf_tcp_iter_state *iter)
+ {
++ union bpf_tcp_iter_batch_item *item;
+ unsigned int cur_sk = iter->cur_sk;
++ __u64 cookie;
+
+- while (cur_sk < iter->end_sk)
+- sock_gen_put(iter->batch[cur_sk++].sk);
++ /* Remember the cookies of the sockets we haven't seen yet, so we can
++ * pick up where we left off next time around.
++ */
++ while (cur_sk < iter->end_sk) {
++ item = &iter->batch[cur_sk++];
++ cookie = sock_gen_cookie(item->sk);
++ sock_gen_put(item->sk);
++ item->cookie = cookie;
++ }
+ }
+
+ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+@@ -2832,6 +2843,106 @@ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+ return 0;
+ }
+
++static struct sock *bpf_iter_tcp_resume_bucket(struct sock *first_sk,
++ union bpf_tcp_iter_batch_item *cookies,
++ int n_cookies)
++{
++ struct hlist_nulls_node *node;
++ struct sock *sk;
++ int i;
++
++ for (i = 0; i < n_cookies; i++) {
++ sk = first_sk;
++ sk_nulls_for_each_from(sk, node)
++ if (cookies[i].cookie == atomic64_read(&sk->sk_cookie))
++ return sk;
++ }
++
++ return NULL;
++}
++
++static struct sock *bpf_iter_tcp_resume_listening(struct seq_file *seq)
++{
++ struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
++ struct bpf_tcp_iter_state *iter = seq->private;
++ struct tcp_iter_state *st = &iter->state;
++ unsigned int find_cookie = iter->cur_sk;
++ unsigned int end_cookie = iter->end_sk;
++ int resume_bucket = st->bucket;
++ struct sock *sk;
++
++ if (end_cookie && find_cookie == end_cookie)
++ ++st->bucket;
++
++ sk = listening_get_first(seq);
++ iter->cur_sk = 0;
++ iter->end_sk = 0;
++
++ if (sk && st->bucket == resume_bucket && end_cookie) {
++ sk = bpf_iter_tcp_resume_bucket(sk, &iter->batch[find_cookie],
++ end_cookie - find_cookie);
++ if (!sk) {
++ spin_unlock(&hinfo->lhash2[st->bucket].lock);
++ ++st->bucket;
++ sk = listening_get_first(seq);
++ }
++ }
++
++ return sk;
++}
++
++static struct sock *bpf_iter_tcp_resume_established(struct seq_file *seq)
++{
++ struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
++ struct bpf_tcp_iter_state *iter = seq->private;
++ struct tcp_iter_state *st = &iter->state;
++ unsigned int find_cookie = iter->cur_sk;
++ unsigned int end_cookie = iter->end_sk;
++ int resume_bucket = st->bucket;
++ struct sock *sk;
++
++ if (end_cookie && find_cookie == end_cookie)
++ ++st->bucket;
++
++ sk = established_get_first(seq);
++ iter->cur_sk = 0;
++ iter->end_sk = 0;
++
++ if (sk && st->bucket == resume_bucket && end_cookie) {
++ sk = bpf_iter_tcp_resume_bucket(sk, &iter->batch[find_cookie],
++ end_cookie - find_cookie);
++ if (!sk) {
++ spin_unlock_bh(inet_ehash_lockp(hinfo, st->bucket));
++ ++st->bucket;
++ sk = established_get_first(seq);
++ }
++ }
++
++ return sk;
++}
++
++static struct sock *bpf_iter_tcp_resume(struct seq_file *seq)
++{
++ struct bpf_tcp_iter_state *iter = seq->private;
++ struct tcp_iter_state *st = &iter->state;
++ struct sock *sk = NULL;
++
++ switch (st->state) {
++ case TCP_SEQ_STATE_LISTENING:
++ sk = bpf_iter_tcp_resume_listening(seq);
++ if (sk)
++ break;
++ st->bucket = 0;
++ st->state = TCP_SEQ_STATE_ESTABLISHED;
++ fallthrough;
++ case TCP_SEQ_STATE_ESTABLISHED:
++ sk = bpf_iter_tcp_resume_established(seq);
++ break;
++ }
++
++ return sk;
++}
++
+ static unsigned int bpf_iter_tcp_listening_batch(struct seq_file *seq,
+ struct sock **start_sk)
+ {
+@@ -2916,32 +3027,12 @@ static void bpf_iter_tcp_unlock_bucket(struct seq_file *seq)
+
+ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ {
+- struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
+ struct bpf_tcp_iter_state *iter = seq->private;
+- struct tcp_iter_state *st = &iter->state;
+ unsigned int expected;
+ struct sock *sk;
+ int err;
+
+- /* The st->bucket is done. Directly advance to the next
+- * bucket instead of having the tcp_seek_last_pos() to skip
+- * one by one in the current bucket and eventually find out
+- * it has to advance to the next bucket.
+- */
+- if (iter->end_sk && iter->cur_sk == iter->end_sk) {
+- st->offset = 0;
+- st->bucket++;
+- if (st->state == TCP_SEQ_STATE_LISTENING &&
+- st->bucket > hinfo->lhash2_mask) {
+- st->state = TCP_SEQ_STATE_ESTABLISHED;
+- st->bucket = 0;
+- }
+- }
+-
+- iter->cur_sk = 0;
+- iter->end_sk = 0;
+-
+- sk = tcp_seek_last_pos(seq);
++ sk = bpf_iter_tcp_resume(seq);
+ if (!sk)
+ return NULL; /* Done */
+
+@@ -2957,10 +3048,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ if (err)
+ return ERR_PTR(err);
+
+- iter->cur_sk = 0;
+- iter->end_sk = 0;
+-
+- sk = tcp_seek_last_pos(seq);
++ sk = bpf_iter_tcp_resume(seq);
+ if (!sk)
+ return NULL; /* Done */
+
+@@ -3012,11 +3100,6 @@ static void *bpf_iter_tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+ * meta.seq_num is used instead.
+ */
+ st->num++;
+- /* Move st->offset to the next sk in the bucket such that
+- * the future start() will resume at st->offset in
+- * st->bucket. See tcp_seek_last_pos().
+- */
+- st->offset++;
+ sock_gen_put(iter->batch[iter->cur_sk++].sk);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 3d3c1423b616a0f7bd12a3f22bfb30af61e0b028 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 22:32:47 +0000
+Subject: bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()
+
+From: Jose Fernandez (Anthropic) <jose.fernandez@linux.dev>
+
+[ Upstream commit e5fd3f514e27db1f05fbd72ba615d74941e23c51 ]
+
+reqsk_queue_hash_req() publishes a TCP_NEW_SYN_RECV request_sock onto
+the ehash chain, drops the bucket lock, and only afterwards sets
+rsk_refcnt to 3.
+
+Lockless readers such as __inet_lookup_established() handle this with
+refcount_inc_not_zero(), but bpf_iter_tcp_established_batch() uses plain
+sock_hold() while holding the bucket lock, on the assumption that the
+lock guarantees sk_refcnt > 0. That assumption does not hold for
+request_sock:
+
+ CPU 0 CPU 1
+ ----- -----
+ tcp_conn_request()
+ reqsk_queue_hash_req()
+ inet_ehash_insert(req)
+ spin_lock(bucket)
+ __sk_nulls_add_node_rcu(req) // rsk_refcnt == 0
+ spin_unlock(bucket)
+ bpf_iter_tcp_established_batch()
+ spin_lock(bucket)
+ sock_hold(req) <-- addition on 0
+ spin_unlock(bucket)
+ refcount_set(&req->rsk_refcnt, 3) // clobbers saturated value
+
+which surfaces as:
+
+ refcount_t: addition on 0; use-after-free.
+ WARNING: lib/refcount.c:25 at refcount_warn_saturate+0x48/0x90, CPU#1
+ Call Trace:
+ bpf_iter_tcp_established_batch+0x14e/0x170
+ bpf_iter_tcp_batch+0x53/0x200
+ bpf_iter_tcp_seq_next+0x27/0x70
+ bpf_seq_read+0x107/0x410
+ vfs_read+0xb9/0x380
+
+The iterator's stolen reference is lost when the publishing CPU's
+refcount_set() overwrites the count, leaving the socket one reference
+short. When the last legitimate owner drops its reference the reqsk is
+freed while still reachable, leading to use-after-free.
+
+This reproduces in seconds with tcp_syncookies=0, a handful of threads
+doing connect()/close() to a local listener while others read an
+iter/tcp link in a tight loop.
+
+Use refcount_inc_not_zero() and skip the socket on failure. A skipped
+socket is still part of the bucket, so keep counting it in expected.
+The reallocations are sized from expected, and a request sock whose
+refcount gets published while the lock is held across the last realloc
+must already have room.
+
+A skipped socket is counted in expected but never batched, so end_sk
+can be short of expected on a batch that is actually complete. Decide
+completeness by whether the walk left any socket behind instead. The
+WARN after the locked realloc checks the same, replacing an
+end_sk == expected check that could not hold on that path since
+commit cdec67a489d4 ("bpf: tcp: Make sure iter->batch always
+contains a full bucket snapshot").
+
+If every matching socket in a bucket is mid-init (refcount 0), end_sk
+stays 0. Advance to the next bucket rather than returning a batch entry
+that was never filled this round.
+
+Fixes: 04c7820b776f ("bpf: tcp: Bpf iter batching and lock_sock")
+Assisted-by: Claude:unspecified
+Signed-off-by: Jose Fernandez (Anthropic) <jose.fernandez@linux.dev>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Link: https://lore.kernel.org/bpf/20260730-bpf-iter-tcp-refcnt-v3-1-754b9c8a6717@linux.dev
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 43 ++++++++++++++++++++++++-------------------
+ 1 file changed, 24 insertions(+), 19 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index e9f191315593c..868a593d63ad2 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -2977,24 +2977,24 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,
+ {
+ struct bpf_tcp_iter_state *iter = seq->private;
+ struct hlist_nulls_node *node;
+- unsigned int expected = 1;
+- struct sock *sk;
+-
+- sock_hold(*start_sk);
+- iter->batch[iter->end_sk++].sk = *start_sk;
++ struct sock *sk = *start_sk;
++ unsigned int expected = 0;
+
+- sk = sk_nulls_next(*start_sk);
+ *start_sk = NULL;
+ sk_nulls_for_each_from(sk, node) {
+- if (seq_sk_match(seq, sk)) {
+- if (iter->end_sk < iter->max_sk) {
+- sock_hold(sk);
+- iter->batch[iter->end_sk++].sk = sk;
+- } else if (!*start_sk) {
+- /* Remember where we left off. */
+- *start_sk = sk;
+- }
+- expected++;
++ if (!seq_sk_match(seq, sk))
++ continue;
++ expected++;
++ if (iter->end_sk < iter->max_sk) {
++ /* reqsk_queue_hash_req() inserts with sk_refcnt == 0
++ * and refcount_set()s it after the bucket lock drops.
++ */
++ if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
++ continue;
++ iter->batch[iter->end_sk++].sk = sk;
++ } else if (!*start_sk) {
++ /* Remember where we left off. */
++ *start_sk = sk;
+ }
+ }
+
+@@ -3032,12 +3032,13 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ struct sock *sk;
+ int err;
+
++again:
+ sk = bpf_iter_tcp_resume(seq);
+ if (!sk)
+ return NULL; /* Done */
+
+ expected = bpf_iter_fill_batch(seq, &sk);
+- if (likely(iter->end_sk == expected))
++ if (likely(!sk))
+ goto done;
+
+ /* Batch size was too small. */
+@@ -3053,7 +3054,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ return NULL; /* Done */
+
+ expected = bpf_iter_fill_batch(seq, &sk);
+- if (likely(iter->end_sk == expected))
++ if (likely(!sk))
+ goto done;
+
+ /* Batch size was still too small. Hold onto the lock while we try
+@@ -3066,10 +3067,14 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ return ERR_PTR(err);
+ }
+
+- expected = bpf_iter_fill_batch(seq, &sk);
+- WARN_ON_ONCE(iter->end_sk != expected);
++ bpf_iter_fill_batch(seq, &sk);
++ WARN_ON_ONCE(sk);
+ done:
+ bpf_iter_tcp_unlock_bucket(seq);
++ if (unlikely(!iter->end_sk)) {
++ ++iter->state.bucket;
++ goto again;
++ }
+ return iter->batch[0].sk;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 2f088a79af1ab9b612219e74a6b3453d8e71ec3d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Jul 2025 11:09:07 -0700
+Subject: bpf: tcp: Get rid of st_bucket_done
+
+From: Jordan Rife <jordan@jrife.io>
+
+[ Upstream commit e25ab9b874a4bd8c6e3e5ce66cbe8a1dd4096e2e ]
+
+Get rid of the st_bucket_done field to simplify TCP iterator state and
+logic. Before, st_bucket_done could be false if bpf_iter_tcp_batch
+returned a partial batch; however, with the last patch ("bpf: tcp: Make
+sure iter->batch always contains a full bucket snapshot"),
+st_bucket_done == true is equivalent to iter->cur_sk == iter->end_sk.
+
+Signed-off-by: Jordan Rife <jordan@jrife.io>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 14 ++++++--------
+ 1 file changed, 6 insertions(+), 8 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index d584ce27b2ddd..c32902c07bd0c 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -2782,7 +2782,6 @@ struct bpf_tcp_iter_state {
+ unsigned int end_sk;
+ unsigned int max_sk;
+ struct sock **batch;
+- bool st_bucket_done;
+ };
+
+ struct bpf_iter__tcp {
+@@ -2805,8 +2804,10 @@ static int tcp_prog_seq_show(struct bpf_prog *prog, struct bpf_iter_meta *meta,
+
+ static void bpf_iter_tcp_put_batch(struct bpf_tcp_iter_state *iter)
+ {
+- while (iter->cur_sk < iter->end_sk)
+- sock_gen_put(iter->batch[iter->cur_sk++]);
++ unsigned int cur_sk = iter->cur_sk;
++
++ while (cur_sk < iter->end_sk)
++ sock_gen_put(iter->batch[cur_sk++]);
+ }
+
+ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+@@ -2923,7 +2924,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ * one by one in the current bucket and eventually find out
+ * it has to advance to the next bucket.
+ */
+- if (iter->st_bucket_done) {
++ if (iter->end_sk && iter->cur_sk == iter->end_sk) {
+ st->offset = 0;
+ st->bucket++;
+ if (st->state == TCP_SEQ_STATE_LISTENING &&
+@@ -2935,7 +2936,6 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+
+ iter->cur_sk = 0;
+ iter->end_sk = 0;
+- iter->st_bucket_done = true;
+
+ sk = tcp_seek_last_pos(seq);
+ if (!sk)
+@@ -3083,10 +3083,8 @@ static void bpf_iter_tcp_seq_stop(struct seq_file *seq, void *v)
+ (void)tcp_prog_seq_show(prog, &meta, v, 0);
+ }
+
+- if (iter->cur_sk < iter->end_sk) {
++ if (iter->cur_sk < iter->end_sk)
+ bpf_iter_tcp_put_batch(iter);
+- iter->st_bucket_done = false;
+- }
+ }
+
+ static const struct seq_operations bpf_iter_tcp_seq_ops = {
+--
+2.53.0
+
--- /dev/null
+From d92dd047190ae8e558cd84d7836e5352bebb3da0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Jul 2025 11:09:05 -0700
+Subject: bpf: tcp: Make mem flags configurable through
+ bpf_iter_tcp_realloc_batch
+
+From: Jordan Rife <jordan@jrife.io>
+
+[ Upstream commit 8271bec9fc1cfe522b1a18cacbefd6712a3d41c2 ]
+
+Prepare for the next patch which needs to be able to choose either
+GFP_USER or GFP_NOWAIT for calls to bpf_iter_tcp_realloc_batch.
+
+Signed-off-by: Jordan Rife <jordan@jrife.io>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index c8d35f1c0ece2..17bd4e3b4558d 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -2810,12 +2810,12 @@ static void bpf_iter_tcp_put_batch(struct bpf_tcp_iter_state *iter)
+ }
+
+ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+- unsigned int new_batch_sz)
++ unsigned int new_batch_sz, gfp_t flags)
+ {
+ struct sock **new_batch;
+
+ new_batch = kvmalloc(sizeof(*new_batch) * new_batch_sz,
+- GFP_USER | __GFP_NOWARN);
++ flags | __GFP_NOWARN);
+ if (!new_batch)
+ return -ENOMEM;
+
+@@ -2927,7 +2927,8 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ return sk;
+ }
+
+- if (!resized && !bpf_iter_tcp_realloc_batch(iter, expected * 3 / 2)) {
++ if (!resized && !bpf_iter_tcp_realloc_batch(iter, expected * 3 / 2,
++ GFP_USER)) {
+ resized = true;
+ goto again;
+ }
+@@ -3355,7 +3356,7 @@ static int bpf_iter_init_tcp(void *priv_data, struct bpf_iter_aux_info *aux)
+ if (err)
+ return err;
+
+- err = bpf_iter_tcp_realloc_batch(iter, INIT_BATCH_SZ);
++ err = bpf_iter_tcp_realloc_batch(iter, INIT_BATCH_SZ, GFP_USER);
+ if (err) {
+ bpf_iter_fini_seq_net(priv_data);
+ return err;
+--
+2.53.0
+
--- /dev/null
+From b714bf7dc84a132dad0ed1c4341ca76bdb6436e0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Jul 2025 11:09:06 -0700
+Subject: bpf: tcp: Make sure iter->batch always contains a full bucket
+ snapshot
+
+From: Jordan Rife <jordan@jrife.io>
+
+[ Upstream commit cdec67a489d4fdae3e83e04fca0419136a83c4c2 ]
+
+Require that iter->batch always contains a full bucket snapshot. This
+invariant is important to avoid skipping or repeating sockets during
+iteration when combined with the next few patches. Before, there were
+two cases where a call to bpf_iter_tcp_batch may only capture part of a
+bucket:
+
+1. When bpf_iter_tcp_realloc_batch() returns -ENOMEM.
+2. When more sockets are added to the bucket while calling
+ bpf_iter_tcp_realloc_batch(), making the updated batch size
+ insufficient.
+
+In cases where the batch size only covers part of a bucket, it is
+possible to forget which sockets were already visited, especially if we
+have to process a bucket in more than two batches. This forces us to
+choose between repeating or skipping sockets, so don't allow this:
+
+1. Stop iteration and propagate -ENOMEM up to userspace if reallocation
+ fails instead of continuing with a partial batch.
+2. Try bpf_iter_tcp_realloc_batch() with GFP_USER just as before, but if
+ we still aren't able to capture the full bucket, call
+ bpf_iter_tcp_realloc_batch() again while holding the bucket lock to
+ guarantee the bucket does not change. On the second attempt use
+ GFP_NOWAIT since we hold onto the spin lock.
+
+I did some manual testing to exercise the code paths where GFP_NOWAIT is
+used and where ERR_PTR(err) is returned. I used the realloc test cases
+included later in this series to trigger a scenario where a realloc
+happens inside bpf_iter_tcp_batch and made a small code tweak to force
+the first realloc attempt to allocate a too-small batch, thus requiring
+another attempt with GFP_NOWAIT. Some printks showed both reallocs with
+the tests passing:
+
+Jun 27 00:00:53 crow kernel: again GFP_USER
+Jun 27 00:00:53 crow kernel: again GFP_NOWAIT
+Jun 27 00:00:53 crow kernel: again GFP_USER
+Jun 27 00:00:53 crow kernel: again GFP_NOWAIT
+
+With this setup, I also forced each of the bpf_iter_tcp_realloc_batch
+calls to return -ENOMEM to ensure that iteration ends and that the
+read() in userspace fails.
+
+Signed-off-by: Jordan Rife <jordan@jrife.io>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 109 +++++++++++++++++++++++++++++++-------------
+ 1 file changed, 77 insertions(+), 32 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index 17bd4e3b4558d..d584ce27b2ddd 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -2819,7 +2819,7 @@ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+ if (!new_batch)
+ return -ENOMEM;
+
+- bpf_iter_tcp_put_batch(iter);
++ memcpy(new_batch, iter->batch, sizeof(*iter->batch) * iter->end_sk);
+ kvfree(iter->batch);
+ iter->batch = new_batch;
+ iter->max_sk = new_batch_sz;
+@@ -2828,69 +2828,95 @@ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+ }
+
+ static unsigned int bpf_iter_tcp_listening_batch(struct seq_file *seq,
+- struct sock *start_sk)
++ struct sock **start_sk)
+ {
+- struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
+ struct bpf_tcp_iter_state *iter = seq->private;
+- struct tcp_iter_state *st = &iter->state;
+ struct hlist_nulls_node *node;
+ unsigned int expected = 1;
+ struct sock *sk;
+
+- sock_hold(start_sk);
+- iter->batch[iter->end_sk++] = start_sk;
++ sock_hold(*start_sk);
++ iter->batch[iter->end_sk++] = *start_sk;
+
+- sk = sk_nulls_next(start_sk);
++ sk = sk_nulls_next(*start_sk);
++ *start_sk = NULL;
+ sk_nulls_for_each_from(sk, node) {
+ if (seq_sk_match(seq, sk)) {
+ if (iter->end_sk < iter->max_sk) {
+ sock_hold(sk);
+ iter->batch[iter->end_sk++] = sk;
++ } else if (!*start_sk) {
++ /* Remember where we left off. */
++ *start_sk = sk;
+ }
+ expected++;
+ }
+ }
+- spin_unlock(&hinfo->lhash2[st->bucket].lock);
+
+ return expected;
+ }
+
+ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,
+- struct sock *start_sk)
++ struct sock **start_sk)
+ {
+- struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
+ struct bpf_tcp_iter_state *iter = seq->private;
+- struct tcp_iter_state *st = &iter->state;
+ struct hlist_nulls_node *node;
+ unsigned int expected = 1;
+ struct sock *sk;
+
+- sock_hold(start_sk);
+- iter->batch[iter->end_sk++] = start_sk;
++ sock_hold(*start_sk);
++ iter->batch[iter->end_sk++] = *start_sk;
+
+- sk = sk_nulls_next(start_sk);
++ sk = sk_nulls_next(*start_sk);
++ *start_sk = NULL;
+ sk_nulls_for_each_from(sk, node) {
+ if (seq_sk_match(seq, sk)) {
+ if (iter->end_sk < iter->max_sk) {
+ sock_hold(sk);
+ iter->batch[iter->end_sk++] = sk;
++ } else if (!*start_sk) {
++ /* Remember where we left off. */
++ *start_sk = sk;
+ }
+ expected++;
+ }
+ }
+- spin_unlock_bh(inet_ehash_lockp(hinfo, st->bucket));
+
+ return expected;
+ }
+
++static unsigned int bpf_iter_fill_batch(struct seq_file *seq,
++ struct sock **start_sk)
++{
++ struct bpf_tcp_iter_state *iter = seq->private;
++ struct tcp_iter_state *st = &iter->state;
++
++ if (st->state == TCP_SEQ_STATE_LISTENING)
++ return bpf_iter_tcp_listening_batch(seq, start_sk);
++ else
++ return bpf_iter_tcp_established_batch(seq, start_sk);
++}
++
++static void bpf_iter_tcp_unlock_bucket(struct seq_file *seq)
++{
++ struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
++ struct bpf_tcp_iter_state *iter = seq->private;
++ struct tcp_iter_state *st = &iter->state;
++
++ if (st->state == TCP_SEQ_STATE_LISTENING)
++ spin_unlock(&hinfo->lhash2[st->bucket].lock);
++ else
++ spin_unlock_bh(inet_ehash_lockp(hinfo, st->bucket));
++}
++
+ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ {
+ struct inet_hashinfo *hinfo = seq_file_net(seq)->ipv4.tcp_death_row.hashinfo;
+ struct bpf_tcp_iter_state *iter = seq->private;
+ struct tcp_iter_state *st = &iter->state;
+ unsigned int expected;
+- bool resized = false;
+ struct sock *sk;
++ int err;
+
+ /* The st->bucket is done. Directly advance to the next
+ * bucket instead of having the tcp_seek_last_pos() to skip
+@@ -2907,33 +2933,52 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ }
+ }
+
+-again:
+- /* Get a new batch */
+ iter->cur_sk = 0;
+ iter->end_sk = 0;
+- iter->st_bucket_done = false;
++ iter->st_bucket_done = true;
+
+ sk = tcp_seek_last_pos(seq);
+ if (!sk)
+ return NULL; /* Done */
+
+- if (st->state == TCP_SEQ_STATE_LISTENING)
+- expected = bpf_iter_tcp_listening_batch(seq, sk);
+- else
+- expected = bpf_iter_tcp_established_batch(seq, sk);
++ expected = bpf_iter_fill_batch(seq, &sk);
++ if (likely(iter->end_sk == expected))
++ goto done;
+
+- if (iter->end_sk == expected) {
+- iter->st_bucket_done = true;
+- return sk;
+- }
++ /* Batch size was too small. */
++ bpf_iter_tcp_unlock_bucket(seq);
++ bpf_iter_tcp_put_batch(iter);
++ err = bpf_iter_tcp_realloc_batch(iter, expected * 3 / 2,
++ GFP_USER);
++ if (err)
++ return ERR_PTR(err);
++
++ iter->cur_sk = 0;
++ iter->end_sk = 0;
++
++ sk = tcp_seek_last_pos(seq);
++ if (!sk)
++ return NULL; /* Done */
++
++ expected = bpf_iter_fill_batch(seq, &sk);
++ if (likely(iter->end_sk == expected))
++ goto done;
+
+- if (!resized && !bpf_iter_tcp_realloc_batch(iter, expected * 3 / 2,
+- GFP_USER)) {
+- resized = true;
+- goto again;
++ /* Batch size was still too small. Hold onto the lock while we try
++ * again with a larger batch to make sure the current bucket's size
++ * does not change in the meantime.
++ */
++ err = bpf_iter_tcp_realloc_batch(iter, expected, GFP_NOWAIT);
++ if (err) {
++ bpf_iter_tcp_unlock_bucket(seq);
++ return ERR_PTR(err);
+ }
+
+- return sk;
++ expected = bpf_iter_fill_batch(seq, &sk);
++ WARN_ON_ONCE(iter->end_sk != expected);
++done:
++ bpf_iter_tcp_unlock_bucket(seq);
++ return iter->batch[0];
+ }
+
+ static void *bpf_iter_tcp_seq_start(struct seq_file *seq, loff_t *pos)
+--
+2.53.0
+
--- /dev/null
+From 63374aa7d62904b8b764d2ab6ca4851df4b2e69a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Jul 2025 11:09:08 -0700
+Subject: bpf: tcp: Use bpf_tcp_iter_batch_item for bpf_tcp_iter_state batch
+ items
+
+From: Jordan Rife <jordan@jrife.io>
+
+[ Upstream commit efeb820951ebf3778830256496ff72d00d135310 ]
+
+Prepare for the next patch that tracks cookies between iterations by
+converting struct sock **batch to union bpf_tcp_iter_batch_item *batch
+inside struct bpf_tcp_iter_state.
+
+Signed-off-by: Jordan Rife <jordan@jrife.io>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 24 ++++++++++++++----------
+ 1 file changed, 14 insertions(+), 10 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index c32902c07bd0c..a826d137c86b4 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -2776,12 +2776,16 @@ static int tcp4_seq_show(struct seq_file *seq, void *v)
+ }
+
+ #ifdef CONFIG_BPF_SYSCALL
++union bpf_tcp_iter_batch_item {
++ struct sock *sk;
++};
++
+ struct bpf_tcp_iter_state {
+ struct tcp_iter_state state;
+ unsigned int cur_sk;
+ unsigned int end_sk;
+ unsigned int max_sk;
+- struct sock **batch;
++ union bpf_tcp_iter_batch_item *batch;
+ };
+
+ struct bpf_iter__tcp {
+@@ -2807,13 +2811,13 @@ static void bpf_iter_tcp_put_batch(struct bpf_tcp_iter_state *iter)
+ unsigned int cur_sk = iter->cur_sk;
+
+ while (cur_sk < iter->end_sk)
+- sock_gen_put(iter->batch[cur_sk++]);
++ sock_gen_put(iter->batch[cur_sk++].sk);
+ }
+
+ static int bpf_iter_tcp_realloc_batch(struct bpf_tcp_iter_state *iter,
+ unsigned int new_batch_sz, gfp_t flags)
+ {
+- struct sock **new_batch;
++ union bpf_tcp_iter_batch_item *new_batch;
+
+ new_batch = kvmalloc(sizeof(*new_batch) * new_batch_sz,
+ flags | __GFP_NOWARN);
+@@ -2837,7 +2841,7 @@ static unsigned int bpf_iter_tcp_listening_batch(struct seq_file *seq,
+ struct sock *sk;
+
+ sock_hold(*start_sk);
+- iter->batch[iter->end_sk++] = *start_sk;
++ iter->batch[iter->end_sk++].sk = *start_sk;
+
+ sk = sk_nulls_next(*start_sk);
+ *start_sk = NULL;
+@@ -2845,7 +2849,7 @@ static unsigned int bpf_iter_tcp_listening_batch(struct seq_file *seq,
+ if (seq_sk_match(seq, sk)) {
+ if (iter->end_sk < iter->max_sk) {
+ sock_hold(sk);
+- iter->batch[iter->end_sk++] = sk;
++ iter->batch[iter->end_sk++].sk = sk;
+ } else if (!*start_sk) {
+ /* Remember where we left off. */
+ *start_sk = sk;
+@@ -2866,7 +2870,7 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,
+ struct sock *sk;
+
+ sock_hold(*start_sk);
+- iter->batch[iter->end_sk++] = *start_sk;
++ iter->batch[iter->end_sk++].sk = *start_sk;
+
+ sk = sk_nulls_next(*start_sk);
+ *start_sk = NULL;
+@@ -2874,7 +2878,7 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,
+ if (seq_sk_match(seq, sk)) {
+ if (iter->end_sk < iter->max_sk) {
+ sock_hold(sk);
+- iter->batch[iter->end_sk++] = sk;
++ iter->batch[iter->end_sk++].sk = sk;
+ } else if (!*start_sk) {
+ /* Remember where we left off. */
+ *start_sk = sk;
+@@ -2978,7 +2982,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ WARN_ON_ONCE(iter->end_sk != expected);
+ done:
+ bpf_iter_tcp_unlock_bucket(seq);
+- return iter->batch[0];
++ return iter->batch[0].sk;
+ }
+
+ static void *bpf_iter_tcp_seq_start(struct seq_file *seq, loff_t *pos)
+@@ -3013,11 +3017,11 @@ static void *bpf_iter_tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+ * st->bucket. See tcp_seek_last_pos().
+ */
+ st->offset++;
+- sock_gen_put(iter->batch[iter->cur_sk++]);
++ sock_gen_put(iter->batch[iter->cur_sk++].sk);
+ }
+
+ if (iter->cur_sk < iter->end_sk)
+- sk = iter->batch[iter->cur_sk];
++ sk = iter->batch[iter->cur_sk].sk;
+ else
+ sk = bpf_iter_tcp_batch(seq);
+
+--
+2.53.0
+
--- /dev/null
+From c3fa879a175b1840b27fee7750f538d9a4accd97 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 14:53:52 +0300
+Subject: btrfs: fix memory leak in btrfs_do_encoded_write()
+
+From: Dmitry Antipov <dmantipov@yandex.ru>
+
+[ Upstream commit d2a4e4e626b2f4670b69b430c357f03f53eb6632 ]
+
+Local fuzzing of 6.12.94 has found the following memory leak:
+
+Unreferenced object 0xffff888018050a80 (size 64):
+ comm "syz.0.17", pid 10297, jiffies 4294953601
+ hex dump (first 32 bytes):
+ 00 10 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................
+ 10 0a 05 18 80 88 ff ff 10 0a 05 18 80 88 ff ff ................
+ backtrace (crc a8a6fc29):
+ kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
+ slab_post_alloc_hook mm/slub.c:4152 [inline]
+ slab_alloc_node mm/slub.c:4197 [inline]
+ __kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358
+ kmalloc_noprof include/linux/slab.h:878 [inline]
+ extent_changeset_alloc fs/btrfs/extent_io.h:207 [inline]
+ qgroup_reserve_data+0x1c5/0x7d0 fs/btrfs/qgroup.c:4305
+ btrfs_qgroup_reserve_data+0x2e/0xb0 fs/btrfs/qgroup.c:4355
+ btrfs_do_encoded_write+0x92e/0x1040 fs/btrfs/inode.c:9746
+ btrfs_encoded_write fs/btrfs/file.c:1482 [inline]
+ btrfs_do_write_iter+0x280/0x610 fs/btrfs/file.c:1507
+ btrfs_ioctl_encoded_write+0x3d6/0x490 fs/btrfs/ioctl.c:4738
+ btrfs_ioctl+0x6f9/0xc90 fs/btrfs/ioctl.c:-1
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:906 [inline]
+ __se_sys_ioctl+0xf9/0x170 fs/ioctl.c:892
+ do_syscall_x64 arch/x86/entry/common.c:47 [inline]
+ do_syscall_64+0xbe/0x1a0 arch/x86/entry/common.c:78
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Unreferenced object 0xffff888018050a00 (size 64):
+ comm "syz.0.17", pid 10297, jiffies 4294953601
+ hex dump (first 32 bytes):
+ 00 00 00 00 00 00 00 00 ff 0f 00 00 00 00 00 00 ................
+ 90 0a 05 18 80 88 ff ff 90 0a 05 18 80 88 ff ff ................
+ backtrace (crc cb5c9580):
+ kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
+ slab_post_alloc_hook mm/slub.c:4152 [inline]
+ slab_alloc_node mm/slub.c:4197 [inline]
+ __kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358
+ kmalloc_noprof include/linux/slab.h:878 [inline]
+ kzalloc_noprof include/linux/slab.h:1014 [inline]
+ ulist_prealloc+0x9c/0x110 fs/btrfs/ulist.c:114
+ extent_changeset_prealloc fs/btrfs/extent_io.h:217 [inline]
+ __set_extent_bit+0x16b/0x1a70 fs/btrfs/extent-io-tree.c:1086
+ set_record_extent_bits+0x50/0x90 fs/btrfs/extent-io-tree.c:1821
+ qgroup_reserve_data+0x274/0x7d0 fs/btrfs/qgroup.c:4312
+ btrfs_qgroup_reserve_data+0x2e/0xb0 fs/btrfs/qgroup.c:4355
+ btrfs_do_encoded_write+0x92e/0x1040 fs/btrfs/inode.c:9746
+ btrfs_encoded_write fs/btrfs/file.c:1482 [inline]
+ btrfs_do_write_iter+0x280/0x610 fs/btrfs/file.c:1507
+ btrfs_ioctl_encoded_write+0x3d6/0x490 fs/btrfs/ioctl.c:4738
+ btrfs_ioctl+0x6f9/0xc90 fs/btrfs/ioctl.c:-1
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:906 [inline]
+ __se_sys_ioctl+0xf9/0x170 fs/ioctl.c:892
+ do_syscall_x64 arch/x86/entry/common.c:47 [inline]
+ do_syscall_64+0xbe/0x1a0 arch/x86/entry/common.c:78
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Fix this by freeing an extent changeset before returning from
+btrfs_do_encoded_write().
+
+Fixes: 7c0c7269f7b5 ("btrfs: add BTRFS_IOC_ENCODED_WRITE")
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/inode.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index b1e2b3f732cce..e843531201bef 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -10640,6 +10640,7 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
+ }
+ kvfree(pages);
+ out:
++ extent_changeset_free(data_reserved);
+ if (ret >= 0)
+ iocb->ki_pos += encoded->len;
+ return ret;
+--
+2.53.0
+
--- /dev/null
+From 51898a436ab6cf9ba19ddda9629df0d74d5ec913 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jul 2026 04:29:10 +0000
+Subject: counter: microchip-tcb-capture: Fix DT channel validation
+
+From: Babanpreet Singh <bbnpreetsingh@gmail.com>
+
+[ Upstream commit f1a3a9946aab611dd2200c01ff122f64b033dad2 ]
+
+mchp_tc_probe() reads the devicetree "reg" cell - a u32, per the API
+contract of of_property_read_u32_index() - into a signed int, so the
+bounds check "channel > 2" fails to reject cell values at or above
+0x80000000: reinterpreted as a negative int, they compare below 2 and
+pass validation.
+
+A malformed devicetree can therefore drive a negative channel into the
+ATMEL_TC_REG() offset arithmetic, making the driver access syscon
+regmap offsets outside the TC block's register window, and into the
+"t%d_clk" clock-name formatting, where it truncates clk_name (sized
+for "t0_clk".."t2_clk").
+
+Declare channel as u32, matching the API contract; the unsigned
+comparison then rejects everything except channels 0..2. Adjust the
+format specifier to %u accordingly, which also resolves the W=1
+warning that exposed the gap:
+
+ microchip-tcb-capture.c:520:56: warning: '%d' directive output may
+ be truncated writing between 1 and 11 bytes into a region of size
+ 6 [-Wformat-truncation=]
+ note: directive argument in the range [-2147483648, 2]
+
+No behavior change for well-formed devicetrees: channels 0..2 take
+identical paths before and after.
+
+Fixes: 106b104137fd ("counter: Add microchip TCB capture counter")
+Assisted-by: Claude:claude-fable-5 [gcc W=1]
+Signed-off-by: Babanpreet Singh <bbnpreetsingh@gmail.com>
+Reviewed-by: Joshua Crofts <joshua.crofts1@gmail.com>
+Link: https://lore.kernel.org/r/20260714042910.7-1-bbnpreetsingh@gmail.com
+Signed-off-by: William Breathitt Gray <wbg@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/counter/microchip-tcb-capture.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/counter/microchip-tcb-capture.c b/drivers/counter/microchip-tcb-capture.c
+index 461f57f66631c..fbd1afe178a36 100644
+--- a/drivers/counter/microchip-tcb-capture.c
++++ b/drivers/counter/microchip-tcb-capture.c
+@@ -309,7 +309,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
+ char clk_name[7];
+ struct regmap *regmap;
+ struct clk *clk[3];
+- int channel;
++ u32 channel;
+ int ret, i;
+
+ counter = devm_counter_alloc(&pdev->dev, sizeof(*priv));
+@@ -343,7 +343,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
+
+ priv->channel[i] = channel;
+
+- snprintf(clk_name, sizeof(clk_name), "t%d_clk", channel);
++ snprintf(clk_name, sizeof(clk_name), "t%u_clk", channel);
+
+ clk[i] = of_clk_get_by_name(np->parent, clk_name);
+ if (IS_ERR(clk[i])) {
+--
+2.53.0
+
--- /dev/null
+From 2eff8e639193246e92867212442c17878c78fc13 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 11:06:00 +0300
+Subject: devlink: fix net namespace reference leak in reload
+
+From: Or Har-Toov <ohartoov@nvidia.com>
+
+[ Upstream commit 1c4dac9bf1d2ac31da63b794bdec697777cbd0fd ]
+
+devlink_nl_reload_doit() calls devlink_netns_get(), which returns a net
+with a held reference. When the requested namespace differs from the
+current one and the reload action is not DRIVER_REINIT, the function
+returns -EOPNOTSUPP without releasing the reference. Add the missing
+put_net() on this error path.
+
+Fixes: 2edd92570441 ("devlink: don't allow to change net namespace for FW_ACTIVATE reload action")
+Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
+Reviewed-by: Jiri Pirko <jiri@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Reviewed-by: Antoine Tenart <atenart@kernel.org>
+Link: https://patch.msgid.link/20260729080600.2427721-1-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/devlink/dev.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/devlink/dev.c b/net/devlink/dev.c
+index bba4ace7d22ba..c70d4dc599b85 100644
+--- a/net/devlink/dev.c
++++ b/net/devlink/dev.c
+@@ -505,6 +505,7 @@ int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
+ action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) {
+ NL_SET_ERR_MSG_MOD(info->extack,
+ "Changing namespace is only supported for reinit action");
++ put_net(dest_net);
+ return -EOPNOTSUPP;
+ }
+ }
+--
+2.53.0
+
--- /dev/null
+From 5ef9c8edfca2171a6af04795098a2e9006e3622b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jul 2026 10:38:06 +0800
+Subject: drm/bridge: ps8640: propagate AUX transfer register errors
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 20697ecb299cd77b4cf8b28f655e56606b0472d8 ]
+
+ps8640_aux_transfer_msg() programs the AUX address registers, starts the
+AUX transfer, waits for SWAUX_SEND to clear, and reads the AUX status
+register. Several of those regmap operations have return values, but the
+function only checks a stale ret after the status read.
+
+Propagate failures from the address write, transfer start, completion
+poll, and status read. This avoids returning a transfer length when the
+bridge register transaction or AUX completion wait failed.
+
+Fixes: 13afcdd7277e ("drm/bridge: parade-ps8640: Add support for AUX channel")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Link: https://patch.msgid.link/20260723103509.2-ps8640-v2-pengpeng@iscas.ac.cn
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/bridge/parade-ps8640.c | 27 ++++++++++++++++++++------
+ 1 file changed, 21 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
+index 14d4dcf239da8..61ea855e55d87 100644
+--- a/drivers/gpu/drm/bridge/parade-ps8640.c
++++ b/drivers/gpu/drm/bridge/parade-ps8640.c
+@@ -258,8 +258,14 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
+ addr_len[PAGE0_SWAUX_LENGTH - base] = (len == 0) ? SWAUX_NO_PAYLOAD :
+ ((len - 1) & SWAUX_LENGTH_MASK);
+
+- regmap_bulk_write(map, PAGE0_SWAUX_ADDR_7_0, addr_len,
+- ARRAY_SIZE(addr_len));
++ ret = regmap_bulk_write(map, PAGE0_SWAUX_ADDR_7_0, addr_len,
++ ARRAY_SIZE(addr_len));
++ if (ret) {
++ DRM_DEV_ERROR(dev,
++ "failed to write AUX address %#x, len %zu: %d\n",
++ msg->address, len, ret);
++ return ret;
++ }
+
+ if (len && (request == DP_AUX_NATIVE_WRITE ||
+ request == DP_AUX_I2C_WRITE)) {
+@@ -275,13 +281,22 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
+ }
+ }
+
+- regmap_write(map, PAGE0_SWAUX_CTRL, SWAUX_SEND);
++ ret = regmap_write(map, PAGE0_SWAUX_CTRL, SWAUX_SEND);
++ if (ret) {
++ DRM_DEV_ERROR(dev, "failed to start AUX transfer: %d\n", ret);
++ return ret;
++ }
+
+ /* Zero delay loop because i2c transactions are slow already */
+- regmap_read_poll_timeout(map, PAGE0_SWAUX_CTRL, data,
+- !(data & SWAUX_SEND), 0, 50 * 1000);
++ ret = regmap_read_poll_timeout(map, PAGE0_SWAUX_CTRL, data,
++ !(data & SWAUX_SEND), 0, 50 * 1000);
++ if (ret) {
++ DRM_DEV_ERROR(dev, "failed to complete AUX transfer: %d\n",
++ ret);
++ return ret;
++ }
+
+- regmap_read(map, PAGE0_SWAUX_STATUS, &data);
++ ret = regmap_read(map, PAGE0_SWAUX_STATUS, &data);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to read PAGE0_SWAUX_STATUS: %d\n",
+ ret);
+--
+2.53.0
+
--- /dev/null
+From 5d033fcd110374088eeeb3fcbc4b1dfbaf9b513f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:16:45 +0800
+Subject: hwmon: (ads7828) Fix external VREF regulator handling
+
+From: Qingshuang Fu <fuqingshuang@kylinos.cn>
+
+[ Upstream commit fddb5ceaf901b050ed2a1a7deeecbf97e003435a ]
+
+The driver currently has two issues with the external VREF regulator
+handling in ads7828_probe():
+
+1. All errors from devm_regulator_get_optional() are ignored, causing the
+ driver to incorrectly fall back to internal VREF even for transient
+ errors like -EPROBE_DEFER or genuine failures like -ENOMEM.
+
+2. The external regulator is never enabled. The driver calls
+ regulator_get_voltage() without first calling regulator_enable(),
+ so the VREF pin may remain unpowered if the regulator is not
+ configured as always-on.
+
+Fix both issues by switching to devm_regulator_get_enable_read_voltage(),
+which handles regulator get, enable, and voltage read in one call.
+Only -ENODEV (no regulator specified in device tree) should trigger the
+fallback to internal VREF. All other errors are propagated to the caller.
+
+Fixes: a8ddfea09566 ("hwmon: (ads7828) Accept optional parameters from device tree")
+Signed-off-by: Qingshuang Fu <fuqingshuang@kylinos.cn>
+Link: https://lore.kernel.org/r/20260805061645.1331652-1-fffsqian@163.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ads7828.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
+index 809e830f52a6b..b9ed146a24cc1 100644
+--- a/drivers/hwmon/ads7828.c
++++ b/drivers/hwmon/ads7828.c
+@@ -108,12 +108,11 @@ static int ads7828_probe(struct i2c_client *client)
+ struct ads7828_data *data;
+ struct device *hwmon_dev;
+ unsigned int vref_mv = ADS7828_INT_VREF_MV;
+- unsigned int vref_uv;
++ int vref_uv;
+ bool diff_input = false;
+ bool ext_vref = false;
+ unsigned int regval;
+ enum ads7828_chips chip;
+- struct regulator *reg;
+
+ data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL);
+ if (!data)
+@@ -127,9 +126,11 @@ static int ads7828_probe(struct i2c_client *client)
+ } else if (dev->of_node) {
+ diff_input = of_property_read_bool(dev->of_node,
+ "ti,differential-input");
+- reg = devm_regulator_get_optional(dev, "vref");
+- if (!IS_ERR(reg)) {
+- vref_uv = regulator_get_voltage(reg);
++ vref_uv = devm_regulator_get_enable_read_voltage(dev, "vref");
++ if (vref_uv < 0) {
++ if (vref_uv != -ENODEV)
++ return vref_uv;
++ } else {
+ vref_mv = DIV_ROUND_CLOSEST(vref_uv, 1000);
+ if (vref_mv < ADS7828_EXT_VREF_MV_MIN ||
+ vref_mv > ADS7828_EXT_VREF_MV_MAX)
+--
+2.53.0
+
--- /dev/null
+From 5424e4121c1d38280f8b0800cde1bad04dedb30d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 07:19:20 +0000
+Subject: hwmon: (corsair-psu) fix possible out-of-bounds access on missing
+ string termination
+
+From: Wilken Gottwalt <wilken.gottwalt@posteo.net>
+
+[ Upstream commit 36c4d73ce05d1d8896c2669eb0730d35a02a2ec1 ]
+
+In theory it could be possible that the REPLY_SIZE sized buffers for
+holding the vendor and product strings could be end up missing the null
+termination (for example by malicious hardware built on purpose)
+required by the seq_printf() call. That limits the debugfs printf calls
+to a maximum string length of REPLY_SIZE.
+
+Fixes: d115b51e0e567 ("hwmon: add Corsair PSU HID controller driver")
+Signed-off-by: Wilken Gottwalt <wilken.gottwalt@posteo.net>
+Link: https://lore.kernel.org/r/anLj9gPWRoRDbQBV@monster.localdomain
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/corsair-psu.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c
+index 4ab73bcef1d12..61d1b22bc63ec 100644
+--- a/drivers/hwmon/corsair-psu.c
++++ b/drivers/hwmon/corsair-psu.c
+@@ -709,7 +709,7 @@ static int vendor_show(struct seq_file *seqf, void *unused)
+ {
+ struct corsairpsu_data *priv = seqf->private;
+
+- seq_printf(seqf, "%s\n", priv->vendor);
++ seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->vendor);
+
+ return 0;
+ }
+@@ -719,7 +719,7 @@ static int product_show(struct seq_file *seqf, void *unused)
+ {
+ struct corsairpsu_data *priv = seqf->private;
+
+- seq_printf(seqf, "%s\n", priv->product);
++ seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->product);
+
+ return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From 69369d1e3a5e2d2a3799d97ea3b33fee5757e0df Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Nov 2023 14:57:02 -0600
+Subject: hwmon: (lm25066) Use i2c_get_match_data()
+
+From: Rob Herring <robh@kernel.org>
+
+[ Upstream commit ac0c26bae662138eac9b49215e505b402f7e80e3 ]
+
+Use preferred i2c_get_match_data() instead of of_match_device() and
+i2c_match_id() to get the driver match data. With this, adjust the
+includes to explicitly include the correct headers.
+
+Adjust the 'chips' enum to not use 0, so that no match data can be
+distinguished from a valid enum value.
+
+Signed-off-by: Rob Herring <robh@kernel.org>
+Link: https://lore.kernel.org/r/20231115205703.3730448-3-robh@kernel.org
+[groeck: Use double cast for enum chips assignment to make compiler happy]
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Stable-dep-of: 0dabe8a56f77 ("hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/pmbus/lm25066.c | 14 +++-----------
+ 1 file changed, 3 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c
+index 929fa6d34efdc..3a20df5a43ec8 100644
+--- a/drivers/hwmon/pmbus/lm25066.c
++++ b/drivers/hwmon/pmbus/lm25066.c
+@@ -14,10 +14,10 @@
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
+ #include <linux/log2.h>
+-#include <linux/of_device.h>
++#include <linux/of.h>
+ #include "pmbus.h"
+
+-enum chips { lm25056, lm25066, lm5064, lm5066, lm5066i };
++enum chips { lm25056 = 1, lm25066, lm5064, lm5066, lm5066i };
+
+ #define LM25066_READ_VAUX 0xd0
+ #define LM25066_MFR_READ_IIN 0xd1
+@@ -468,8 +468,6 @@ static int lm25066_probe(struct i2c_client *client)
+ struct lm25066_data *data;
+ struct pmbus_driver_info *info;
+ const struct __coeff *coeff;
+- const struct of_device_id *of_id;
+- const struct i2c_device_id *i2c_id;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA))
+@@ -484,14 +482,8 @@ static int lm25066_probe(struct i2c_client *client)
+ if (config < 0)
+ return config;
+
+- i2c_id = i2c_match_id(lm25066_id, client);
++ data->id = (enum chips)(unsigned long)i2c_get_match_data(client);
+
+- of_id = of_match_device(lm25066_of_match, &client->dev);
+- if (of_id && (unsigned long)of_id->data != i2c_id->driver_data)
+- dev_notice(&client->dev, "Device mismatch: %s in device tree, %s detected\n",
+- of_id->name, i2c_id->name);
+-
+- data->id = i2c_id->driver_data;
+ info = &data->info;
+
+ info->pages = 1;
+--
+2.53.0
+
--- /dev/null
+From 0bd3bc90edec78af41cfba197a5b49b646c8366d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 15:48:42 +0800
+Subject: hwmon: (nzxt-smart2) Check return value of init_device() in probe
+
+From: Qingshuang Fu <fuqingshuang@kylinos.cn>
+
+[ Upstream commit d533882ce1060866a590257f2c77ee23eabef5b8 ]
+
+The init_device() call in nzxt_smart2_hid_probe() can fail because it
+sends HID output reports to the hardware to detect fans and set the
+update interval. If the hardware is not responding or the HID reports
+fail, init_device() returns a negative error code.
+
+However, the return value was ignored, causing the probe to continue
+and register an hwmon device even though the device was never properly
+initialized. This leads to an inconsistent state where the driver
+reports stale data or blocks on wait queues that will never be woken.
+
+The same function's return value is already checked in the
+reset_resume() handler, confirming the author's intent that errors
+should be propagated.
+
+Note that this fix was not possible before commit 59d104b54b0b
+("hwmon: (nzxt-smart2) Stop device IO before calling hid_hw_stop")
+because the out_hw_close error path was missing hid_device_io_stop(),
+which would have opened a use-after-free risk window.
+
+Fixes: 53e68c20aeb1 ("hwmon: add driver for NZXT RGB&Fan Controller/Smart Device v2.")
+Signed-off-by: Qingshuang Fu <fuqingshuang@kylinos.cn>
+Link: https://lore.kernel.org/r/20260804074842.505923-1-fffsqian@163.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/nzxt-smart2.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/nzxt-smart2.c b/drivers/hwmon/nzxt-smart2.c
+index 5bbe6f3f8af48..00c8d3bc3e344 100644
+--- a/drivers/hwmon/nzxt-smart2.c
++++ b/drivers/hwmon/nzxt-smart2.c
+@@ -760,7 +760,11 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev,
+
+ hid_device_io_start(hdev);
+
+- init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS);
++ ret = init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS);
++ if (ret) {
++ dev_err(&hdev->dev, "init_device failed: %d\n", ret);
++ goto out_hw_close;
++ }
+
+ drvdata->hwmon =
+ hwmon_device_register_with_info(&hdev->dev, "nzxtsmart2", drvdata,
+--
+2.53.0
+
--- /dev/null
+From d9116982a429a72f0adbe1fe596b56a601467165 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 14:12:31 -0700
+Subject: hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit 0dabe8a56f772f0ece46d2597799f412c277d874 ]
+
+In lm25066_probe(), the PMBus coefficients for current and power are
+scaled based on the shunt resistor value. The calculation evaluates the
+multiplication using 32-bit arithmetic because info->m is an int and
+shunt is a u32:
+
+static int lm25066_probe(struct i2c_client *client) {
+ ...
+ info->m[PSC_CURRENT_IN] = info->m[PSC_CURRENT_IN] * shunt / 1000;
+ info->m[PSC_POWER] = info->m[PSC_POWER] * shunt / 1000;
+ ...
+}
+
+For large coefficients like 26882 (LM25056) or 15076 (LM5066i), a device
+tree shunt-resistor-micro-ohms value exceeding approximately 159,000
+(159 mOhm, which is physically valid for low-current applications) causes
+the intermediate product to exceed UINT_MAX (4,294,967,295). This results
+in a silent wraparound before the division by 1000.
+
+Furthermore, if the wrapped value has the most significant bit set,
+converting it back to the signed int info->m results in negative
+coefficients. This logic error leads to drastically corrupted current and
+power readings, which can cause erratic thermal or power management
+behavior in the system.
+
+Fix the problem by using 64-bit operations for the multiply/divide
+operations. This can still overflow, but only for unreasonably large
+shunt resistor values.
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Fixes: 94ee5fcc240fe ("hwmon: (pmbus/lm25066) Support configurable sense resistor values")
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/pmbus/lm25066.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c
+index 3a20df5a43ec8..8a94c4cfb5d19 100644
+--- a/drivers/hwmon/pmbus/lm25066.c
++++ b/drivers/hwmon/pmbus/lm25066.c
+@@ -14,6 +14,7 @@
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
+ #include <linux/log2.h>
++#include <linux/math.h>
+ #include <linux/of.h>
+ #include "pmbus.h"
+
+@@ -540,8 +541,8 @@ static int lm25066_probe(struct i2c_client *client)
+ if (of_property_read_u32(client->dev.of_node, "shunt-resistor-micro-ohms", &shunt))
+ shunt = 1000;
+
+- info->m[PSC_CURRENT_IN] = info->m[PSC_CURRENT_IN] * shunt / 1000;
+- info->m[PSC_POWER] = info->m[PSC_POWER] * shunt / 1000;
++ info->m[PSC_CURRENT_IN] = DIV_ROUND_CLOSEST_ULL((u64)info->m[PSC_CURRENT_IN] * shunt, 1000);
++ info->m[PSC_POWER] = DIV_ROUND_CLOSEST_ULL((u64)info->m[PSC_POWER] * shunt, 1000);
+
+ #if IS_ENABLED(CONFIG_SENSORS_LM25066_REGULATOR)
+ /* LM25056 doesn't support OPERATION */
+--
+2.53.0
+
--- /dev/null
+From e74bd05e1da1fbd8de57594226d1a3cfd7bcdabc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 21:35:05 +0300
+Subject: ipvs: avoid out-of-bounds write in ip_vs_nat_icmp
+
+From: Julian Anastasov <ja@ssi.bg>
+
+[ Upstream commit 646922a0379496154e8c8faca4f8e2fd9100cacc ]
+
+Sashiko warns that local attacker can modify the packet
+while it is processed by IPVS. Some places read the
+IP ihl field multiple times which can cause out-of-bounds
+access. One such place is ip_vs_nat_icmp where we
+can write after the validated area.
+
+Fix it by providing ciph argument just like it is done for
+IPv6 and use ciph->len as offset to the embedded transport
+header.
+
+Modify some IPv4 header checks by reading the ihl field
+only once.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Link: https://sashiko.dev/#/patchset/20260722101517.36313-1-ja%40ssi.bg
+Signed-off-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/ip_vs.h | 2 +-
+ net/netfilter/ipvs/ip_vs_core.c | 67 +++++++++++++++++----------------
+ net/netfilter/ipvs/ip_vs_xmit.c | 2 +-
+ 3 files changed, 36 insertions(+), 35 deletions(-)
+
+diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
+index 6935ec09af24d..80110ec025002 100644
+--- a/include/net/ip_vs.h
++++ b/include/net/ip_vs.h
+@@ -1707,7 +1707,7 @@ static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp)
+
+ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct ip_vs_conn *cp, int dir, unsigned int toff,
+- bool has_ports);
++ bool has_ports, struct ip_vs_iphdr *ciph);
+
+ #ifdef CONFIG_IP_VS_IPV6
+ void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
+diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
+index e49a4840effb3..9c32d346e8400 100644
+--- a/net/netfilter/ipvs/ip_vs_core.c
++++ b/net/netfilter/ipvs/ip_vs_core.c
+@@ -747,28 +747,27 @@ static int ip_vs_route_me_harder(struct netns_ipvs *ipvs, int af,
+ */
+ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct ip_vs_conn *cp, int inout, unsigned int toff,
+- bool has_ports)
++ bool has_ports, struct ip_vs_iphdr *ciph)
+ {
+ struct iphdr *iph = ip_hdr(skb);
+ struct icmphdr *icmph = (struct icmphdr *)(skb->data + toff);
+- struct iphdr *ciph = (struct iphdr *)(icmph + 1);
+- unsigned int coff __maybe_unused = toff + sizeof(struct icmphdr);
++ struct iphdr *cih = (struct iphdr *)(icmph + 1);
+
+ if (inout) {
+ iph->saddr = cp->vaddr.ip;
+ ip_send_check(iph);
+- ciph->daddr = cp->vaddr.ip;
+- ip_send_check(ciph);
++ cih->daddr = cp->vaddr.ip;
++ ip_send_check(cih);
+ } else {
+ iph->daddr = cp->daddr.ip;
+ ip_send_check(iph);
+- ciph->saddr = cp->daddr.ip;
+- ip_send_check(ciph);
++ cih->saddr = cp->daddr.ip;
++ ip_send_check(cih);
+ }
+
+ /* the TCP/UDP/SCTP port */
+ if (has_ports) {
+- __be16 *ports = (void *)ciph + ciph->ihl*4;
++ __be16 *ports = (void *)(skb->data + ciph->len);
+
+ if (inout)
+ ports[1] = cp->vport;
+@@ -782,10 +781,10 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ if (inout)
+- IP_VS_DBG_PKT(11, AF_INET, pp, skb, coff,
++ IP_VS_DBG_PKT(11, AF_INET, pp, skb, ciph->off,
+ "Forwarding altered outgoing ICMP");
+ else
+- IP_VS_DBG_PKT(11, AF_INET, pp, skb, coff,
++ IP_VS_DBG_PKT(11, AF_INET, pp, skb, ciph->off,
+ "Forwarding altered incoming ICMP");
+ }
+
+@@ -878,7 +877,7 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
+ ip_vs_nat_icmp_v6(skb, pp, cp, 1, toff, has_ports, ciph);
+ else
+ #endif
+- ip_vs_nat_icmp(skb, pp, cp, 1, toff, has_ports);
++ ip_vs_nat_icmp(skb, pp, cp, 1, toff, has_ports, ciph);
+
+ if (ip_vs_route_me_harder(cp->ipvs, af, skb, hooknum))
+ goto out;
+@@ -914,7 +913,7 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ struct ip_vs_iphdr ciph;
+ struct ip_vs_conn *cp;
+ struct ip_vs_protocol *pp;
+- unsigned int offset, ihl;
++ unsigned int offset;
+ union nf_inet_addr snet;
+
+ *related = 1;
+@@ -927,7 +926,6 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ return NF_ACCEPT;
+ }
+
+- ihl = ipvsh->len;
+ offset = ipvsh->len;
+ ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
+ if (ic == NULL)
+@@ -953,11 +951,15 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+
+ /* Now find the contained IP header */
+ offset += sizeof(_icmph);
++ if (!ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, true, &ciph))
++ return NF_ACCEPT; /* The packet looks wrong, ignore */
++
+ cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+- if (!(cih && cih->version == 4 && cih->ihl >= 5))
++ if (!(cih && cih->version == 4 &&
++ ciph.len - ciph.off >= sizeof(struct iphdr)))
+ return NF_ACCEPT; /* The packet looks wrong, ignore */
+
+- pp = ip_vs_proto_get(cih->protocol);
++ pp = ip_vs_proto_get(ciph.protocol);
+ if (!pp)
+ return NF_ACCEPT;
+
+@@ -968,8 +970,6 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ IP_VS_DBG_PKT(11, AF_INET, pp, skb, offset,
+ "Checking outgoing ICMP for");
+
+- ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, true, &ciph);
+-
+ /* The embedded headers contain source and dest in reverse order */
+ cp = INDIRECT_CALL_1(pp->conn_out_get, ip_vs_conn_out_get_proto,
+ ipvs, AF_INET, skb, &ciph);
+@@ -977,8 +977,8 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ return NF_ACCEPT;
+
+ snet.ip = ipvsh->saddr.ip;
+- return handle_response_icmp(AF_INET, skb, &snet, cp, pp, &ciph, ihl,
+- hooknum);
++ return handle_response_icmp(AF_INET, skb, &snet, cp, pp, &ciph,
++ ipvsh->len, hooknum);
+ }
+
+ #ifdef CONFIG_IP_VS_IPV6
+@@ -1621,10 +1621,12 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ /* Now find the contained IP header */
+ offset += sizeof(_icmph);
+ cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+- if (!(cih && cih->version == 4 && cih->ihl >= 5))
++ if (!cih)
+ return NF_ACCEPT; /* The packet looks wrong, ignore */
+- raddr = (union nf_inet_addr *)&cih->daddr;
+ hlen_ipip = cih->ihl * 4;
++ if (!(cih->version == 4 && hlen_ipip >= sizeof(struct iphdr)))
++ return NF_ACCEPT; /* The packet looks wrong, ignore */
++ raddr = (union nf_inet_addr *)&cih->daddr;
+
+ /* Special case for errors for IPIP/UDP/GRE tunnel packets */
+ tunnel = false;
+@@ -1641,9 +1643,6 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ if (!dest || dest->tun_type != IP_VS_CONN_F_TUNNEL_TYPE_IPIP)
+ return NF_ACCEPT;
+ offset += hlen_ipip;
+- cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+- if (!(cih && cih->version == 4 && cih->ihl >= 5))
+- return NF_ACCEPT; /* The packet looks wrong, ignore */
+ tunnel = true;
+ } else if ((cih->protocol == IPPROTO_UDP || /* Can be UDP encap */
+ cih->protocol == IPPROTO_GRE) && /* Can be GRE encap */
+@@ -1668,21 +1667,25 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ /* Skip IP and UDP/GRE tunnel headers */
+ offset = offset2 + ulen;
+ /* Now we should be at the original IP header */
+- cih = skb_header_pointer(skb, offset, sizeof(_ciph),
+- &_ciph);
+- if (cih && cih->version == 4 && cih->ihl >= 5 &&
+- iproto == IPPROTO_IPIP)
++ if (iproto == IPPROTO_IPIP)
+ tunnel = true;
+ else
+ return NF_ACCEPT;
+ }
+ }
+
+- pd = ip_vs_proto_data_get(ipvs, cih->protocol);
++ if (!ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, !tunnel, &ciph))
++ return NF_ACCEPT;
++ pd = ip_vs_proto_data_get(ipvs, ciph.protocol);
+ if (!pd)
+ return NF_ACCEPT;
+ pp = pd->pp;
+
++ cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
++ if (!(cih && cih->version == 4 &&
++ ciph.len - ciph.off >= sizeof(struct iphdr)))
++ return NF_ACCEPT; /* The packet looks wrong, ignore */
++
+ /* Is the embedded protocol header present? */
+ if (unlikely(cih->frag_off & htons(IP_OFFSET) && !pp->dont_defrag))
+ return NF_ACCEPT;
+@@ -1690,9 +1693,6 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ IP_VS_DBG_PKT(11, AF_INET, pp, skb, offset,
+ "Checking incoming ICMP for");
+
+- offset2 = offset;
+- ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, !tunnel, &ciph);
+-
+ /* The embedded headers contain source and dest in reverse order.
+ * For IPIP/UDP/GRE tunnel this is error for request, not for reply.
+ */
+@@ -1722,11 +1722,12 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ }
+
+ if (tunnel) {
+- unsigned int hlen_orig = cih->ihl * 4;
++ unsigned int hlen_orig = ciph.len - ciph.off;
+ __be32 info = ic->un.gateway;
+ __u8 type = ic->type;
+ __u8 code = ic->code;
+
++ offset2 = offset;
+ /* Update the MTU */
+ if (ic->type == ICMP_DEST_UNREACH &&
+ ic->code == ICMP_FRAG_NEEDED) {
+diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
+index c214e5d05524c..5b37e92df02c5 100644
+--- a/net/netfilter/ipvs/ip_vs_xmit.c
++++ b/net/netfilter/ipvs/ip_vs_xmit.c
+@@ -1551,7 +1551,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
+ if (skb_cow(skb, rt->dst.dev->hard_header_len))
+ goto tx_error;
+
+- ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports);
++ ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports, ciph);
+
+ /* Another hack: avoid icmp_send in ip_fragment */
+ skb->ignore_df = 1;
+--
+2.53.0
+
--- /dev/null
+From 216d0c71944fb1b2bc5cc20ebeaec4c34a8208f2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 21:35:06 +0300
+Subject: ipvs: return the csum validation for forward hook
+
+From: Julian Anastasov <ja@ssi.bg>
+
+[ Upstream commit 99609cb0aa789c8d071050ce8579989551882cc6 ]
+
+Sashiko notes that playing games with the skb dst and rt
+flags instead of providing hooknum is not a good idea
+when validating the checksums.
+
+Also, skipping checksum validation for FORWARD packets
+risk silent data corruption, even if the only user is
+the FTP-CMD packets coming from the real server.
+
+Sashiko also noticed that by using common checksum
+helper in the previous commit we actually fixed old bug
+where the TCP/UDP checksum for IPv6 on CHECKSUM_COMPLETE
+was not validated correctly.
+
+Fixes: e876b75b9020 ("ipvs: fix the checksum validations")
+Link: https://sashiko.dev/#/patchset/20260722211420.153933-1-pablo%40netfilter.org
+Link: https://sashiko.dev/#/patchset/20260727185024.67534-1-ja%40ssi.bg
+Link: https://sashiko.dev/#/patchset/20260728202520.59179-1-ja%40ssi.bg
+Signed-off-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/ip_vs.h | 19 +++++--------------
+ net/netfilter/ipvs/ip_vs_proto_sctp.c | 2 +-
+ 2 files changed, 6 insertions(+), 15 deletions(-)
+
+diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
+index 80110ec025002..1121845bcc2a6 100644
+--- a/include/net/ip_vs.h
++++ b/include/net/ip_vs.h
+@@ -24,9 +24,7 @@
+ #include <linux/netfilter.h> /* for union nf_inet_addr */
+ #include <linux/ip.h>
+ #include <linux/ipv6.h> /* for struct ipv6hdr */
+-#include <net/route.h>
+ #include <net/ipv6.h>
+-#include <net/ip6_fib.h>
+ #if IS_ENABLED(CONFIG_NF_CONNTRACK)
+ #include <net/netfilter/nf_conntrack.h>
+ #endif
+@@ -1740,30 +1738,23 @@ static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum)
+ return csum_partial(diff, sizeof(diff), oldsum);
+ }
+
+-static inline bool ip_vs_checksum_needed(struct sk_buff *skb, int af)
++static inline bool ip_vs_checksum_needed(struct sk_buff *skb)
+ {
+ /* Checksum unnecessary or already validated? */
+ if (skb_csum_unnecessary(skb))
+ return false;
+- /* LOCAL_OUT ? */
+- if (!skb->dev || skb->dev->flags & IFF_LOOPBACK)
++ /* Locally generated ? */
++ if (!skb->dev)
+ return false;
+- /* !LOCAL_IN (FORWARD) ? */
+- if (af == AF_INET6) {
+- if (!(dst_rt6_info(skb_dst(skb))->rt6i_flags & RTF_LOCAL))
+- return false;
+- } else {
+- if (!(skb_rtable(skb)->rt_flags & RTCF_LOCAL))
+- return false;
+- }
+ return true;
+ }
+
+ static inline bool ip_vs_checksum_common_check(struct sk_buff *skb,
+ int offset, int proto, int af)
+ {
+- if (!ip_vs_checksum_needed(skb, af))
++ if (!ip_vs_checksum_needed(skb))
+ return true;
++ /* Validate csum even for FORWARD */
+ return !nf_checksum(skb, NF_INET_LOCAL_IN, offset, proto, af);
+ }
+
+diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
+index 3dbd3096e1637..c80567c73469b 100644
+--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
++++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
+@@ -193,7 +193,7 @@ sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct sctphdr *sh;
+ __le32 cmp, val;
+
+- if (!ip_vs_checksum_needed(skb, af))
++ if (!ip_vs_checksum_needed(skb))
+ return 1;
+ sh = (struct sctphdr *)(skb->data + sctphoff);
+ cmp = sh->checksum;
+--
+2.53.0
+
--- /dev/null
+From 4962d904a54474e882985fd09f2fb9c7bc6cc78b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 13:15:08 +0000
+Subject: net/atm: fix slab-out-of-bounds read in vcc_setsockopt()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit d0c80dbb970439bd2eeb0e5effff8c16a5f4e1e3 ]
+
+vcc_setsockopt() contained an ineffective optlen check:
+ if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
+ return -EINVAL;
+
+If __SO_LEVEL_MATCH(optname, level) evaluated to false (e.g. if the caller
+passed a mismatched level), the length check optlen != __SO_SIZE(optname)
+was short-circuited and bypassed. Execution then fell through to switch(optname),
+calling copy_from_sockptr() assuming optval contained sufficient space.
+
+Furthermore, even if level matched, a cgroup BPF setsockopt filter could shrink
+optlen after entry. Because copy_from_sockptr() on kernel pointers uses memcpy(),
+this leads to a KASAN slab-out-of-bounds read when optlen is smaller than the
+expected structure size.
+
+Fix this by using copy_safe_from_sockptr(), which unconditionally validates
+that optlen is at least the expected size before copying. Also change the local
+'value' variable type from 'unsigned long' to 'int' so that SO_SETCLP matches
+its sizeof(int) ABI encoding on 64-bit systems.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: syzbot+53ecc09fb81df10ef4de@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=53ecc09fb81df10ef4de
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260805131508.3227331-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/atm/common.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/net/atm/common.c b/net/atm/common.c
+index 96f680a45e306..f3f68c231935a 100644
+--- a/net/atm/common.c
++++ b/net/atm/common.c
+@@ -760,7 +760,7 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
+ sockptr_t optval, unsigned int optlen)
+ {
+ struct atm_vcc *vcc;
+- unsigned long value;
++ int value;
+ int error;
+
+ if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
+@@ -772,8 +772,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
+ {
+ struct atm_qos qos;
+
+- if (copy_from_sockptr(&qos, optval, sizeof(qos)))
+- return -EFAULT;
++ error = copy_safe_from_sockptr(&qos, sizeof(qos), optval,
++ optlen);
++ if (error)
++ return error;
+ error = check_qos(&qos);
+ if (error)
+ return error;
+@@ -786,8 +788,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
+ return 0;
+ }
+ case SO_SETCLP:
+- if (copy_from_sockptr(&value, optval, sizeof(value)))
+- return -EFAULT;
++ error = copy_safe_from_sockptr(&value, sizeof(value), optval,
++ optlen);
++ if (error)
++ return error;
+ if (value)
+ vcc->atm_options |= ATM_ATMOPT_CLP;
+ else
+--
+2.53.0
+
--- /dev/null
+From 923e2e30e6ae64462806cc2e9535e47ce567f000 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 12:17:10 +0400
+Subject: net: hisilicon: hix5hd2_gmac: remove redundant NAPI delete
+
+From: Jiawen Liu <1298662399@qq.com>
+
+[ Upstream commit f307a7dc32097c11413178fca437a10d20890bc2 ]
+
+hix5hd2_dev_remove() calls netif_napi_del() before unregister_netdev().
+This is not needed because free_netdev() deletes all NAPI instances
+attached to the net_device.
+
+Remove the redundant call and let the networking core tear down the NAPI
+instance during unregister_netdev(). The probe error path still keeps its
+explicit netif_napi_del(), because the device has not been registered
+there.
+
+Fixes: 57c5bc9ad7d7 ("net: hisilicon: add hix5hd2 mac driver")
+Signed-off-by: Jiawen Liu <1298662399@qq.com>
+Link: https://patch.msgid.link/tencent_5FFD37A252B4FEA6A80AD25B17C8E904F005@qq.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hix5hd2_gmac.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+index 26d22bb04b879..e8cedc2608654 100644
+--- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
++++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+@@ -1287,7 +1287,6 @@ static int hix5hd2_dev_remove(struct platform_device *pdev)
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct hix5hd2_priv *priv = netdev_priv(ndev);
+
+- netif_napi_del(&priv->napi);
+ unregister_netdev(ndev);
+ mdiobus_unregister(priv->bus);
+ mdiobus_free(priv->bus);
+--
+2.53.0
+
--- /dev/null
+From 2e456ce684daae5f535abff9cdb7525703e1bfc6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 11:04:02 +0300
+Subject: net/mlx5: fw_tracer, return NULL on create error
+
+From: Michael Guralnik <michaelgur@nvidia.com>
+
+[ Upstream commit af39eb111ce6b5eba9c08513b62c4868eb7e7fd5 ]
+
+Tracer creation can fail by returning either NULL or ERR_PTR.
+The return value is stored without a check on the device, and users
+treat ERR_PTR and NULL the same way.
+This also causes a crash in the core dump logic, which is missing the
+ERR_PTR check and ends up dereferencing it, as shown in the trace below.
+
+Switch tracer creation to return NULL on failure only, so callers only
+need a single NULL check.
+
+ Internal error: Oops: 0000000096000006 [#1] SMP
+ Modules linked in: mlx5_ib ib_uverbs ib_core ipv6 mlx5_core
+ CPU: 1 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted 6.19.7 #1 PREEMPT(none)
+ Workqueue: mlx5_health0001:01:00.0 mlx5_fw_reporter_err_work [mlx5_core]
+ pstate: a3400009 (NzCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
+ pc : mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core]
+ lr : mlx5_fw_tracer_trigger_core_dump_general+0x40/0xe0 [mlx5_core]
+ sp : ffff800081cf3c40
+ x29: ffff800081cf3c90 x28: 0000000000000000 x27: 0000000000000000
+ x26: ffff000080018828 x25: 0000000000000000 x24: ffff000080304a05
+ x23: ffff800081cf3d80 x22: ffff0000847e01a0 x21: 0000000000000000
+ x20: ffff0000847e01a0 x19: ffffffffffffffa1 x18: ffff80008310bbf0
+ x17: ffff800080119650 x16: ffff80008010df54 x15: ffff80008010d4ac
+ x14: ffff800079c202e4 x13: ffff80008002fe60 x12: ffff800080119650
+ x11: ffff80008010df54 x10: ffff80008010d4ac x9 : ffff800079c203d8
+ x8 : ffff800081cf3c88 x7 : 0000000000000000 x6 : 0000000000000000
+ x5 : 0000000000000000 x4 : 0000000000000008 x3 : 0000000000000030
+ x2 : 0000000000000008 x1 : 0000000000000000 x0 : 00000000c5c4000e
+ Call trace:
+ mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core] (P)
+ mlx5_fw_reporter_dump+0x30/0x2e0 [mlx5_core]
+ devlink_health_do_dump+0x9c/0x160
+ devlink_health_report+0x1c0/0x288
+ mlx5_fw_reporter_err_work+0xac/0xc0 [mlx5_core]
+ process_one_work+0x15c/0x3d8
+ worker_thread+0x18c/0x320
+ kthread+0x148/0x228
+ ret_from_fork+0x10/0x20
+ Code: b9400000 5ac00800 7a401800 540003ca (3940a260)
+ ---[ end trace 0000000000000000 ]---
+ Kernel panic - not syncing: Oops: Fatal exception
+ SMP: stopping secondary CPUs
+ Kernel Offset: disabled
+ CPU features: 0x000000,00078031,75fce5a1,35fffe67
+ Memory Limit: none
+ ---[ end Kernel panic - not syncing: Oops: Fatal exception ]---
+
+Fixes: fd1483fe1f9f ("net/mlx5: Add support for FW reporter dump")
+Signed-off-by: Michael Guralnik <michaelgur@nvidia.com>
+Reviewed-by: Shay Drori <shayd@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260729080402.2427184-1-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ethernet/mellanox/mlx5/core/diag/fw_tracer.c | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+index 0a33ab5f53fd3..dba0d73ac37d5 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+@@ -1050,13 +1050,11 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
+
+ tracer = kvzalloc(sizeof(*tracer), GFP_KERNEL);
+ if (!tracer)
+- return ERR_PTR(-ENOMEM);
++ return NULL;
+
+ tracer->work_queue = create_singlethread_workqueue("mlx5_fw_tracer");
+- if (!tracer->work_queue) {
+- err = -ENOMEM;
++ if (!tracer->work_queue)
+ goto free_tracer;
+- }
+
+ tracer->dev = dev;
+
+@@ -1098,7 +1096,7 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
+ destroy_workqueue(tracer->work_queue);
+ free_tracer:
+ kvfree(tracer);
+- return ERR_PTR(err);
++ return NULL;
+ }
+
+ static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data);
+@@ -1109,7 +1107,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
+ struct mlx5_core_dev *dev;
+ int err;
+
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return 0;
+
+ if (!tracer->str_db.loaded)
+@@ -1159,7 +1157,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
+ /* Stop tracer + Cleanup HW resources */
+ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
+ {
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return;
+
+ mutex_lock(&tracer->state_lock);
+@@ -1188,7 +1186,7 @@ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
+ /* Free software resources (Buffers, etc ..) */
+ void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer)
+ {
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return;
+
+ mlx5_core_dbg(tracer->dev, "FWTracer: Destroy\n");
+@@ -1240,7 +1238,7 @@ int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer)
+ struct mlx5_core_dev *dev;
+ int err;
+
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return 0;
+
+ dev = tracer->dev;
+--
+2.53.0
+
--- /dev/null
+From 8ca54dc66807bcce17a66462f3b80e06e5e1eb47 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 07:43:38 +0300
+Subject: net/mlx5e: TC, Check if flow is PEER before acquiring devcom lock
+
+From: Shay Drory <shayd@nvidia.com>
+
+[ Upstream commit 6ddfba2ea98db21b001e0e5c472499156224650c ]
+
+In case __mlx5e_add_fdb_flow() fails in lower levels, the flow is
+deleted via mlx5e_tc_del_flow(), and mlx5e_tc_del_flow() is acquiring
+ESW devcom lock without condition. In addition, in case of peer_flow,
+__mlx5e_add_fdb_flow() is called while holding ESW devcom comp lock.
+This results in an AA deadlock.
+
+To fix this, introduce a new PEER flag that is set on flows created as
+peer flows (the duplicate flows on peer devices), and check it in
+mlx5e_tc_del_flow() before acquiring ESW devcom lock.
+
+Lockdep splat:
+============================================
+WARNING: possible recursive locking detected
+============================================
+ Possible unsafe locking scenario:
+ CPU0
+ ----
+ lock(&comp->lock_key#2);
+ lock(&comp->lock_key#2);
+ *** DEADLOCK ***
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0x69/0xa0
+ print_deadlock_bug.cold+0xbd/0xca
+ __lock_acquire+0x1671/0x2ec0
+ lock_acquire+0x10e/0x2e0
+ down_read+0x95/0x430
+ mlx5_devcom_for_each_peer_begin+0x4e/0xe0 [mlx5_core]
+ mlx5e_tc_del_flow+0x11d/0xa70 [mlx5_core]
+ mlx5e_flow_put+0x99/0x100 [mlx5_core]
+ __mlx5e_add_fdb_flow+0x409/0xf00 [mlx5_core]
+ mlx5e_configure_flower+0x2a86/0x4100 [mlx5_core]
+ mlx5e_rep_setup_tc_cls_flower+0x12f/0x1b0 [mlx5_core]
+ mlx5e_rep_setup_tc_cb+0x153/0x750 [mlx5_core]
+ tc_setup_cb_add+0x1dc/0x470
+ fl_change+0x2f4d/0x626d [cls_flower]
+ tc_new_tfilter+0x79b/0x2310
+ rtnetlink_rcv_msg+0x778/0xad0
+ do_syscall_64+0x70/0x960
+ entry_SYSCALL_64_after_hwframe+0x4b/0x53
+ </TASK>
+
+Fixes: 04de7dda7394 ("net/mlx5e: Infrastructure for duplicated offloading of TC flows")
+Signed-off-by: Shay Drory <shayd@nvidia.com>
+Reviewed-by: Cosmin Ratiu <cratiu@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260728044338.2271143-1-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h | 1 +
+ drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 4 +++-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
+index 6cc23af66b5be..a23d0df42f027 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
+@@ -30,6 +30,7 @@ enum {
+ MLX5E_TC_FLOW_FLAG_FAILED = MLX5E_TC_FLOW_BASE + 9,
+ MLX5E_TC_FLOW_FLAG_SAMPLE = MLX5E_TC_FLOW_BASE + 10,
+ MLX5E_TC_FLOW_FLAG_USE_ACT_STATS = MLX5E_TC_FLOW_BASE + 11,
++ MLX5E_TC_FLOW_FLAG_PEER = MLX5E_TC_FLOW_BASE + 12,
+ };
+
+ struct mlx5e_tc_flow_parse_attr {
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+index f1f4225057311..8c52bbeabb7e0 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+@@ -2043,7 +2043,8 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
+ if (mlx5e_is_eswitch_flow(flow)) {
+ struct mlx5_devcom_comp_dev *devcom = flow->priv->mdev->priv.eswitch->devcom;
+
+- if (!mlx5_devcom_for_each_peer_begin(devcom)) {
++ if (flow_flag_test(flow, PEER) ||
++ !mlx5_devcom_for_each_peer_begin(devcom)) {
+ mlx5e_tc_del_fdb_flow(priv, flow);
+ return;
+ }
+@@ -4489,6 +4490,7 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f,
+ else
+ in_mdev = priv->mdev;
+
++ flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_PEER);
+ parse_attr = flow->attr->parse_attr;
+ peer_flow = __mlx5e_add_fdb_flow(peer_priv, f, flow_flags,
+ parse_attr->filter_dev,
+--
+2.53.0
+
--- /dev/null
+From 4bced815c3e2adf53e2ac833258c811ab8ffb06b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 12:36:18 +0800
+Subject: net/ncsi: fix heap OOB read in NCSI_CMD_SEND_CMD payload length
+
+From: Henry Martin <bsdhenrymartin@gmail.com>
+
+[ Upstream commit afa58b7384913c8773d837acdb07b035690ec5d2 ]
+
+ncsi_send_cmd_nl() takes the number of bytes to copy from the
+attacker-controlled ncsi_pkt_hdr.length field of the in-band packet
+header, while the source buffer is the NCSI_ATTR_DATA netlink
+attribute whose readable size is nla_len() - sizeof(ncsi_pkt_hdr).
+The two length sources are never cross-checked: only
+nla_len() >= sizeof(struct ncsi_pkt_hdr) is enforced.
+
+With hdr->length set larger than the attribute payload (up to 65535
+against at most 2032 readable bytes), ncsi_cmd_handler_oem() copies
+past the end of the netlink attribute buffer with unsafe_memcpy(),
+leaking up to ~64KB of kernel heap memory into the transmitted NCSI
+command packet. The destination skb is sized by the declared payload,
+so the write side does not overflow - this is a pure OOB read /
+information leak, reachable with CAP_NET_ADMIN on systems with a
+registered NCSI device (e.g. OpenBMC on Aspeed BMC SoCs, where
+NET_NCSI=y is standard).
+
+Reject commands whose declared payload extends past the end of the
+data attribute.
+
+The issue was found by the autokbug dynamic kernel fuzzer at Tencent
+Yunding Lab.
+
+Fixes: 9771b8ccdfa6 ("net/ncsi: Extend NC-SI Netlink interface to allow user space to send NC-SI command")
+Reported-by: Henry Martin <bsdhenrymartin@gmail.com>
+Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>
+Link: https://patch.msgid.link/20260803043618.3210301-1-bsdhenrymartin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ncsi/ncsi-netlink.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/net/ncsi/ncsi-netlink.c b/net/ncsi/ncsi-netlink.c
+index 2f872d064396d..8cc538358f6a3 100644
+--- a/net/ncsi/ncsi-netlink.c
++++ b/net/ncsi/ncsi-netlink.c
+@@ -461,6 +461,10 @@ static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info)
+ nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN;
+ nca.info = info;
+ nca.payload = ntohs(hdr->length);
++ if (nca.payload > len - sizeof(*hdr)) {
++ ret = -EINVAL;
++ goto out_netlink;
++ }
+ nca.data = data + sizeof(*hdr);
+
+ ret = ncsi_xmit_cmd(&nca);
+--
+2.53.0
+
--- /dev/null
+From a045441708444ca097bbe8358aebfc6fd7996bbd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 18:20:06 -0400
+Subject: net/openvswitch: check Ethernet header length in key_extract()
+
+From: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+
+[ Upstream commit cf6f8b29befb92173659bcef6a441d274947bfae ]
+
+When a packet arrives on an ARPHRD_NONE device (e.g. TUN),
+ovs_flow_key_extract() trusts the user-provided skb->protocol field: if
+it is ETH_P_TEB, the packet is classified as MAC_PROTO_ETHERNET and
+key_extract() is called without ensuring the skb has ETH_HLEN (14) bytes
+of linear data. key_extract() unconditionally pulls 2 * ETH_ALEN bytes
+for MAC addresses and parse_ethertype() pulls 2 more, either of which
+triggers a kernel BUG in __skb_pull() when the linear area is too small.
+
+ kernel BUG at include/linux/skbuff.h:2848!
+ RIP: 0010:key_extract+0xa7e/0xd90 net/openvswitch/flow.c:933
+ ovs_flow_key_extract+0x419/0xa70
+ ovs_vport_receive+0x222/0x390
+ netdev_frame_hook+0x3e0/0x630
+ tun_get_user+0x2d0c/0x38e0
+
+Fixed by calling check_header() in key_extract() before accessing the
+Ethernet header.
+
+Fixes: 217ac77a3c25 ("openvswitch: allow L3 netdev ports")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Reviewed-by: Eelco Chaudron <echaudro@redhat.com>
+Signed-off-by: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
+Link: https://patch.msgid.link/20260730222006.118652-1-blbllhy@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/flow.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
+index b80bd3a907739..52e261ce91e8e 100644
+--- a/net/openvswitch/flow.c
++++ b/net/openvswitch/flow.c
+@@ -893,8 +893,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ * Ethernet header
+ * @key: output flow key
+ *
+- * The caller must ensure that skb->len >= ETH_HLEN.
+- *
+ * Initializes @skb header fields as follows:
+ *
+ * - skb->mac_header: the L2 header.
+@@ -914,8 +912,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ */
+ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+ {
+- struct ethhdr *eth;
+-
+ /* Flags are always used as part of stats */
+ key->tp.flags = 0;
+
+@@ -930,6 +926,13 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+ skb_reset_network_header(skb);
+ key->eth.type = skb->protocol;
+ } else {
++ struct ethhdr *eth;
++ int err;
++
++ err = check_header(skb, ETH_HLEN);
++ if (unlikely(err))
++ return err;
++
+ eth = eth_hdr(skb);
+ ether_addr_copy(key->eth.src, eth->h_source);
+ ether_addr_copy(key->eth.dst, eth->h_dest);
+--
+2.53.0
+
--- /dev/null
+From 7e9094dca48e787324492070d823bddf0b571b43 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 22:19:06 +0800
+Subject: net: prestera: validate firmware header length
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 8ae344eb540af3f457179b52bc6061416752485c ]
+
+prestera_fw_hdr_parse() reads the firmware header before checking
+that the firmware image contains that header.
+
+Reject images shorter than struct prestera_fw_header before decoding the
+magic and version fields.
+
+Fixes: 4c2703dfd7fabb ("net: marvell: prestera: Add PCI interface support")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Acked-by: Elad Nachman <enachman@marvell.com>
+Link: https://patch.msgid.link/20260731141500.1-prestera-v2-pengpeng@iscas.ac.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/marvell/prestera/prestera_pci.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/marvell/prestera/prestera_pci.c b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+index 35857dc19542f..5db2c9e5e077d 100644
+--- a/drivers/net/ethernet/marvell/prestera/prestera_pci.c
++++ b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+@@ -684,6 +684,9 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw)
+ struct prestera_fw_header *hdr;
+ u32 magic;
+
++ if (fw->bin->size < sizeof(*hdr))
++ return -EINVAL;
++
+ hdr = (struct prestera_fw_header *)fw->bin->data;
+
+ magic = be32_to_cpu(hdr->magic_number);
+--
+2.53.0
+
--- /dev/null
+From 522df6435251270ad6c72cd23231abc38e59640b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 15:20:48 +0000
+Subject: net: remove WARN_ON_ONCE() from sk_mc_loop()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit b8a39a09ae4eaae04309e1e38ed6a1101d967496 ]
+
+sk_mc_loop() can be called for sockets that are neither AF_INET
+nor AF_INET6 (e.g. AF_PACKET sockets when sending packets via raw/packet
+socket over virtual devices such as VRF or ipvlan).
+
+In such cases, sk_family is not AF_INET/AF_INET6 and sk_mc_loop() falls
+through the switch statement and triggers WARN_ON_ONCE(1).
+
+Non-INET sockets do not support IP_MULTICAST_LOOP or IPV6_MULTICAST_LOOP
+options, so loopback should default to true without generating a warning.
+
+Fixes: f60e5990d9c1 ("ipv6: protect skb->sk accesses from recursive dereference inside the stack")
+Reported-by: syzbot+22c3218a6fa219e47321@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/6a72024c.13623e66.bdc14.0019.GAE@google.com/T/#u
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260804152048.2134341-1-edumazet@google.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/sock.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/net/core/sock.c b/net/core/sock.c
+index 87e6060c8bca7..846e95805c199 100644
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -776,7 +776,6 @@ bool sk_mc_loop(struct sock *sk)
+ return inet6_sk(sk)->mc_loop;
+ #endif
+ }
+- WARN_ON_ONCE(1);
+ return true;
+ }
+ EXPORT_SYMBOL(sk_mc_loop);
+--
+2.53.0
+
--- /dev/null
+From f9b2cd440597e1f6e9864e5f0d66be4080ceefd1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 25 Mar 2024 20:47:35 +0000
+Subject: net: sched: cls_api: add filter counter
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Asbjørn Sloth Tønnesen <ast@fiberby.net>
+
+[ Upstream commit 2081fd3445fec6b9813c20e8b910c2abd6de31cb ]
+
+Maintain a count of filters per block.
+
+Counter updates are protected by cb_lock, which is
+also used to protect the offload counters.
+
+Signed-off-by: Asbjørn Sloth Tønnesen <ast@fiberby.net>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Reviewed-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: a347304b2ca1 ("net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/sch_generic.h | 2 ++
+ net/sched/cls_api.c | 19 +++++++++++++++++++
+ 2 files changed, 21 insertions(+)
+
+diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
+index 5df841ed0aeaa..a94ff63e3cd5b 100644
+--- a/include/net/sch_generic.h
++++ b/include/net/sch_generic.h
+@@ -429,6 +429,7 @@ struct tcf_proto {
+ */
+ spinlock_t lock;
+ bool deleting;
++ bool counted;
+ refcount_t refcnt;
+ struct rcu_head rcu;
+ struct hlist_node destroy_ht_node;
+@@ -477,6 +478,7 @@ struct tcf_block {
+ struct flow_block flow_block;
+ struct list_head owner_list;
+ bool keep_dst;
++ atomic_t filtercnt; /* Number of filters */
+ atomic_t skipswcnt; /* Number of skip_sw filters */
+ atomic_t offloadcnt; /* Number of oddloaded filters */
+ unsigned int nooffloaddevcnt; /* Number of devs unable to do offload */
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index 792e7040ebc1f..d25ac60259715 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -410,12 +410,30 @@ static void tcf_proto_get(struct tcf_proto *tp)
+ refcount_inc(&tp->refcnt);
+ }
+
++static void tcf_block_filter_cnt_update(struct tcf_block *block, bool *counted, bool add)
++{
++ lockdep_assert_not_held(&block->cb_lock);
++
++ down_write(&block->cb_lock);
++ if (*counted != add) {
++ if (add) {
++ atomic_inc(&block->filtercnt);
++ *counted = true;
++ } else {
++ atomic_dec(&block->filtercnt);
++ *counted = false;
++ }
++ }
++ up_write(&block->cb_lock);
++}
++
+ static void tcf_chain_put(struct tcf_chain *chain);
+
+ static void tcf_proto_destroy(struct tcf_proto *tp, bool rtnl_held,
+ bool sig_destroy, struct netlink_ext_ack *extack)
+ {
+ tp->ops->destroy(tp, rtnl_held, extack);
++ tcf_block_filter_cnt_update(tp->chain->block, &tp->counted, false);
+ if (sig_destroy)
+ tcf_proto_signal_destroyed(tp->chain, tp);
+ tcf_chain_put(tp->chain);
+@@ -2354,6 +2372,7 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
+ err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh,
+ flags, extack);
+ if (err == 0) {
++ tcf_block_filter_cnt_update(block, &tp->counted, true);
+ tfilter_notify(net, skb, n, tp, block, q, parent, fh,
+ RTM_NEWTFILTER, false, rtnl_held, extack);
+ tfilter_put(tp, fh);
+--
+2.53.0
+
--- /dev/null
+From c9b21c1888961e4ed043378d29923e3d0cfe21e3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 25 Mar 2024 20:47:34 +0000
+Subject: net: sched: cls_api: add skip_sw counter
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Asbjørn Sloth Tønnesen <ast@fiberby.net>
+
+[ Upstream commit f631ef39d81956a2ee69d25039781ceae1162f62 ]
+
+Maintain a count of skip_sw filters.
+
+This counter is protected by the cb_lock, and is updated
+at the same time as offloadcnt.
+
+Signed-off-by: Asbjørn Sloth Tønnesen <ast@fiberby.net>
+Reviewed-by: Jiri Pirko <jiri@nvidia.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Reviewed-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: a347304b2ca1 ("net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/sch_generic.h | 1 +
+ net/sched/cls_api.c | 4 ++++
+ 2 files changed, 5 insertions(+)
+
+diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
+index 385af747b0b4e..5df841ed0aeaa 100644
+--- a/include/net/sch_generic.h
++++ b/include/net/sch_generic.h
+@@ -477,6 +477,7 @@ struct tcf_block {
+ struct flow_block flow_block;
+ struct list_head owner_list;
+ bool keep_dst;
++ atomic_t skipswcnt; /* Number of skip_sw filters */
+ atomic_t offloadcnt; /* Number of oddloaded filters */
+ unsigned int nooffloaddevcnt; /* Number of devs unable to do offload */
+ unsigned int lockeddevcnt; /* Number of devs that require rtnl lock. */
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index e259ec6ed145d..792e7040ebc1f 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -3478,6 +3478,8 @@ static void tcf_block_offload_inc(struct tcf_block *block, u32 *flags)
+ if (*flags & TCA_CLS_FLAGS_IN_HW)
+ return;
+ *flags |= TCA_CLS_FLAGS_IN_HW;
++ if (tc_skip_sw(*flags))
++ atomic_inc(&block->skipswcnt);
+ atomic_inc(&block->offloadcnt);
+ }
+
+@@ -3486,6 +3488,8 @@ static void tcf_block_offload_dec(struct tcf_block *block, u32 *flags)
+ if (!(*flags & TCA_CLS_FLAGS_IN_HW))
+ return;
+ *flags &= ~TCA_CLS_FLAGS_IN_HW;
++ if (tc_skip_sw(*flags))
++ atomic_dec(&block->skipswcnt);
+ atomic_dec(&block->offloadcnt);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From a5018ba5e92d2c8478278db4210c7cf49590761e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 1 Aug 2026 08:56:32 -0400
+Subject: net/sched: cls_api: Always acquire rtnl_lock when destroying locked
+ classifiers
+
+From: Jamal Hadi Salim <jhs@mojatatu.com>
+
+[ Upstream commit a347304b2ca1a5377d5bd2d8a72e4b4f12afe648 ]
+
+Another challenge with unlocked filters.
+There is a short window in tc_new_tfilter where a tcf_proto can be found
+and briefly referenced by a totally unrelated, unlocked classifier's request
+and cause a race.
+
+Feng created a poc which created this race with two threads, one creating a
+u32 filter and other a flower filter in the same chain/prio:
+
+1. Both threads enter tc_new_tfilter, both find the chain empty, both
+ drop filter_chain_lock
+2. u32 finishes tcf_proto_create("u32") first, calls
+ tcf_chain_tp_insert_unique() -> inserts u32_tp into the chain
+3. flower finishes tcf_proto_create("flower") later, calls
+ tcf_chain_tp_insert_unique() -> tcf_chain_tp_find() now sees u32_tp
+ already there, takes a reference on it, destroys flower's own tp_new
+ and returns u32_tp to the caller.
+
+Flower then hits the kind mismatch check (because it requested for kind
+"flower" but tp->ops->kind is "u32") and goes through the errout path
+which calls tcf_proto_put() on u32_tp. If the u32 thread has already
+gone through its own errout (its change() call failed on the PoC's empty
+options) and dropped its create and insert refs, flower's put is the
+last one and drops u32_tp's refcnt to zero.
+
+At this point tp->ops->destroy() runs in a context that never took
+rtnl_lock. When that happens, it might cause a UAF like the following
+(illustrated by the PoC):
+
+[ +0.000710] BUG: KASAN: slab-use-after-free in u32_init (net/sched/cls_u32.c:393)
+[ +0.000281] Read of size 8 at addr ffff888120022f00 by task poc_feng_xue/524
+
+ Call Trace:
+ u32_init (net/sched/cls_u32.c:393)
+ tc_new_tfilter (net/sched/cls_api.c:2378)
+
+ Allocated by task 526:
+ u32_init (net/sched/cls_u32.c:378)
+ tc_new_tfilter (net/sched/cls_api.c:2378)
+
+ Freed by task 522:
+ kfree
+ u32_destroy (net/sched/cls_u32.c:662)
+ tcf_proto_destroy (net/sched/cls_api.c:446)
+ tcf_proto_put (net/sched/cls_api.c:459)
+ tc_new_tfilter (net/sched/cls_api.c:2459)
+
+Fix this by having tcf_proto_destroy() take rtnl_lock around
+tp->ops->destroy() for locked classifiers whenever rtnl is not held.
+
+To explain why I used a temp variable "not_lockless" I'd like to point to a
+semi-related note on rtnl_held vs TCF_PROTO_OPS_DOIT_UNLOCKED (adding here
+for future cleanup if deemed necessary):
+The rtnl_held parameter and the TCF_PROTO_OPS_DOIT_UNLOCKED flag are
+redundant sources of truth for whether rtnl_lock is held. Among the nine
+classifier destroy(..rtnl_held..) callbacks, only flower consults the
+rtnl_held parameter which it propagates to tc_setup_cb_destroy()
+and tc_setup_cb_call(). The other eight (u32, flow, bpf, cgroup, route, basic,
+fw, mall) ignore it entirely;-> those that call tc_setup_cb_destroy()
+(u32, bpf, mall) hardcode true always instead of forwarding the parameter.
+
+A future cleanup should remove the rtnl_held parameter from the destroy callback
+signature entirely and have callers rely solely on their knowledge whether
+they are running in an unlocked context.
+
+Fixes: 12db03b65c2b ("net: sched: extend proto ops to support unlocked classifiers")
+Reported-by: Feng Xue <feng.xue@outlook.com>
+Tested-by: Victor Nogueira <victor@mojatatu.com>
+Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260801125632.360365-1-jhs@mojatatu.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_api.c | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index f107afdd36bbd..ff6af03cb855d 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -443,7 +443,22 @@ static void tcf_chain_put(struct tcf_chain *chain);
+ static void tcf_proto_destroy(struct tcf_proto *tp, bool rtnl_held,
+ bool sig_destroy, struct netlink_ext_ack *extack)
+ {
+- tp->ops->destroy(tp, rtnl_held, extack);
++ /* A locked classifier's destroy callback (e.g. u32_destroy) uses
++ * rtnl_dereference() and mutates shared structures (e.g. the
++ * tc_u_common hash list) that are only safe under rtnl_lock. When an
++ * unlocked classifier's request (e.g. flower on ingress) loses the
++ * tcf_chain_tp_insert_unique() race and ends up dropping the last
++ * reference on a locked classifier's proto, destroy() would run
++ * without rtnl held. Take it here in that case.
++ */
++ bool not_lockless = !rtnl_held &&
++ !(tp->ops->flags & TCF_PROTO_OPS_DOIT_UNLOCKED);
++
++ if (not_lockless)
++ rtnl_lock();
++ tp->ops->destroy(tp, rtnl_held || not_lockless, extack);
++ if (not_lockless)
++ rtnl_unlock();
+ tcf_proto_count_usesw(tp, false);
+ if (sig_destroy)
+ tcf_proto_signal_destroyed(tp->chain, tp);
+--
+2.53.0
+
--- /dev/null
+From e76ee5f3b2c5e990e3d22ff09f1db08e2f766e9c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 8 Apr 2024 16:48:17 +0300
+Subject: net: sched: cls_api: fix slab-use-after-free in fl_dump_key
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jianbo Liu <jianbol@nvidia.com>
+
+[ Upstream commit 2ecd487b670fcbb1ad4893fff1af4aafdecb6023 ]
+
+The filter counter is updated under the protection of cb_lock in the
+cited commit. While waiting for the lock, it's possible the filter is
+being deleted by other thread, and thus causes UAF when dump it.
+
+Fix this issue by moving tcf_block_filter_cnt_update() after
+tfilter_put().
+
+ ==================================================================
+ BUG: KASAN: slab-use-after-free in fl_dump_key+0x1d3e/0x20d0 [cls_flower]
+ Read of size 4 at addr ffff88814f864000 by task tc/2973
+
+ CPU: 7 PID: 2973 Comm: tc Not tainted 6.9.0-rc2_for_upstream_debug_2024_04_02_12_41 #1
+ Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014
+ Call Trace:
+ <TASK>
+ dump_stack_lvl+0x7e/0xc0
+ print_report+0xc1/0x600
+ ? __virt_addr_valid+0x1cf/0x390
+ ? fl_dump_key+0x1d3e/0x20d0 [cls_flower]
+ ? fl_dump_key+0x1d3e/0x20d0 [cls_flower]
+ kasan_report+0xb9/0xf0
+ ? fl_dump_key+0x1d3e/0x20d0 [cls_flower]
+ fl_dump_key+0x1d3e/0x20d0 [cls_flower]
+ ? lock_acquire+0x1c2/0x530
+ ? fl_dump+0x172/0x5c0 [cls_flower]
+ ? lockdep_hardirqs_on_prepare+0x400/0x400
+ ? fl_dump_key_options.part.0+0x10f0/0x10f0 [cls_flower]
+ ? do_raw_spin_lock+0x12d/0x270
+ ? spin_bug+0x1d0/0x1d0
+ fl_dump+0x21d/0x5c0 [cls_flower]
+ ? fl_tmplt_dump+0x1f0/0x1f0 [cls_flower]
+ ? nla_put+0x15f/0x1c0
+ tcf_fill_node+0x51b/0x9a0
+ ? tc_skb_ext_tc_enable+0x150/0x150
+ ? __alloc_skb+0x17b/0x310
+ ? __build_skb_around+0x340/0x340
+ ? down_write+0x1b0/0x1e0
+ tfilter_notify+0x1a5/0x390
+ ? fl_terse_dump+0x400/0x400 [cls_flower]
+ tc_new_tfilter+0x963/0x2170
+ ? tc_del_tfilter+0x1490/0x1490
+ ? print_usage_bug.part.0+0x670/0x670
+ ? lock_downgrade+0x680/0x680
+ ? security_capable+0x51/0x90
+ ? tc_del_tfilter+0x1490/0x1490
+ rtnetlink_rcv_msg+0x75e/0xac0
+ ? if_nlmsg_stats_size+0x4c0/0x4c0
+ ? lockdep_set_lock_cmp_fn+0x190/0x190
+ ? __netlink_lookup+0x35e/0x6e0
+ netlink_rcv_skb+0x12c/0x360
+ ? if_nlmsg_stats_size+0x4c0/0x4c0
+ ? netlink_ack+0x15e0/0x15e0
+ ? lockdep_hardirqs_on_prepare+0x400/0x400
+ ? netlink_deliver_tap+0xcd/0xa60
+ ? netlink_deliver_tap+0xcd/0xa60
+ ? netlink_deliver_tap+0x1c9/0xa60
+ netlink_unicast+0x43e/0x700
+ ? netlink_attachskb+0x750/0x750
+ ? lock_acquire+0x1c2/0x530
+ ? __might_fault+0xbb/0x170
+ netlink_sendmsg+0x749/0xc10
+ ? netlink_unicast+0x700/0x700
+ ? __might_fault+0xbb/0x170
+ ? netlink_unicast+0x700/0x700
+ __sock_sendmsg+0xc5/0x190
+ ____sys_sendmsg+0x534/0x6b0
+ ? import_iovec+0x7/0x10
+ ? kernel_sendmsg+0x30/0x30
+ ? __copy_msghdr+0x3c0/0x3c0
+ ? entry_SYSCALL_64_after_hwframe+0x46/0x4e
+ ? lock_acquire+0x1c2/0x530
+ ? __virt_addr_valid+0x116/0x390
+ ___sys_sendmsg+0xeb/0x170
+ ? __virt_addr_valid+0x1ca/0x390
+ ? copy_msghdr_from_user+0x110/0x110
+ ? __delete_object+0xb8/0x100
+ ? __virt_addr_valid+0x1cf/0x390
+ ? do_sys_openat2+0x102/0x150
+ ? lockdep_hardirqs_on_prepare+0x284/0x400
+ ? do_sys_openat2+0x102/0x150
+ ? __fget_light+0x53/0x1d0
+ ? sockfd_lookup_light+0x1a/0x150
+ __sys_sendmsg+0xb5/0x140
+ ? __sys_sendmsg_sock+0x20/0x20
+ ? lock_downgrade+0x680/0x680
+ do_syscall_64+0x70/0x140
+ entry_SYSCALL_64_after_hwframe+0x46/0x4e
+ RIP: 0033:0x7f98e3713367
+ Code: 0e 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b9 0f 1f 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 2e 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 89 54 24 1c 48 89 74 24 10
+ RSP: 002b:00007ffc74a64608 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
+ RAX: ffffffffffffffda RBX: 000000000047eae0 RCX: 00007f98e3713367
+ RDX: 0000000000000000 RSI: 00007ffc74a64670 RDI: 0000000000000003
+ RBP: 0000000000000008 R08: 0000000000000000 R09: 0000000000000000
+ R10: 00007f98e360c5e8 R11: 0000000000000246 R12: 00007ffc74a6a508
+ R13: 00000000660d518d R14: 0000000000484a80 R15: 00007ffc74a6a50b
+ </TASK>
+
+ Allocated by task 2973:
+ kasan_save_stack+0x20/0x40
+ kasan_save_track+0x10/0x30
+ __kasan_kmalloc+0x77/0x90
+ fl_change+0x27a6/0x4540 [cls_flower]
+ tc_new_tfilter+0x879/0x2170
+ rtnetlink_rcv_msg+0x75e/0xac0
+ netlink_rcv_skb+0x12c/0x360
+ netlink_unicast+0x43e/0x700
+ netlink_sendmsg+0x749/0xc10
+ __sock_sendmsg+0xc5/0x190
+ ____sys_sendmsg+0x534/0x6b0
+ ___sys_sendmsg+0xeb/0x170
+ __sys_sendmsg+0xb5/0x140
+ do_syscall_64+0x70/0x140
+ entry_SYSCALL_64_after_hwframe+0x46/0x4e
+
+ Freed by task 283:
+ kasan_save_stack+0x20/0x40
+ kasan_save_track+0x10/0x30
+ kasan_save_free_info+0x37/0x50
+ poison_slab_object+0x105/0x190
+ __kasan_slab_free+0x11/0x30
+ kfree+0x111/0x340
+ process_one_work+0x787/0x1490
+ worker_thread+0x586/0xd30
+ kthread+0x2df/0x3b0
+ ret_from_fork+0x2d/0x70
+ ret_from_fork_asm+0x11/0x20
+
+ Last potentially related work creation:
+ kasan_save_stack+0x20/0x40
+ __kasan_record_aux_stack+0x9b/0xb0
+ insert_work+0x25/0x1b0
+ __queue_work+0x640/0xc90
+ rcu_work_rcufn+0x42/0x70
+ rcu_core+0x6a9/0x1850
+ __do_softirq+0x264/0x88f
+
+ Second to last potentially related work creation:
+ kasan_save_stack+0x20/0x40
+ __kasan_record_aux_stack+0x9b/0xb0
+ __call_rcu_common.constprop.0+0x6f/0xac0
+ queue_rcu_work+0x56/0x70
+ fl_mask_put+0x20d/0x270 [cls_flower]
+ __fl_delete+0x352/0x6b0 [cls_flower]
+ fl_delete+0x97/0x160 [cls_flower]
+ tc_del_tfilter+0x7d1/0x1490
+ rtnetlink_rcv_msg+0x75e/0xac0
+ netlink_rcv_skb+0x12c/0x360
+ netlink_unicast+0x43e/0x700
+ netlink_sendmsg+0x749/0xc10
+ __sock_sendmsg+0xc5/0x190
+ ____sys_sendmsg+0x534/0x6b0
+ ___sys_sendmsg+0xeb/0x170
+ __sys_sendmsg+0xb5/0x140
+ do_syscall_64+0x70/0x140
+ entry_SYSCALL_64_after_hwframe+0x46/0x4e
+
+Fixes: 2081fd3445fe ("net: sched: cls_api: add filter counter")
+Signed-off-by: Jianbo Liu <jianbol@nvidia.com>
+Reviewed-by: Cosmin Ratiu <cratiu@nvidia.com>
+Tested-by: Asbjørn Sloth Tønnesen <ast@fiberby.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: a347304b2ca1 ("net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_api.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index f16cfc23014b2..1eedeaf427298 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -2390,10 +2390,10 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
+ err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh,
+ flags, extack);
+ if (err == 0) {
+- tcf_block_filter_cnt_update(block, &tp->counted, true);
+ tfilter_notify(net, skb, n, tp, block, q, parent, fh,
+ RTM_NEWTFILTER, false, rtnl_held, extack);
+ tfilter_put(tp, fh);
++ tcf_block_filter_cnt_update(block, &tp->counted, true);
+ /* q pointer is NULL for shared blocks */
+ if (q)
+ q->flags &= ~TCQ_F_CAN_BYPASS;
+--
+2.53.0
+
--- /dev/null
+From 4c756026630c2e20dc03f88374d22f3b76e18a49 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 05:44:11 -0400
+Subject: net/sched: cls_route: fix fastmap use-after-free on filter
+
+From: Jamal Hadi Salim <jhs@mojatatu.com>
+
+[ Upstream commit 47d7f7051253bdc02b1d245d87e38f16d31a74df ]
+
+The route4 classifier maintains a 16-slot fastmap cache that stores raw
+struct route4_filter pointers indexed by (id, iif). The reader
+(route4_classify) populates this cache via route4_set_fastmap() for every
+classified packet that hits a filter. The writer (route4_delete,
+route4_change) clears the cache via route4_reset_fastmap() before
+RCU-deferred kfree of the filter.
+
+This creates a UAF race:
+ 1. Reader walks the RCU-protected bucket chain, finds filter f
+ 2. Writer unlinks f, calls route4_reset_fastmap(), then tcf_queue_work()
+ 3. Reader calls route4_set_fastmap() and writes f into the cache
+ *after* the writer's reset, caching a pointer about to be freed
+ 4. After the RCU grace period, kfree(f) executes
+ 5. Next classified packet on the same (id, iif) tuple hits the stale
+ fastmap entry and reads f->res from freed memory
+
+Reproduced with an mdelay(100) accelerator in route4_set_fastmap() and a
+concurrent add/delete stress test (provided by both zdi and Santosh).
+Both triggered KASAN slab-use-after-free reports in the route4 fastmap
+paths.
+
+Fix:
+Introduce a per-filter boolean dying flag to suppress stale fastmap
+republishing by in-flight readers.
+
+Fixes: 1109c00547fc ("net: sched: RCU cls_route")
+Reported-by: zdi-disclosures@trendmicro.com
+Reported-by: Santosh Kalluri <santosh.kalluri129@gmail.com>
+Suggested-by: Paolo Abeni <pabeni@redhat.com>
+Tested-by: Victor Nogueira <victor@mojatatu.com>
+Tested-by: Santosh Kalluri <santosh.kalluri129@gmail.com>
+Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260729094411.46257-1-jhs@mojatatu.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_route.c | 35 ++++++++++++++++++++++++++---------
+ 1 file changed, 26 insertions(+), 9 deletions(-)
+
+diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
+index 1e20bbd687f1d..fd72ab9d19eac 100644
+--- a/net/sched/cls_route.c
++++ b/net/sched/cls_route.c
+@@ -52,6 +52,7 @@ struct route4_filter {
+ struct tcf_result res;
+ struct tcf_exts exts;
+ u32 handle;
++ bool dying;
+ struct route4_bucket *bkt;
+ struct tcf_proto *tp;
+ struct rcu_work rwork;
+@@ -66,9 +67,11 @@ static inline int route4_fastmap_hash(u32 id, int iif)
+
+ static DEFINE_SPINLOCK(fastmap_lock);
+ static void
+-route4_reset_fastmap(struct route4_head *head)
++route4_reset_fastmap(struct route4_head *head, struct route4_filter *f)
+ {
+ spin_lock_bh(&fastmap_lock);
++ if (f)
++ f->dying = true;
+ memset(head->fastmap, 0, sizeof(head->fastmap));
+ spin_unlock_bh(&fastmap_lock);
+ }
+@@ -81,9 +84,11 @@ route4_set_fastmap(struct route4_head *head, u32 id, int iif,
+
+ /* fastmap updates must look atomic to aling id, iff, filter */
+ spin_lock_bh(&fastmap_lock);
+- head->fastmap[h].id = id;
+- head->fastmap[h].iif = iif;
+- head->fastmap[h].filter = f;
++ if (f == ROUTE4_FAILURE || !f->dying) {
++ head->fastmap[h].id = id;
++ head->fastmap[h].iif = iif;
++ head->fastmap[h].filter = f;
++ }
+ spin_unlock_bh(&fastmap_lock);
+ }
+
+@@ -297,6 +302,13 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
+ next = rtnl_dereference(f->next);
+ RCU_INIT_POINTER(b->ht[h2], next);
+ tcf_unbind_filter(tp, &f->res);
++ /* Mark the filter dying under fastmap_lock so
++ * any in-flight reader that still holds it
++ * will skip the republish in route4_set_fastmap().
++ */
++ spin_lock_bh(&fastmap_lock);
++ f->dying = true;
++ spin_unlock_bh(&fastmap_lock);
+ if (tcf_exts_get_net(&f->exts))
+ route4_queue_work(f);
+ else
+@@ -307,6 +319,11 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
+ kfree_rcu(b, rcu);
+ }
+ }
++
++ /* All filters are unlinked and marked dying, so no in-flight
++ * reader can republish a stale entry after this reset.
++ */
++ route4_reset_fastmap(head, NULL);
+ kfree_rcu(head, rcu);
+ }
+
+@@ -334,11 +351,11 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,
+ /* unlink it */
+ RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
+
+- /* Remove any fastmap lookups that might ref filter
+- * notice we unlink'd the filter so we can't get it
+- * back in the fastmap.
++ /* Clear any fastmap entries that may ref this filter and
++ * mark it dying so in-flight readers can't republish it
++ * after the reset.
+ */
+- route4_reset_fastmap(head);
++ route4_reset_fastmap(head, f);
+
+ /* Delete it */
+ tcf_unbind_filter(tp, &f->res);
+@@ -553,7 +570,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
+ }
+ }
+
+- route4_reset_fastmap(head);
++ route4_reset_fastmap(head, fold);
+ *arg = f;
+ if (fold) {
+ tcf_unbind_filter(tp, &fold->res);
+--
+2.53.0
+
--- /dev/null
+From 72ece3300ede9fdedf0ab45835e4bd8e06b43e0f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 25 Mar 2024 20:47:36 +0000
+Subject: net: sched: make skip_sw actually skip software
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Asbjørn Sloth Tønnesen <ast@fiberby.net>
+
+[ Upstream commit 047f340b36fc550c0fc6a8947fc0a1f8e429e9ab ]
+
+TC filters come in 3 variants:
+- no flag (try to process in hardware, but fallback to software))
+- skip_hw (do not process filter by hardware)
+- skip_sw (do not process filter by software)
+
+However skip_sw is implemented so that the skip_sw
+flag can first be checked, after it has been matched.
+
+IMHO it's common when using skip_sw, to use it on all rules.
+
+So if all filters in a block is skip_sw filters, then
+we can bail early, we can thus avoid having to match
+the filters, just to check for the skip_sw flag.
+
+This patch adds a bypass, for when only TC skip_sw rules
+are used. The bypass is guarded by a static key, to avoid
+harming other workloads.
+
+There are 3 ways that a packet from a skip_sw ruleset, can
+end up in the kernel path. Although the send packets to a
+non-existent chain way is only improved a few percents, then
+I believe it's worth optimizing the trap and fall-though
+use-cases.
+
+ +----------------------------+--------+--------+--------+
+ | Test description | Pre- | Post- | Rel. |
+ | | kpps | kpps | chg. |
+ +----------------------------+--------+--------+--------+
+ | basic forwarding + notrack | 3589.3 | 3587.9 | 1.00x |
+ | switch to eswitch mode | 3081.8 | 3094.7 | 1.00x |
+ | add ingress qdisc | 3042.9 | 3063.6 | 1.01x |
+ | tc forward in hw / skip_sw |37024.7 |37028.4 | 1.00x |
+ | tc forward in sw / skip_hw | 3245.0 | 3245.3 | 1.00x |
+ +----------------------------+--------+--------+--------+
+ | tests with only skip_sw rules below: |
+ +----------------------------+--------+--------+--------+
+ | 1 non-matching rule | 2694.7 | 3058.7 | 1.14x |
+ | 1 n-m rule, match trap | 2611.2 | 3323.1 | 1.27x |
+ | 1 n-m rule, goto non-chain | 2886.8 | 2945.9 | 1.02x |
+ | 5 non-matching rules | 1958.2 | 3061.3 | 1.56x |
+ | 5 n-m rules, match trap | 1911.9 | 3327.0 | 1.74x |
+ | 5 n-m rules, goto non-chain| 2883.1 | 2947.5 | 1.02x |
+ | 10 non-matching rules | 1466.3 | 3062.8 | 2.09x |
+ | 10 n-m rules, match trap | 1444.3 | 3317.9 | 2.30x |
+ | 10 n-m rules,goto non-chain| 2883.1 | 2939.5 | 1.02x |
+ | 25 non-matching rules | 838.5 | 3058.9 | 3.65x |
+ | 25 n-m rules, match trap | 824.5 | 3323.0 | 4.03x |
+ | 25 n-m rules,goto non-chain| 2875.8 | 2944.7 | 1.02x |
+ | 50 non-matching rules | 488.1 | 3054.7 | 6.26x |
+ | 50 n-m rules, match trap | 484.9 | 3318.5 | 6.84x |
+ | 50 n-m rules,goto non-chain| 2884.1 | 2939.7 | 1.02x |
+ +----------------------------+--------+--------+--------+
+
+perf top (25 n-m skip_sw rules - pre patch):
+ 20.39% [kernel] [k] __skb_flow_dissect
+ 16.43% [kernel] [k] rhashtable_jhash2
+ 10.58% [kernel] [k] fl_classify
+ 10.23% [kernel] [k] fl_mask_lookup
+ 4.79% [kernel] [k] memset_orig
+ 2.58% [kernel] [k] tcf_classify
+ 1.47% [kernel] [k] __x86_indirect_thunk_rax
+ 1.42% [kernel] [k] __dev_queue_xmit
+ 1.36% [kernel] [k] nft_do_chain
+ 1.21% [kernel] [k] __rcu_read_lock
+
+perf top (25 n-m skip_sw rules - post patch):
+ 5.12% [kernel] [k] __dev_queue_xmit
+ 4.77% [kernel] [k] nft_do_chain
+ 3.65% [kernel] [k] dev_gro_receive
+ 3.41% [kernel] [k] check_preemption_disabled
+ 3.14% [kernel] [k] mlx5e_skb_from_cqe_mpwrq_nonlinear
+ 2.88% [kernel] [k] __netif_receive_skb_core.constprop.0
+ 2.49% [kernel] [k] mlx5e_xmit
+ 2.15% [kernel] [k] ip_forward
+ 1.95% [kernel] [k] mlx5e_tc_restore_tunnel
+ 1.92% [kernel] [k] vlan_gro_receive
+
+Test setup:
+ DUT: Intel Xeon D-1518 (2.20GHz) w/ Nvidia/Mellanox ConnectX-6 Dx 2x100G
+ Data rate measured on switch (Extreme X690), and DUT connected as
+ a router on a stick, with pktgen and pktsink as VLANs.
+ Pktgen-dpdk was in range 36.6-37.7 Mpps 64B packets across all tests.
+ Full test data at https://files.fiberby.net/ast/2024/tc_skip_sw/v2_tests/
+
+Signed-off-by: Asbjørn Sloth Tønnesen <ast@fiberby.net>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Reviewed-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: a347304b2ca1 ("net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/pkt_cls.h | 9 +++++++++
+ include/net/sch_generic.h | 1 +
+ net/core/dev.c | 10 ++++++++++
+ net/sched/cls_api.c | 18 ++++++++++++++++++
+ 4 files changed, 38 insertions(+)
+
+diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
+index ccc1c698ed007..0c1a1e366e8eb 100644
+--- a/include/net/pkt_cls.h
++++ b/include/net/pkt_cls.h
+@@ -72,6 +72,15 @@ static inline bool tcf_block_non_null_shared(struct tcf_block *block)
+ return block && block->index;
+ }
+
++#ifdef CONFIG_NET_CLS_ACT
++DECLARE_STATIC_KEY_FALSE(tcf_bypass_check_needed_key);
++
++static inline bool tcf_block_bypass_sw(struct tcf_block *block)
++{
++ return block && block->bypass_wanted;
++}
++#endif
++
+ static inline struct Qdisc *tcf_block_q(struct tcf_block *block)
+ {
+ WARN_ON(tcf_block_shared(block));
+diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
+index a94ff63e3cd5b..18ba0226b624f 100644
+--- a/include/net/sch_generic.h
++++ b/include/net/sch_generic.h
+@@ -478,6 +478,7 @@ struct tcf_block {
+ struct flow_block flow_block;
+ struct list_head owner_list;
+ bool keep_dst;
++ bool bypass_wanted;
+ atomic_t filtercnt; /* Number of filters */
+ atomic_t skipswcnt; /* Number of skip_sw filters */
+ atomic_t offloadcnt; /* Number of oddloaded filters */
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 0cc03e6c6fb14..31469d53e067d 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -2146,6 +2146,11 @@ void net_dec_egress_queue(void)
+ EXPORT_SYMBOL_GPL(net_dec_egress_queue);
+ #endif
+
++#ifdef CONFIG_NET_CLS_ACT
++DEFINE_STATIC_KEY_FALSE(tcf_bypass_check_needed_key);
++EXPORT_SYMBOL(tcf_bypass_check_needed_key);
++#endif
++
+ DEFINE_STATIC_KEY_FALSE(netstamp_needed_key);
+ EXPORT_SYMBOL(netstamp_needed_key);
+ #ifdef CONFIG_JUMP_LABEL
+@@ -4030,6 +4035,11 @@ static int tc_run(struct tcx_entry *entry, struct sk_buff *skb)
+ if (!miniq)
+ return ret;
+
++ if (static_branch_unlikely(&tcf_bypass_check_needed_key)) {
++ if (tcf_block_bypass_sw(miniq->block))
++ return ret;
++ }
++
+ tc_skb_cb(skb)->mru = 0;
+ tc_skb_cb(skb)->post_ct = false;
+
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index d25ac60259715..f16cfc23014b2 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -410,6 +410,23 @@ static void tcf_proto_get(struct tcf_proto *tp)
+ refcount_inc(&tp->refcnt);
+ }
+
++static void tcf_maintain_bypass(struct tcf_block *block)
++{
++ int filtercnt = atomic_read(&block->filtercnt);
++ int skipswcnt = atomic_read(&block->skipswcnt);
++ bool bypass_wanted = filtercnt > 0 && filtercnt == skipswcnt;
++
++ if (bypass_wanted != block->bypass_wanted) {
++#ifdef CONFIG_NET_CLS_ACT
++ if (bypass_wanted)
++ static_branch_inc(&tcf_bypass_check_needed_key);
++ else
++ static_branch_dec(&tcf_bypass_check_needed_key);
++#endif
++ block->bypass_wanted = bypass_wanted;
++ }
++}
++
+ static void tcf_block_filter_cnt_update(struct tcf_block *block, bool *counted, bool add)
+ {
+ lockdep_assert_not_held(&block->cb_lock);
+@@ -424,6 +441,7 @@ static void tcf_block_filter_cnt_update(struct tcf_block *block, bool *counted,
+ *counted = false;
+ }
+ }
++ tcf_maintain_bypass(block);
+ up_write(&block->cb_lock);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From d39609f033baec27a962861e40a96c44903d464c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Jan 2025 09:27:54 -0500
+Subject: net: sched: refine software bypass handling in tc_run
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Xin Long <lucien.xin@gmail.com>
+
+[ Upstream commit a12c76a03386e32413ae8eaaefa337e491880632 ]
+
+This patch addresses issues with filter counting in block (tcf_block),
+particularly for software bypass scenarios, by introducing a more
+accurate mechanism using useswcnt.
+
+Previously, filtercnt and skipswcnt were introduced by:
+
+ Commit 2081fd3445fe ("net: sched: cls_api: add filter counter") and
+ Commit f631ef39d819 ("net: sched: cls_api: add skip_sw counter")
+
+ filtercnt tracked all tp (tcf_proto) objects added to a block, and
+ skipswcnt counted tp objects with the skipsw attribute set.
+
+The problem is: a single tp can contain multiple filters, some with skipsw
+and others without. The current implementation fails in the case:
+
+ When the first filter in a tp has skipsw, both skipswcnt and filtercnt
+ are incremented, then adding a second filter without skipsw to the same
+ tp does not modify these counters because tp->counted is already set.
+
+ This results in bypass software behavior based solely on skipswcnt
+ equaling filtercnt, even when the block includes filters without
+ skipsw. Consequently, filters without skipsw are inadvertently bypassed.
+
+To address this, the patch introduces useswcnt in block to explicitly count
+tp objects containing at least one filter without skipsw. Key changes
+include:
+
+ Whenever a filter without skipsw is added, its tp is marked with usesw
+ and counted in useswcnt. tc_run() now uses useswcnt to determine software
+ bypass, eliminating reliance on filtercnt and skipswcnt.
+
+ This refined approach prevents software bypass for blocks containing
+ mixed filters, ensuring correct behavior in tc_run().
+
+Additionally, as atomic operations on useswcnt ensure thread safety and
+tp->lock guards access to tp->usesw and tp->counted, the broader lock
+down_write(&block->cb_lock) is no longer required in tc_new_tfilter(),
+and this resolves a performance regression caused by the filter counting
+mechanism during parallel filter insertions.
+
+ The improvement can be demonstrated using the following script:
+
+ # cat insert_tc_rules.sh
+
+ tc qdisc add dev ens1f0np0 ingress
+ for i in $(seq 16); do
+ taskset -c $i tc -b rules_$i.txt &
+ done
+ wait
+
+ Each of rules_$i.txt files above includes 100000 tc filter rules to a
+ mlx5 driver NIC ens1f0np0.
+
+ Without this patch:
+
+ # time sh insert_tc_rules.sh
+
+ real 0m50.780s
+ user 0m23.556s
+ sys 4m13.032s
+
+ With this patch:
+
+ # time sh insert_tc_rules.sh
+
+ real 0m17.718s
+ user 0m7.807s
+ sys 3m45.050s
+
+Fixes: 047f340b36fc ("net: sched: make skip_sw actually skip software")
+Reported-by: Shuang Li <shuali@redhat.com>
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+Reviewed-by: Asbjørn Sloth Tønnesen <ast@fiberby.net>
+Tested-by: Asbjørn Sloth Tønnesen <ast@fiberby.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: a347304b2ca1 ("net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/pkt_cls.h | 13 +++++++--
+ include/net/sch_generic.h | 5 ++--
+ net/core/dev.c | 15 ++++++-----
+ net/sched/cls_api.c | 57 ++++++++++++++++-----------------------
+ net/sched/cls_bpf.c | 2 ++
+ net/sched/cls_flower.c | 2 ++
+ net/sched/cls_matchall.c | 2 ++
+ net/sched/cls_u32.c | 4 +++
+ 8 files changed, 55 insertions(+), 45 deletions(-)
+
+diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
+index 0c1a1e366e8eb..307478c233223 100644
+--- a/include/net/pkt_cls.h
++++ b/include/net/pkt_cls.h
+@@ -73,11 +73,11 @@ static inline bool tcf_block_non_null_shared(struct tcf_block *block)
+ }
+
+ #ifdef CONFIG_NET_CLS_ACT
+-DECLARE_STATIC_KEY_FALSE(tcf_bypass_check_needed_key);
++DECLARE_STATIC_KEY_FALSE(tcf_sw_enabled_key);
+
+ static inline bool tcf_block_bypass_sw(struct tcf_block *block)
+ {
+- return block && block->bypass_wanted;
++ return block && !atomic_read(&block->useswcnt);
+ }
+ #endif
+
+@@ -759,6 +759,15 @@ tc_cls_common_offload_init(struct flow_cls_common_offload *cls_common,
+ cls_common->extack = extack;
+ }
+
++static inline void tcf_proto_update_usesw(struct tcf_proto *tp, u32 flags)
++{
++ if (tp->usesw)
++ return;
++ if (tc_skip_sw(flags) && tc_in_hw(flags))
++ return;
++ tp->usesw = true;
++}
++
+ #if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
+ static inline struct tc_skb_ext *tc_skb_ext_alloc(struct sk_buff *skb)
+ {
+diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
+index 18ba0226b624f..6ec258d0278e3 100644
+--- a/include/net/sch_generic.h
++++ b/include/net/sch_generic.h
+@@ -430,6 +430,7 @@ struct tcf_proto {
+ spinlock_t lock;
+ bool deleting;
+ bool counted;
++ bool usesw;
+ refcount_t refcnt;
+ struct rcu_head rcu;
+ struct hlist_node destroy_ht_node;
+@@ -478,9 +479,7 @@ struct tcf_block {
+ struct flow_block flow_block;
+ struct list_head owner_list;
+ bool keep_dst;
+- bool bypass_wanted;
+- atomic_t filtercnt; /* Number of filters */
+- atomic_t skipswcnt; /* Number of skip_sw filters */
++ atomic_t useswcnt;
+ atomic_t offloadcnt; /* Number of oddloaded filters */
+ unsigned int nooffloaddevcnt; /* Number of devs unable to do offload */
+ unsigned int lockeddevcnt; /* Number of devs that require rtnl lock. */
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 31469d53e067d..0fa5431de2cc0 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -2147,8 +2147,8 @@ EXPORT_SYMBOL_GPL(net_dec_egress_queue);
+ #endif
+
+ #ifdef CONFIG_NET_CLS_ACT
+-DEFINE_STATIC_KEY_FALSE(tcf_bypass_check_needed_key);
+-EXPORT_SYMBOL(tcf_bypass_check_needed_key);
++DEFINE_STATIC_KEY_FALSE(tcf_sw_enabled_key);
++EXPORT_SYMBOL(tcf_sw_enabled_key);
+ #endif
+
+ DEFINE_STATIC_KEY_FALSE(netstamp_needed_key);
+@@ -4035,10 +4035,13 @@ static int tc_run(struct tcx_entry *entry, struct sk_buff *skb)
+ if (!miniq)
+ return ret;
+
+- if (static_branch_unlikely(&tcf_bypass_check_needed_key)) {
+- if (tcf_block_bypass_sw(miniq->block))
+- return ret;
+- }
++ /* Global bypass */
++ if (!static_branch_likely(&tcf_sw_enabled_key))
++ return ret;
++
++ /* Block-wise bypass */
++ if (tcf_block_bypass_sw(miniq->block))
++ return ret;
+
+ tc_skb_cb(skb)->mru = 0;
+ tc_skb_cb(skb)->post_ct = false;
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index 1eedeaf427298..f107afdd36bbd 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -390,6 +390,7 @@ static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
+ tp->protocol = protocol;
+ tp->prio = prio;
+ tp->chain = chain;
++ tp->usesw = !tp->ops->reoffload;
+ spin_lock_init(&tp->lock);
+ refcount_set(&tp->refcnt, 1);
+
+@@ -410,39 +411,31 @@ static void tcf_proto_get(struct tcf_proto *tp)
+ refcount_inc(&tp->refcnt);
+ }
+
+-static void tcf_maintain_bypass(struct tcf_block *block)
++static void tcf_proto_count_usesw(struct tcf_proto *tp, bool add)
+ {
+- int filtercnt = atomic_read(&block->filtercnt);
+- int skipswcnt = atomic_read(&block->skipswcnt);
+- bool bypass_wanted = filtercnt > 0 && filtercnt == skipswcnt;
+-
+- if (bypass_wanted != block->bypass_wanted) {
+ #ifdef CONFIG_NET_CLS_ACT
+- if (bypass_wanted)
+- static_branch_inc(&tcf_bypass_check_needed_key);
+- else
+- static_branch_dec(&tcf_bypass_check_needed_key);
+-#endif
+- block->bypass_wanted = bypass_wanted;
++ struct tcf_block *block = tp->chain->block;
++ bool counted = false;
++
++ if (!add) {
++ if (tp->usesw && tp->counted) {
++ if (!atomic_dec_return(&block->useswcnt))
++ static_branch_dec(&tcf_sw_enabled_key);
++ tp->counted = false;
++ }
++ return;
+ }
+-}
+-
+-static void tcf_block_filter_cnt_update(struct tcf_block *block, bool *counted, bool add)
+-{
+- lockdep_assert_not_held(&block->cb_lock);
+
+- down_write(&block->cb_lock);
+- if (*counted != add) {
+- if (add) {
+- atomic_inc(&block->filtercnt);
+- *counted = true;
+- } else {
+- atomic_dec(&block->filtercnt);
+- *counted = false;
+- }
++ spin_lock(&tp->lock);
++ if (tp->usesw && !tp->counted) {
++ counted = true;
++ tp->counted = true;
+ }
+- tcf_maintain_bypass(block);
+- up_write(&block->cb_lock);
++ spin_unlock(&tp->lock);
++
++ if (counted && atomic_inc_return(&block->useswcnt) == 1)
++ static_branch_inc(&tcf_sw_enabled_key);
++#endif
+ }
+
+ static void tcf_chain_put(struct tcf_chain *chain);
+@@ -451,7 +444,7 @@ static void tcf_proto_destroy(struct tcf_proto *tp, bool rtnl_held,
+ bool sig_destroy, struct netlink_ext_ack *extack)
+ {
+ tp->ops->destroy(tp, rtnl_held, extack);
+- tcf_block_filter_cnt_update(tp->chain->block, &tp->counted, false);
++ tcf_proto_count_usesw(tp, false);
+ if (sig_destroy)
+ tcf_proto_signal_destroyed(tp->chain, tp);
+ tcf_chain_put(tp->chain);
+@@ -2393,7 +2386,7 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
+ tfilter_notify(net, skb, n, tp, block, q, parent, fh,
+ RTM_NEWTFILTER, false, rtnl_held, extack);
+ tfilter_put(tp, fh);
+- tcf_block_filter_cnt_update(block, &tp->counted, true);
++ tcf_proto_count_usesw(tp, true);
+ /* q pointer is NULL for shared blocks */
+ if (q)
+ q->flags &= ~TCQ_F_CAN_BYPASS;
+@@ -3515,8 +3508,6 @@ static void tcf_block_offload_inc(struct tcf_block *block, u32 *flags)
+ if (*flags & TCA_CLS_FLAGS_IN_HW)
+ return;
+ *flags |= TCA_CLS_FLAGS_IN_HW;
+- if (tc_skip_sw(*flags))
+- atomic_inc(&block->skipswcnt);
+ atomic_inc(&block->offloadcnt);
+ }
+
+@@ -3525,8 +3516,6 @@ static void tcf_block_offload_dec(struct tcf_block *block, u32 *flags)
+ if (!(*flags & TCA_CLS_FLAGS_IN_HW))
+ return;
+ *flags &= ~TCA_CLS_FLAGS_IN_HW;
+- if (tc_skip_sw(*flags))
+- atomic_dec(&block->skipswcnt);
+ atomic_dec(&block->offloadcnt);
+ }
+
+diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
+index d5a5dffcd6f9b..cede21257d27c 100644
+--- a/net/sched/cls_bpf.c
++++ b/net/sched/cls_bpf.c
+@@ -509,6 +509,8 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
+ if (!tc_in_hw(prog->gen_flags))
+ prog->gen_flags |= TCA_CLS_FLAGS_NOT_IN_HW;
+
++ tcf_proto_update_usesw(tp, prog->gen_flags);
++
+ if (oldprog) {
+ idr_replace(&head->handle_idr, prog, handle);
+ list_replace_rcu(&oldprog->link, &prog->link);
+diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
+index b00e491e8130d..4fc59af6696ea 100644
+--- a/net/sched/cls_flower.c
++++ b/net/sched/cls_flower.c
+@@ -2374,6 +2374,8 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
+ if (!tc_in_hw(fnew->flags))
+ fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
+
++ tcf_proto_update_usesw(tp, fnew->flags);
++
+ spin_lock(&tp->lock);
+
+ /* tp was deleted concurrently. -EAGAIN will cause caller to lookup
+diff --git a/net/sched/cls_matchall.c b/net/sched/cls_matchall.c
+index c4ed11df62548..e8353b27c8c4d 100644
+--- a/net/sched/cls_matchall.c
++++ b/net/sched/cls_matchall.c
+@@ -228,6 +228,8 @@ static int mall_change(struct net *net, struct sk_buff *in_skb,
+ if (!tc_in_hw(new->flags))
+ new->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
+
++ tcf_proto_update_usesw(tp, new->flags);
++
+ *arg = head;
+ rcu_assign_pointer(tp->root, new);
+ return 0;
+diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
+index 1338d9b4c03a4..9829df127d054 100644
+--- a/net/sched/cls_u32.c
++++ b/net/sched/cls_u32.c
+@@ -950,6 +950,8 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
+ if (!tc_in_hw(new->flags))
+ new->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
+
++ tcf_proto_update_usesw(tp, new->flags);
++
+ u32_replace_knode(tp, tp_c, new);
+ tcf_unbind_filter(tp, &n->res);
+ tcf_exts_get_net(&n->exts);
+@@ -1163,6 +1165,8 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
+ if (!tc_in_hw(n->flags))
+ n->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
+
++ tcf_proto_update_usesw(tp, n->flags);
++
+ ins = &ht->ht[TC_U32_HASH(handle)];
+ for (pins = rtnl_dereference(*ins); pins;
+ ins = &pins->next, pins = rtnl_dereference(*ins))
+--
+2.53.0
+
--- /dev/null
+From 72ca602caf481109c4195ebae1a34141f18a32fe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 21:14:16 +0200
+Subject: net/sched: sch_cake: drop WARN_ON(1) for malformed packets in ACK
+ filter
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Toke Høiland-Jørgensen <toke@toke.dk>
+
+[ Upstream commit 2a33516f9ef59ad11844d4fc152f889449b5daf3 ]
+
+The sch_cake ACK filter parses packets to find the TCP header and filter
+duplicated ACKs if the flow is backlogged. The parsing code contains a
+WARN_ON(1) which can be triggered by a malformed IP header in certain
+cases. Depending on the system configuration, this leads either to
+either spamming dmesg with warnings, or a panic if panic_on_warn is set.
+
+The code already correctly skips the offending packet in the branch that
+triggers the warning, so the WARN_ON itself doesn't really serve any
+purpose. So just drop it altogether to avoid the inconvenient side
+effects.
+
+Fixes: 8b7138814f29 ("sch_cake: Add optional ACK filter")
+Reported-by: Zhiling Zou <zhilinz@nebusec.ai>
+Reported-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
+Link: https://patch.msgid.link/20260729191417.45665-1-toke@toke.dk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_cake.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c
+index ce9ee43e9ee2b..4331097f813ec 100644
+--- a/net/sched/sch_cake.c
++++ b/net/sched/sch_cake.c
+@@ -1282,7 +1282,6 @@ static struct sk_buff *cake_ack_filter(struct cake_sched_data *q,
+
+ seglen = ntohs(ipv6h_check->payload_len);
+ } else {
+- WARN_ON(1); /* shouldn't happen */
+ continue;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 9bb5cc8bb500be2675d14d6591f4b0c97de36de9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:01:53 +0200
+Subject: net/smc: fix qentry overwrite for CONFIRM_LINK and ADD_LINK_CONT in
+ smc_llc_event_handler()
+
+From: Mahanta Jambigi <mjambigi@linux.ibm.com>
+
+[ Upstream commit 976245094925bab9bc39366b2e9ab44ffcde61d0 ]
+
+The SMC_LLC_CONFIRM_LINK / SMC_LLC_ADD_LINK_CONT branch in
+smc_llc_event_handler() stores an incoming qentry into the local LLC flow
+without first checking whether a qentry is already pending. If a malicious or
+buggy peer sends a second CONFIRM_LINK or ADD_LINK_CONT request while a flow is
+active and flow->qentry is already set, smc_llc_flow_qentry_set() overwrites the
+pointer without freeing the previous allocation, leaking one kmalloc-96 object
+per spurious message.
+
+The sibling SMC_LLC_DELETE_LINK branch already has the correct !flow->qentry
+guard. Apply the same guard to the CONFIRM_LINK/ADD_LINK_CONT branch so that a
+duplicate message when qentry is already occupied falls through to break and is
+freed by the kfree(qentry) at the out: label, rather than silently leaking the
+existing allocation.
+
+The response direction (smc_llc_rx_response()) is unaffected: it already guards
+with flow->qentry at the equivalent site and drops duplicate responses
+correctly.
+
+Fixes: 0fb0b02bd6fd ("net/smc: adapt SMC client code to use the LLC flow")
+Signed-off-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
+Reviewed-by: Hidayath Khan <hidayath@linux.ibm.com>
+Reviewed-by: Sidraya Jayagond <sidraya@linux.ibm.com>
+Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
+Link: https://patch.msgid.link/20260729130153.970800-1-mjambigi@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/smc_llc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c
+index 018ce8133b026..149d63cff667e 100644
+--- a/net/smc/smc_llc.c
++++ b/net/smc/smc_llc.c
+@@ -1918,7 +1918,8 @@ static void smc_llc_event_handler(struct smc_llc_qentry *qentry)
+ return;
+ case SMC_LLC_CONFIRM_LINK:
+ case SMC_LLC_ADD_LINK_CONT:
+- if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) {
++ if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE &&
++ !lgr->llc_flow_lcl.qentry) {
+ /* a flow is waiting for this message */
+ smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry);
+ wake_up(&lgr->llc_msg_waiter);
+--
+2.53.0
+
--- /dev/null
+From 637bd3ade2324c39398731844bd537d8b2481390 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 09:07:01 +0200
+Subject: net/smc: fix TOCTOU race between smc_listen_out() and listener close
+
+From: Sidraya Jayagond <sidraya@linux.ibm.com>
+
+[ Upstream commit 185a4caeecabc150106deda1da170b09f2ad803f ]
+
+smc_listen_out() reads lsmc->sk.sk_state without the listener lock,
+then acquires lock_sock_nested() only after the check passes. This
+opens a window where smc_close_active() can transition the listener
+to SMC_CLOSED, call smc_close_cleanup_listen() to drain the accept
+queue, and release the lock, all between the lockless read and the
+delayed lock acquisition:
+
+ smc_listen_work (smc_hs_wq) smc_close_active()
+ ------------------------------- -------------------------
+ release_sock(child)
+ if (sk_state == SMC_LISTEN) TRUE
+ lock_sock(listener)
+ sk_state = SMC_CLOSED
+ smc_close_cleanup_listen()
+ release_sock(listener)
+ flush_work(tcp_listen_work)
+ lock_sock_nested(listener)
+ smc_accept_enqueue(listener, child) /* child enqueued on dead listener */
+
+smc_close_active() flushes only tcp_listen_work. Work items already
+dispatched onto smc_hs_wq for the CLC handshake continue running
+unguarded. smc_accept_enqueue() takes a sock_hold() on the child that
+is never released, so the child smc_sock, its clcsock, and the
+reference all leak. A remote peer that opens TCP connections while the
+server calls close() can exhaust kernel memory.
+
+Move lock_sock_nested() to before the sk_state check so that the test
+and the enqueue are atomic under the listener lock.
+
+Fixes: fd57770dd198 ("net/smc: wait for pending work before clcsock release_sock")
+Reviewed-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
+Signed-off-by: Sidraya Jayagond <sidraya@linux.ibm.com>
+Reviewed-by: Breno Leitao <leitao@debian.org>
+Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
+Link: https://patch.msgid.link/20260803070701.126339-1-sidraya@linux.ibm.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/af_smc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
+index e5e07160e5719..087102ff3c640 100644
+--- a/net/smc/af_smc.c
++++ b/net/smc/af_smc.c
+@@ -1921,11 +1921,12 @@ static void smc_listen_out(struct smc_sock *new_smc)
+ atomic_dec(&lsmc->queued_smc_hs);
+
+ release_sock(newsmcsk); /* lock in smc_listen_work() */
++ lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
+ if (lsmc->sk.sk_state == SMC_LISTEN) {
+- lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
+ smc_accept_enqueue(&lsmc->sk, newsmcsk);
+ release_sock(&lsmc->sk);
+ } else { /* no longer listening */
++ release_sock(&lsmc->sk);
+ smc_close_non_accepted(newsmcsk);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 9772224077b914196aa211675a40dc013bf3d8af Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 23 Oct 2023 20:21:54 +0100
+Subject: net/tcp: Add TCP-AO config and structures
+
+From: Dmitry Safonov <dima@arista.com>
+
+[ Upstream commit c845f5f3590ef4669fe5464f8a42be6442cd174b ]
+
+Introduce new kernel config option and common structures as well as
+helpers to be used by TCP-AO code.
+
+Co-developed-by: Francesco Ruggeri <fruggeri@arista.com>
+Signed-off-by: Francesco Ruggeri <fruggeri@arista.com>
+Co-developed-by: Salam Noureddine <noureddine@arista.com>
+Signed-off-by: Salam Noureddine <noureddine@arista.com>
+Signed-off-by: Dmitry Safonov <dima@arista.com>
+Acked-by: David Ahern <dsahern@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: d0c80dbb9704 ("net/atm: fix slab-out-of-bounds read in vcc_setsockopt()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/tcp.h | 9 +++-
+ include/net/tcp.h | 8 +---
+ include/net/tcp_ao.h | 90 ++++++++++++++++++++++++++++++++++++++++
+ include/uapi/linux/tcp.h | 2 +
+ net/ipv4/Kconfig | 13 ++++++
+ 5 files changed, 114 insertions(+), 8 deletions(-)
+ create mode 100644 include/net/tcp_ao.h
+
+diff --git a/include/linux/tcp.h b/include/linux/tcp.h
+index e15452df9804f..c38778b0baa05 100644
+--- a/include/linux/tcp.h
++++ b/include/linux/tcp.h
+@@ -445,13 +445,18 @@ struct tcp_sock {
+ bool syn_smc; /* SYN includes SMC */
+ #endif
+
+-#ifdef CONFIG_TCP_MD5SIG
+-/* TCP AF-Specific parts; only used by MD5 Signature support so far */
++#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)
++/* TCP AF-Specific parts; only used by TCP-AO/MD5 Signature support so far */
+ const struct tcp_sock_af_ops *af_specific;
+
++#ifdef CONFIG_TCP_MD5SIG
+ /* TCP MD5 Signature Option information */
+ struct tcp_md5sig_info __rcu *md5sig_info;
+ #endif
++#ifdef CONFIG_TCP_AO
++ struct tcp_ao_info __rcu *ao_info;
++#endif
++#endif
+
+ /* TCP fastopen related information */
+ struct tcp_fastopen_request *fastopen_req;
+diff --git a/include/net/tcp.h b/include/net/tcp.h
+index 9c3ec3200e27b..0eb9341f74888 100644
+--- a/include/net/tcp.h
++++ b/include/net/tcp.h
+@@ -37,6 +37,7 @@
+ #include <net/snmp.h>
+ #include <net/ip.h>
+ #include <net/tcp_states.h>
++#include <net/tcp_ao.h>
+ #include <net/inet_ecn.h>
+ #include <net/dst.h>
+ #include <net/mptcp.h>
+@@ -1681,12 +1682,7 @@ static inline void tcp_clear_all_retrans_hints(struct tcp_sock *tp)
+ tp->retransmit_skb_hint = NULL;
+ }
+
+-union tcp_md5_addr {
+- struct in_addr a4;
+-#if IS_ENABLED(CONFIG_IPV6)
+- struct in6_addr a6;
+-#endif
+-};
++#define tcp_md5_addr tcp_ao_addr
+
+ /* - key database */
+ struct tcp_md5sig_key {
+diff --git a/include/net/tcp_ao.h b/include/net/tcp_ao.h
+new file mode 100644
+index 0000000000000..af76e1c47bea9
+--- /dev/null
++++ b/include/net/tcp_ao.h
+@@ -0,0 +1,90 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++#ifndef _TCP_AO_H
++#define _TCP_AO_H
++
++#define TCP_AO_KEY_ALIGN 1
++#define __tcp_ao_key_align __aligned(TCP_AO_KEY_ALIGN)
++
++union tcp_ao_addr {
++ struct in_addr a4;
++#if IS_ENABLED(CONFIG_IPV6)
++ struct in6_addr a6;
++#endif
++};
++
++struct tcp_ao_hdr {
++ u8 kind;
++ u8 length;
++ u8 keyid;
++ u8 rnext_keyid;
++};
++
++struct tcp_ao_key {
++ struct hlist_node node;
++ union tcp_ao_addr addr;
++ u8 key[TCP_AO_MAXKEYLEN] __tcp_ao_key_align;
++ unsigned int tcp_sigpool_id;
++ unsigned int digest_size;
++ u8 prefixlen;
++ u8 family;
++ u8 keylen;
++ u8 keyflags;
++ u8 sndid;
++ u8 rcvid;
++ u8 maclen;
++ struct rcu_head rcu;
++ u8 traffic_keys[];
++};
++
++static inline u8 *rcv_other_key(struct tcp_ao_key *key)
++{
++ return key->traffic_keys;
++}
++
++static inline u8 *snd_other_key(struct tcp_ao_key *key)
++{
++ return key->traffic_keys + key->digest_size;
++}
++
++static inline int tcp_ao_maclen(const struct tcp_ao_key *key)
++{
++ return key->maclen;
++}
++
++static inline int tcp_ao_len(const struct tcp_ao_key *key)
++{
++ return tcp_ao_maclen(key) + sizeof(struct tcp_ao_hdr);
++}
++
++static inline unsigned int tcp_ao_digest_size(struct tcp_ao_key *key)
++{
++ return key->digest_size;
++}
++
++static inline int tcp_ao_sizeof_key(const struct tcp_ao_key *key)
++{
++ return sizeof(struct tcp_ao_key) + (key->digest_size << 1);
++}
++
++struct tcp_ao_info {
++ /* List of tcp_ao_key's */
++ struct hlist_head head;
++ /* current_key and rnext_key aren't maintained on listen sockets.
++ * Their purpose is to cache keys on established connections,
++ * saving needless lookups. Never dereference any of them from
++ * listen sockets.
++ * ::current_key may change in RX to the key that was requested by
++ * the peer, please use READ_ONCE()/WRITE_ONCE() in order to avoid
++ * load/store tearing.
++ * Do the same for ::rnext_key, if you don't hold socket lock
++ * (it's changed only by userspace request in setsockopt()).
++ */
++ struct tcp_ao_key *current_key;
++ struct tcp_ao_key *rnext_key;
++ u32 flags;
++ __be32 lisn;
++ __be32 risn;
++ struct rcu_head rcu;
++};
++
++#endif /* _TCP_AO_H */
+diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h
+index d1d08da6331ab..bf93a80809d6a 100644
+--- a/include/uapi/linux/tcp.h
++++ b/include/uapi/linux/tcp.h
+@@ -360,6 +360,8 @@ struct tcp_diag_md5sig {
+ __u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN];
+ };
+
++#define TCP_AO_MAXKEYLEN 80
++
+ /* setsockopt(fd, IPPROTO_TCP, TCP_ZEROCOPY_RECEIVE, ...) */
+
+ #define TCP_RECEIVE_ZEROCOPY_FLAG_TLB_CLEAN_HINT 0x1
+diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
+index 89e2ab023272f..8e94ed7c56a0e 100644
+--- a/net/ipv4/Kconfig
++++ b/net/ipv4/Kconfig
+@@ -744,6 +744,19 @@ config DEFAULT_TCP_CONG
+ config TCP_SIGPOOL
+ tristate
+
++config TCP_AO
++ bool "TCP: Authentication Option (RFC5925)"
++ select CRYPTO
++ select TCP_SIGPOOL
++ depends on 64BIT && IPV6 != m # seq-number extension needs WRITE_ONCE(u64)
++ help
++ TCP-AO specifies the use of stronger Message Authentication Codes (MACs),
++ protects against replays for long-lived TCP connections, and
++ provides more details on the association of security with TCP
++ connections than TCP MD5 (See RFC5925)
++
++ If unsure, say N.
++
+ config TCP_MD5SIG
+ bool "TCP: MD5 Signature Option support (RFC2385)"
+ select CRYPTO
+--
+2.53.0
+
--- /dev/null
+From 8917d63c7fb7265415692a74297683511f001bee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 23 Oct 2023 20:21:53 +0100
+Subject: net/tcp: Prepare tcp_md5sig_pool for TCP-AO
+
+From: Dmitry Safonov <dima@arista.com>
+
+[ Upstream commit 8c73b26315aadb82218360d0a9a05e515f6e4118 ]
+
+TCP-AO, similarly to TCP-MD5, needs to allocate tfms on a slow-path,
+which is setsockopt() and use crypto ahash requests on fast paths,
+which are RX/TX softirqs. Also, it needs a temporary/scratch buffer
+for preparing the hash.
+
+Rework tcp_md5sig_pool in order to support other hashing algorithms
+than MD5. It will make it possible to share pre-allocated crypto_ahash
+descriptors and scratch area between all TCP hash users.
+
+Internally tcp_sigpool calls crypto_clone_ahash() API over pre-allocated
+crypto ahash tfm. Kudos to Herbert, who provided this new crypto API.
+
+I was a little concerned over GFP_ATOMIC allocations of ahash and
+crypto_request in RX/TX (see tcp_sigpool_start()), so I benchmarked both
+"backends" with different algorithms, using patched version of iperf3[2].
+On my laptop with i7-7600U @ 2.80GHz:
+
+ clone-tfm per-CPU-requests
+TCP-MD5 2.25 Gbits/sec 2.30 Gbits/sec
+TCP-AO(hmac(sha1)) 2.53 Gbits/sec 2.54 Gbits/sec
+TCP-AO(hmac(sha512)) 1.67 Gbits/sec 1.64 Gbits/sec
+TCP-AO(hmac(sha384)) 1.77 Gbits/sec 1.80 Gbits/sec
+TCP-AO(hmac(sha224)) 1.29 Gbits/sec 1.30 Gbits/sec
+TCP-AO(hmac(sha3-512)) 481 Mbits/sec 480 Mbits/sec
+TCP-AO(hmac(md5)) 2.07 Gbits/sec 2.12 Gbits/sec
+TCP-AO(hmac(rmd160)) 1.01 Gbits/sec 995 Mbits/sec
+TCP-AO(cmac(aes128)) [not supporetd yet] 2.11 Gbits/sec
+
+So, it seems that my concerns don't have strong grounds and per-CPU
+crypto_request allocation can be dropped/removed from tcp_sigpool once
+ciphers get crypto_clone_ahash() support.
+
+[1]: https://lore.kernel.org/all/ZDefxOq6Ax0JeTRH@gondor.apana.org.au/T/#u
+[2]: https://github.com/0x7f454c46/iperf/tree/tcp-md5-ao
+Signed-off-by: Dmitry Safonov <dima@arista.com>
+Reviewed-by: Steen Hegelund <Steen.Hegelund@microchip.com>
+Acked-by: David Ahern <dsahern@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: d0c80dbb9704 ("net/atm: fix slab-out-of-bounds read in vcc_setsockopt()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/tcp.h | 50 ++++--
+ net/ipv4/Kconfig | 4 +
+ net/ipv4/Makefile | 1 +
+ net/ipv4/tcp.c | 145 +++-------------
+ net/ipv4/tcp_ipv4.c | 97 ++++++-----
+ net/ipv4/tcp_minisocks.c | 21 ++-
+ net/ipv4/tcp_sigpool.c | 358 +++++++++++++++++++++++++++++++++++++++
+ net/ipv6/tcp_ipv6.c | 60 +++----
+ 8 files changed, 525 insertions(+), 211 deletions(-)
+ create mode 100644 net/ipv4/tcp_sigpool.c
+
+diff --git a/include/net/tcp.h b/include/net/tcp.h
+index a6def0aab3ed3..9c3ec3200e27b 100644
+--- a/include/net/tcp.h
++++ b/include/net/tcp.h
+@@ -1730,12 +1730,39 @@ union tcp_md5sum_block {
+ #endif
+ };
+
+-/* - pool: digest algorithm, hash description and scratch buffer */
+-struct tcp_md5sig_pool {
+- struct ahash_request *md5_req;
+- void *scratch;
++/*
++ * struct tcp_sigpool - per-CPU pool of ahash_requests
++ * @scratch: per-CPU temporary area, that can be used between
++ * tcp_sigpool_start() and tcp_sigpool_end() to perform
++ * crypto request
++ * @req: pre-allocated ahash request
++ */
++struct tcp_sigpool {
++ void *scratch;
++ struct ahash_request *req;
+ };
+
++int tcp_sigpool_alloc_ahash(const char *alg, size_t scratch_size);
++void tcp_sigpool_get(unsigned int id);
++void tcp_sigpool_release(unsigned int id);
++int tcp_sigpool_hash_skb_data(struct tcp_sigpool *hp,
++ const struct sk_buff *skb,
++ unsigned int header_len);
++
++/**
++ * tcp_sigpool_start - disable bh and start using tcp_sigpool_ahash
++ * @id: tcp_sigpool that was previously allocated by tcp_sigpool_alloc_ahash()
++ * @c: returned tcp_sigpool for usage (uninitialized on failure)
++ *
++ * Returns 0 on success, error otherwise.
++ */
++int tcp_sigpool_start(unsigned int id, struct tcp_sigpool *c);
++/**
++ * tcp_sigpool_end - enable bh and stop using tcp_sigpool
++ * @c: tcp_sigpool context that was returned by tcp_sigpool_start()
++ */
++void tcp_sigpool_end(struct tcp_sigpool *c);
++size_t tcp_sigpool_algo(unsigned int id, char *buf, size_t buf_len);
+ /* - functions */
+ int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key,
+ const struct sock *sk, const struct sk_buff *skb);
+@@ -1791,17 +1818,12 @@ tcp_inbound_md5_hash(const struct sock *sk, const struct sk_buff *skb,
+ #define tcp_twsk_md5_key(twsk) NULL
+ #endif
+
+-bool tcp_alloc_md5sig_pool(void);
+-
+-struct tcp_md5sig_pool *tcp_get_md5sig_pool(void);
+-static inline void tcp_put_md5sig_pool(void)
+-{
+- local_bh_enable();
+-}
++int tcp_md5_alloc_sigpool(void);
++void tcp_md5_release_sigpool(void);
++void tcp_md5_add_sigpool(void);
++extern int tcp_md5_sigpool_id;
+
+-int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, const struct sk_buff *,
+- unsigned int header_len);
+-int tcp_md5_hash_key(struct tcp_md5sig_pool *hp,
++int tcp_md5_hash_key(struct tcp_sigpool *hp,
+ const struct tcp_md5sig_key *key);
+
+ /* From tcp_fastopen.c */
+diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
+index 2dfb12230f089..89e2ab023272f 100644
+--- a/net/ipv4/Kconfig
++++ b/net/ipv4/Kconfig
+@@ -741,10 +741,14 @@ config DEFAULT_TCP_CONG
+ default "bbr" if DEFAULT_BBR
+ default "cubic"
+
++config TCP_SIGPOOL
++ tristate
++
+ config TCP_MD5SIG
+ bool "TCP: MD5 Signature Option support (RFC2385)"
+ select CRYPTO
+ select CRYPTO_MD5
++ select TCP_SIGPOOL
+ help
+ RFC2385 specifies a method of giving MD5 protection to TCP sessions.
+ Its main (only?) use is to protect BGP sessions between core routers
+diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
+index b18ba8ef93ad2..cd760793cfcba 100644
+--- a/net/ipv4/Makefile
++++ b/net/ipv4/Makefile
+@@ -62,6 +62,7 @@ obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o
+ obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o
+ obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o
+ obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o
++obj-$(CONFIG_TCP_SIGPOOL) += tcp_sigpool.o
+ obj-$(CONFIG_NET_SOCK_MSG) += tcp_bpf.o
+ obj-$(CONFIG_BPF_SYSCALL) += udp_bpf.o
+ obj-$(CONFIG_NETLABEL) += cipso_ipv4.o
+diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
+index 5b1fbb0ca2ff6..f05d1699683ff 100644
+--- a/net/ipv4/tcp.c
++++ b/net/ipv4/tcp.c
+@@ -4365,141 +4365,52 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
+ EXPORT_SYMBOL(tcp_getsockopt);
+
+ #ifdef CONFIG_TCP_MD5SIG
+-static DEFINE_PER_CPU(struct tcp_md5sig_pool, tcp_md5sig_pool);
+-static DEFINE_MUTEX(tcp_md5sig_mutex);
+-static bool tcp_md5sig_pool_populated = false;
++int tcp_md5_sigpool_id = -1;
++EXPORT_SYMBOL_GPL(tcp_md5_sigpool_id);
+
+-static void __tcp_alloc_md5sig_pool(void)
++int tcp_md5_alloc_sigpool(void)
+ {
+- struct crypto_ahash *hash;
+- int cpu;
+-
+- hash = crypto_alloc_ahash("md5", 0, CRYPTO_ALG_ASYNC);
+- if (IS_ERR(hash))
+- return;
+-
+- for_each_possible_cpu(cpu) {
+- void *scratch = per_cpu(tcp_md5sig_pool, cpu).scratch;
+- struct ahash_request *req;
+-
+- if (!scratch) {
+- scratch = kmalloc_node(sizeof(union tcp_md5sum_block) +
+- sizeof(struct tcphdr),
+- GFP_KERNEL,
+- cpu_to_node(cpu));
+- if (!scratch)
+- return;
+- per_cpu(tcp_md5sig_pool, cpu).scratch = scratch;
+- }
+- if (per_cpu(tcp_md5sig_pool, cpu).md5_req)
+- continue;
+-
+- req = ahash_request_alloc(hash, GFP_KERNEL);
+- if (!req)
+- return;
+-
+- ahash_request_set_callback(req, 0, NULL, NULL);
+-
+- per_cpu(tcp_md5sig_pool, cpu).md5_req = req;
+- }
+- /* before setting tcp_md5sig_pool_populated, we must commit all writes
+- * to memory. See smp_rmb() in tcp_get_md5sig_pool()
+- */
+- smp_wmb();
+- /* Paired with READ_ONCE() from tcp_alloc_md5sig_pool()
+- * and tcp_get_md5sig_pool().
+- */
+- WRITE_ONCE(tcp_md5sig_pool_populated, true);
+-}
+-
+-bool tcp_alloc_md5sig_pool(void)
+-{
+- /* Paired with WRITE_ONCE() from __tcp_alloc_md5sig_pool() */
+- if (unlikely(!READ_ONCE(tcp_md5sig_pool_populated))) {
+- mutex_lock(&tcp_md5sig_mutex);
+-
+- if (!tcp_md5sig_pool_populated)
+- __tcp_alloc_md5sig_pool();
++ size_t scratch_size;
++ int ret;
+
+- mutex_unlock(&tcp_md5sig_mutex);
++ scratch_size = sizeof(union tcp_md5sum_block) + sizeof(struct tcphdr);
++ ret = tcp_sigpool_alloc_ahash("md5", scratch_size);
++ if (ret >= 0) {
++ /* As long as any md5 sigpool was allocated, the return
++ * id would stay the same. Re-write the id only for the case
++ * when previously all MD5 keys were deleted and this call
++ * allocates the first MD5 key, which may return a different
++ * sigpool id than was used previously.
++ */
++ WRITE_ONCE(tcp_md5_sigpool_id, ret); /* Avoids the compiler potentially being smart here */
++ return 0;
+ }
+- /* Paired with WRITE_ONCE() from __tcp_alloc_md5sig_pool() */
+- return READ_ONCE(tcp_md5sig_pool_populated);
++ return ret;
+ }
+-EXPORT_SYMBOL(tcp_alloc_md5sig_pool);
+-
+
+-/**
+- * tcp_get_md5sig_pool - get md5sig_pool for this user
+- *
+- * We use percpu structure, so if we succeed, we exit with preemption
+- * and BH disabled, to make sure another thread or softirq handling
+- * wont try to get same context.
+- */
+-struct tcp_md5sig_pool *tcp_get_md5sig_pool(void)
++void tcp_md5_release_sigpool(void)
+ {
+- local_bh_disable();
+-
+- /* Paired with WRITE_ONCE() from __tcp_alloc_md5sig_pool() */
+- if (READ_ONCE(tcp_md5sig_pool_populated)) {
+- /* coupled with smp_wmb() in __tcp_alloc_md5sig_pool() */
+- smp_rmb();
+- return this_cpu_ptr(&tcp_md5sig_pool);
+- }
+- local_bh_enable();
+- return NULL;
++ tcp_sigpool_release(READ_ONCE(tcp_md5_sigpool_id));
+ }
+-EXPORT_SYMBOL(tcp_get_md5sig_pool);
+
+-int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp,
+- const struct sk_buff *skb, unsigned int header_len)
++void tcp_md5_add_sigpool(void)
+ {
+- struct scatterlist sg;
+- const struct tcphdr *tp = tcp_hdr(skb);
+- struct ahash_request *req = hp->md5_req;
+- unsigned int i;
+- const unsigned int head_data_len = skb_headlen(skb) > header_len ?
+- skb_headlen(skb) - header_len : 0;
+- const struct skb_shared_info *shi = skb_shinfo(skb);
+- struct sk_buff *frag_iter;
+-
+- sg_init_table(&sg, 1);
+-
+- sg_set_buf(&sg, ((u8 *) tp) + header_len, head_data_len);
+- ahash_request_set_crypt(req, &sg, NULL, head_data_len);
+- if (crypto_ahash_update(req))
+- return 1;
+-
+- for (i = 0; i < shi->nr_frags; ++i) {
+- const skb_frag_t *f = &shi->frags[i];
+- unsigned int offset = skb_frag_off(f);
+- struct page *page = skb_frag_page(f) + (offset >> PAGE_SHIFT);
+-
+- sg_set_page(&sg, page, skb_frag_size(f),
+- offset_in_page(offset));
+- ahash_request_set_crypt(req, &sg, NULL, skb_frag_size(f));
+- if (crypto_ahash_update(req))
+- return 1;
+- }
+-
+- skb_walk_frags(skb, frag_iter)
+- if (tcp_md5_hash_skb_data(hp, frag_iter, 0))
+- return 1;
+-
+- return 0;
++ tcp_sigpool_get(READ_ONCE(tcp_md5_sigpool_id));
+ }
+-EXPORT_SYMBOL(tcp_md5_hash_skb_data);
+
+-int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, const struct tcp_md5sig_key *key)
++int tcp_md5_hash_key(struct tcp_sigpool *hp,
++ const struct tcp_md5sig_key *key)
+ {
+ u8 keylen = READ_ONCE(key->keylen); /* paired with WRITE_ONCE() in tcp_md5_do_add */
+ struct scatterlist sg;
+
+ sg_init_one(&sg, key->key, keylen);
+- ahash_request_set_crypt(hp->md5_req, &sg, NULL, keylen);
++ ahash_request_set_crypt(hp->req, &sg, NULL, keylen);
+
+- /* We use data_race() because tcp_md5_do_add() might change key->key under us */
+- return data_race(crypto_ahash_update(hp->md5_req));
++ /* We use data_race() because tcp_md5_do_add() might change
++ * key->key under us
++ */
++ return data_race(crypto_ahash_update(hp->req));
+ }
+ EXPORT_SYMBOL(tcp_md5_hash_key);
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index 868a593d63ad2..0255f149885eb 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -1227,10 +1227,6 @@ static int __tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
+ key = sock_kmalloc(sk, sizeof(*key), gfp | __GFP_ZERO);
+ if (!key)
+ return -ENOMEM;
+- if (!tcp_alloc_md5sig_pool()) {
+- sock_kfree_s(sk, key, sizeof(*key));
+- return -ENOMEM;
+- }
+
+ memcpy(key->key, newkey, newkeylen);
+ key->keylen = newkeylen;
+@@ -1252,8 +1248,13 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
+ struct tcp_sock *tp = tcp_sk(sk);
+
+ if (!rcu_dereference_protected(tp->md5sig_info, lockdep_sock_is_held(sk))) {
+- if (tcp_md5sig_info_add(sk, GFP_KERNEL))
++ if (tcp_md5_alloc_sigpool())
++ return -ENOMEM;
++
++ if (tcp_md5sig_info_add(sk, GFP_KERNEL)) {
++ tcp_md5_release_sigpool();
+ return -ENOMEM;
++ }
+
+ if (!static_branch_inc(&tcp_md5_needed.key)) {
+ struct tcp_md5sig_info *md5sig;
+@@ -1261,6 +1262,7 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
+ md5sig = rcu_dereference_protected(tp->md5sig_info, lockdep_sock_is_held(sk));
+ rcu_assign_pointer(tp->md5sig_info, NULL);
+ kfree_rcu(md5sig, rcu);
++ tcp_md5_release_sigpool();
+ return -EUSERS;
+ }
+ }
+@@ -1277,8 +1279,12 @@ int tcp_md5_key_copy(struct sock *sk, const union tcp_md5_addr *addr,
+ struct tcp_sock *tp = tcp_sk(sk);
+
+ if (!rcu_dereference_protected(tp->md5sig_info, lockdep_sock_is_held(sk))) {
+- if (tcp_md5sig_info_add(sk, sk_gfp_mask(sk, GFP_ATOMIC)))
++ tcp_md5_add_sigpool();
++
++ if (tcp_md5sig_info_add(sk, sk_gfp_mask(sk, GFP_ATOMIC))) {
++ tcp_md5_release_sigpool();
+ return -ENOMEM;
++ }
+
+ if (!static_key_fast_inc_not_disabled(&tcp_md5_needed.key.key)) {
+ struct tcp_md5sig_info *md5sig;
+@@ -1287,6 +1293,7 @@ int tcp_md5_key_copy(struct sock *sk, const union tcp_md5_addr *addr,
+ net_warn_ratelimited("Too many TCP-MD5 keys in the system\n");
+ rcu_assign_pointer(tp->md5sig_info, NULL);
+ kfree_rcu(md5sig, rcu);
++ tcp_md5_release_sigpool();
+ return -EUSERS;
+ }
+ }
+@@ -1386,7 +1393,7 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, int optname,
+ cmd.tcpm_key, cmd.tcpm_keylen);
+ }
+
+-static int tcp_v4_md5_hash_headers(struct tcp_md5sig_pool *hp,
++static int tcp_v4_md5_hash_headers(struct tcp_sigpool *hp,
+ __be32 daddr, __be32 saddr,
+ const struct tcphdr *th, int nbytes)
+ {
+@@ -1406,38 +1413,35 @@ static int tcp_v4_md5_hash_headers(struct tcp_md5sig_pool *hp,
+ _th->check = 0;
+
+ sg_init_one(&sg, bp, sizeof(*bp) + sizeof(*th));
+- ahash_request_set_crypt(hp->md5_req, &sg, NULL,
++ ahash_request_set_crypt(hp->req, &sg, NULL,
+ sizeof(*bp) + sizeof(*th));
+- return crypto_ahash_update(hp->md5_req);
++ return crypto_ahash_update(hp->req);
+ }
+
+ static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
+ __be32 daddr, __be32 saddr, const struct tcphdr *th)
+ {
+- struct tcp_md5sig_pool *hp;
+- struct ahash_request *req;
++ struct tcp_sigpool hp;
+
+- hp = tcp_get_md5sig_pool();
+- if (!hp)
+- goto clear_hash_noput;
+- req = hp->md5_req;
++ if (tcp_sigpool_start(tcp_md5_sigpool_id, &hp))
++ goto clear_hash_nostart;
+
+- if (crypto_ahash_init(req))
++ if (crypto_ahash_init(hp.req))
+ goto clear_hash;
+- if (tcp_v4_md5_hash_headers(hp, daddr, saddr, th, th->doff << 2))
++ if (tcp_v4_md5_hash_headers(&hp, daddr, saddr, th, th->doff << 2))
+ goto clear_hash;
+- if (tcp_md5_hash_key(hp, key))
++ if (tcp_md5_hash_key(&hp, key))
+ goto clear_hash;
+- ahash_request_set_crypt(req, NULL, md5_hash, 0);
+- if (crypto_ahash_final(req))
++ ahash_request_set_crypt(hp.req, NULL, md5_hash, 0);
++ if (crypto_ahash_final(hp.req))
+ goto clear_hash;
+
+- tcp_put_md5sig_pool();
++ tcp_sigpool_end(&hp);
+ return 0;
+
+ clear_hash:
+- tcp_put_md5sig_pool();
+-clear_hash_noput:
++ tcp_sigpool_end(&hp);
++clear_hash_nostart:
+ memset(md5_hash, 0, 16);
+ return 1;
+ }
+@@ -1446,9 +1450,8 @@ int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key,
+ const struct sock *sk,
+ const struct sk_buff *skb)
+ {
+- struct tcp_md5sig_pool *hp;
+- struct ahash_request *req;
+ const struct tcphdr *th = tcp_hdr(skb);
++ struct tcp_sigpool hp;
+ __be32 saddr, daddr;
+
+ if (sk) { /* valid for establish/request sockets */
+@@ -1460,30 +1463,28 @@ int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key,
+ daddr = iph->daddr;
+ }
+
+- hp = tcp_get_md5sig_pool();
+- if (!hp)
+- goto clear_hash_noput;
+- req = hp->md5_req;
++ if (tcp_sigpool_start(tcp_md5_sigpool_id, &hp))
++ goto clear_hash_nostart;
+
+- if (crypto_ahash_init(req))
++ if (crypto_ahash_init(hp.req))
+ goto clear_hash;
+
+- if (tcp_v4_md5_hash_headers(hp, daddr, saddr, th, skb->len))
++ if (tcp_v4_md5_hash_headers(&hp, daddr, saddr, th, skb->len))
+ goto clear_hash;
+- if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
++ if (tcp_sigpool_hash_skb_data(&hp, skb, th->doff << 2))
+ goto clear_hash;
+- if (tcp_md5_hash_key(hp, key))
++ if (tcp_md5_hash_key(&hp, key))
+ goto clear_hash;
+- ahash_request_set_crypt(req, NULL, md5_hash, 0);
+- if (crypto_ahash_final(req))
++ ahash_request_set_crypt(hp.req, NULL, md5_hash, 0);
++ if (crypto_ahash_final(hp.req))
+ goto clear_hash;
+
+- tcp_put_md5sig_pool();
++ tcp_sigpool_end(&hp);
+ return 0;
+
+ clear_hash:
+- tcp_put_md5sig_pool();
+-clear_hash_noput:
++ tcp_sigpool_end(&hp);
++clear_hash_nostart:
+ memset(md5_hash, 0, 16);
+ return 1;
+ }
+@@ -2311,6 +2312,18 @@ static int tcp_v4_init_sock(struct sock *sk)
+ return 0;
+ }
+
++#ifdef CONFIG_TCP_MD5SIG
++static void tcp_md5sig_info_free_rcu(struct rcu_head *head)
++{
++ struct tcp_md5sig_info *md5sig;
++
++ md5sig = container_of(head, struct tcp_md5sig_info, rcu);
++ kfree(md5sig);
++ static_branch_slow_dec_deferred(&tcp_md5_needed);
++ tcp_md5_release_sigpool();
++}
++#endif
++
+ void tcp_v4_destroy_sock(struct sock *sk)
+ {
+ struct tcp_sock *tp = tcp_sk(sk);
+@@ -2335,10 +2348,12 @@ void tcp_v4_destroy_sock(struct sock *sk)
+ #ifdef CONFIG_TCP_MD5SIG
+ /* Clean up the MD5 key list, if any */
+ if (tp->md5sig_info) {
++ struct tcp_md5sig_info *md5sig;
++
++ md5sig = rcu_dereference_protected(tp->md5sig_info, 1);
+ tcp_clear_md5_list(sk);
+- kfree_rcu(rcu_dereference_protected(tp->md5sig_info, 1), rcu);
+- tp->md5sig_info = NULL;
+- static_branch_slow_dec_deferred(&tcp_md5_needed);
++ call_rcu(&md5sig->rcu, tcp_md5sig_info_free_rcu);
++ rcu_assign_pointer(tp->md5sig_info, NULL);
+ }
+ #endif
+
+diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
+index 2eea9672ca01e..c3f5e4fc7b210 100644
+--- a/net/ipv4/tcp_minisocks.c
++++ b/net/ipv4/tcp_minisocks.c
+@@ -261,10 +261,9 @@ static void tcp_time_wait_init(struct sock *sk, struct tcp_timewait_sock *tcptw)
+ tcptw->tw_md5_key = kmemdup(key, sizeof(*key), GFP_ATOMIC);
+ if (!tcptw->tw_md5_key)
+ return;
+- if (!tcp_alloc_md5sig_pool())
+- goto out_free;
+ if (!static_key_fast_inc_not_disabled(&tcp_md5_needed.key.key))
+ goto out_free;
++ tcp_md5_add_sigpool();
+ }
+ return;
+ out_free:
+@@ -348,16 +347,26 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
+ }
+ EXPORT_SYMBOL(tcp_time_wait);
+
++#ifdef CONFIG_TCP_MD5SIG
++static void tcp_md5_twsk_free_rcu(struct rcu_head *head)
++{
++ struct tcp_md5sig_key *key;
++
++ key = container_of(head, struct tcp_md5sig_key, rcu);
++ kfree(key);
++ static_branch_slow_dec_deferred(&tcp_md5_needed);
++ tcp_md5_release_sigpool();
++}
++#endif
++
+ void tcp_twsk_destructor(struct sock *sk)
+ {
+ #ifdef CONFIG_TCP_MD5SIG
+ if (static_branch_unlikely(&tcp_md5_needed.key)) {
+ struct tcp_timewait_sock *twsk = tcp_twsk(sk);
+
+- if (twsk->tw_md5_key) {
+- kfree_rcu(twsk->tw_md5_key, rcu);
+- static_branch_slow_dec_deferred(&tcp_md5_needed);
+- }
++ if (twsk->tw_md5_key)
++ call_rcu(&twsk->tw_md5_key->rcu, tcp_md5_twsk_free_rcu);
+ }
+ #endif
+ }
+diff --git a/net/ipv4/tcp_sigpool.c b/net/ipv4/tcp_sigpool.c
+new file mode 100644
+index 0000000000000..65a8eaae2fec6
+--- /dev/null
++++ b/net/ipv4/tcp_sigpool.c
+@@ -0,0 +1,358 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++
++#include <crypto/hash.h>
++#include <linux/cpu.h>
++#include <linux/kref.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/percpu.h>
++#include <linux/workqueue.h>
++#include <net/tcp.h>
++
++static size_t __scratch_size;
++static DEFINE_PER_CPU(void __rcu *, sigpool_scratch);
++
++struct sigpool_entry {
++ struct crypto_ahash *hash;
++ const char *alg;
++ struct kref kref;
++ uint16_t needs_key:1,
++ reserved:15;
++};
++
++#define CPOOL_SIZE (PAGE_SIZE / sizeof(struct sigpool_entry))
++static struct sigpool_entry cpool[CPOOL_SIZE];
++static unsigned int cpool_populated;
++static DEFINE_MUTEX(cpool_mutex);
++
++/* Slow-path */
++struct scratches_to_free {
++ struct rcu_head rcu;
++ unsigned int cnt;
++ void *scratches[];
++};
++
++static void free_old_scratches(struct rcu_head *head)
++{
++ struct scratches_to_free *stf;
++
++ stf = container_of(head, struct scratches_to_free, rcu);
++ while (stf->cnt--)
++ kfree(stf->scratches[stf->cnt]);
++ kfree(stf);
++}
++
++/**
++ * sigpool_reserve_scratch - re-allocates scratch buffer, slow-path
++ * @size: request size for the scratch/temp buffer
++ */
++static int sigpool_reserve_scratch(size_t size)
++{
++ struct scratches_to_free *stf;
++ size_t stf_sz = struct_size(stf, scratches, num_possible_cpus());
++ int cpu, err = 0;
++
++ lockdep_assert_held(&cpool_mutex);
++ if (__scratch_size >= size)
++ return 0;
++
++ stf = kmalloc(stf_sz, GFP_KERNEL);
++ if (!stf)
++ return -ENOMEM;
++ stf->cnt = 0;
++
++ size = max(size, __scratch_size);
++ cpus_read_lock();
++ for_each_possible_cpu(cpu) {
++ void *scratch, *old_scratch;
++
++ scratch = kmalloc_node(size, GFP_KERNEL, cpu_to_node(cpu));
++ if (!scratch) {
++ err = -ENOMEM;
++ break;
++ }
++
++ old_scratch = rcu_replace_pointer(per_cpu(sigpool_scratch, cpu),
++ scratch, lockdep_is_held(&cpool_mutex));
++ if (!cpu_online(cpu) || !old_scratch) {
++ kfree(old_scratch);
++ continue;
++ }
++ stf->scratches[stf->cnt++] = old_scratch;
++ }
++ cpus_read_unlock();
++ if (!err)
++ __scratch_size = size;
++
++ call_rcu(&stf->rcu, free_old_scratches);
++ return err;
++}
++
++static void sigpool_scratch_free(void)
++{
++ int cpu;
++
++ for_each_possible_cpu(cpu)
++ kfree(rcu_replace_pointer(per_cpu(sigpool_scratch, cpu),
++ NULL, lockdep_is_held(&cpool_mutex)));
++ __scratch_size = 0;
++}
++
++static int __cpool_try_clone(struct crypto_ahash *hash)
++{
++ struct crypto_ahash *tmp;
++
++ tmp = crypto_clone_ahash(hash);
++ if (IS_ERR(tmp))
++ return PTR_ERR(tmp);
++
++ crypto_free_ahash(tmp);
++ return 0;
++}
++
++static int __cpool_alloc_ahash(struct sigpool_entry *e, const char *alg)
++{
++ struct crypto_ahash *cpu0_hash;
++ int ret;
++
++ e->alg = kstrdup(alg, GFP_KERNEL);
++ if (!e->alg)
++ return -ENOMEM;
++
++ cpu0_hash = crypto_alloc_ahash(alg, 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(cpu0_hash)) {
++ ret = PTR_ERR(cpu0_hash);
++ goto out_free_alg;
++ }
++
++ e->needs_key = crypto_ahash_get_flags(cpu0_hash) & CRYPTO_TFM_NEED_KEY;
++
++ ret = __cpool_try_clone(cpu0_hash);
++ if (ret)
++ goto out_free_cpu0_hash;
++ e->hash = cpu0_hash;
++ kref_init(&e->kref);
++ return 0;
++
++out_free_cpu0_hash:
++ crypto_free_ahash(cpu0_hash);
++out_free_alg:
++ kfree(e->alg);
++ e->alg = NULL;
++ return ret;
++}
++
++/**
++ * tcp_sigpool_alloc_ahash - allocates pool for ahash requests
++ * @alg: name of async hash algorithm
++ * @scratch_size: reserve a tcp_sigpool::scratch buffer of this size
++ */
++int tcp_sigpool_alloc_ahash(const char *alg, size_t scratch_size)
++{
++ int i, ret;
++
++ /* slow-path */
++ mutex_lock(&cpool_mutex);
++ ret = sigpool_reserve_scratch(scratch_size);
++ if (ret)
++ goto out;
++ for (i = 0; i < cpool_populated; i++) {
++ if (!cpool[i].alg)
++ continue;
++ if (strcmp(cpool[i].alg, alg))
++ continue;
++
++ if (kref_read(&cpool[i].kref) > 0)
++ kref_get(&cpool[i].kref);
++ else
++ kref_init(&cpool[i].kref);
++ ret = i;
++ goto out;
++ }
++
++ for (i = 0; i < cpool_populated; i++) {
++ if (!cpool[i].alg)
++ break;
++ }
++ if (i >= CPOOL_SIZE) {
++ ret = -ENOSPC;
++ goto out;
++ }
++
++ ret = __cpool_alloc_ahash(&cpool[i], alg);
++ if (!ret) {
++ ret = i;
++ if (i == cpool_populated)
++ cpool_populated++;
++ }
++out:
++ mutex_unlock(&cpool_mutex);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(tcp_sigpool_alloc_ahash);
++
++static void __cpool_free_entry(struct sigpool_entry *e)
++{
++ crypto_free_ahash(e->hash);
++ kfree(e->alg);
++ memset(e, 0, sizeof(*e));
++}
++
++static void cpool_cleanup_work_cb(struct work_struct *work)
++{
++ bool free_scratch = true;
++ unsigned int i;
++
++ mutex_lock(&cpool_mutex);
++ for (i = 0; i < cpool_populated; i++) {
++ if (kref_read(&cpool[i].kref) > 0) {
++ free_scratch = false;
++ continue;
++ }
++ if (!cpool[i].alg)
++ continue;
++ __cpool_free_entry(&cpool[i]);
++ }
++ if (free_scratch)
++ sigpool_scratch_free();
++ mutex_unlock(&cpool_mutex);
++}
++
++static DECLARE_WORK(cpool_cleanup_work, cpool_cleanup_work_cb);
++static void cpool_schedule_cleanup(struct kref *kref)
++{
++ schedule_work(&cpool_cleanup_work);
++}
++
++/**
++ * tcp_sigpool_release - decreases number of users for a pool. If it was
++ * the last user of the pool, releases any memory that was consumed.
++ * @id: tcp_sigpool that was previously allocated by tcp_sigpool_alloc_ahash()
++ */
++void tcp_sigpool_release(unsigned int id)
++{
++ if (WARN_ON_ONCE(id > cpool_populated || !cpool[id].alg))
++ return;
++
++ /* slow-path */
++ kref_put(&cpool[id].kref, cpool_schedule_cleanup);
++}
++EXPORT_SYMBOL_GPL(tcp_sigpool_release);
++
++/**
++ * tcp_sigpool_get - increases number of users (refcounter) for a pool
++ * @id: tcp_sigpool that was previously allocated by tcp_sigpool_alloc_ahash()
++ */
++void tcp_sigpool_get(unsigned int id)
++{
++ if (WARN_ON_ONCE(id > cpool_populated || !cpool[id].alg))
++ return;
++ kref_get(&cpool[id].kref);
++}
++EXPORT_SYMBOL_GPL(tcp_sigpool_get);
++
++int tcp_sigpool_start(unsigned int id, struct tcp_sigpool *c) __cond_acquires(RCU_BH)
++{
++ struct crypto_ahash *hash;
++
++ rcu_read_lock_bh();
++ if (WARN_ON_ONCE(id > cpool_populated || !cpool[id].alg)) {
++ rcu_read_unlock_bh();
++ return -EINVAL;
++ }
++
++ hash = crypto_clone_ahash(cpool[id].hash);
++ if (IS_ERR(hash)) {
++ rcu_read_unlock_bh();
++ return PTR_ERR(hash);
++ }
++
++ c->req = ahash_request_alloc(hash, GFP_ATOMIC);
++ if (!c->req) {
++ crypto_free_ahash(hash);
++ rcu_read_unlock_bh();
++ return -ENOMEM;
++ }
++ ahash_request_set_callback(c->req, 0, NULL, NULL);
++
++ /* Pairs with tcp_sigpool_reserve_scratch(), scratch area is
++ * valid (allocated) until tcp_sigpool_end().
++ */
++ c->scratch = rcu_dereference_bh(*this_cpu_ptr(&sigpool_scratch));
++ return 0;
++}
++EXPORT_SYMBOL_GPL(tcp_sigpool_start);
++
++void tcp_sigpool_end(struct tcp_sigpool *c) __releases(RCU_BH)
++{
++ struct crypto_ahash *hash = crypto_ahash_reqtfm(c->req);
++
++ rcu_read_unlock_bh();
++ ahash_request_free(c->req);
++ crypto_free_ahash(hash);
++}
++EXPORT_SYMBOL_GPL(tcp_sigpool_end);
++
++/**
++ * tcp_sigpool_algo - return algorithm of tcp_sigpool
++ * @id: tcp_sigpool that was previously allocated by tcp_sigpool_alloc_ahash()
++ * @buf: buffer to return name of algorithm
++ * @buf_len: size of @buf
++ */
++size_t tcp_sigpool_algo(unsigned int id, char *buf, size_t buf_len)
++{
++ if (WARN_ON_ONCE(id > cpool_populated || !cpool[id].alg))
++ return -EINVAL;
++
++ return strscpy(buf, cpool[id].alg, buf_len);
++}
++EXPORT_SYMBOL_GPL(tcp_sigpool_algo);
++
++/**
++ * tcp_sigpool_hash_skb_data - hash data in skb with initialized tcp_sigpool
++ * @hp: tcp_sigpool pointer
++ * @skb: buffer to add sign for
++ * @header_len: TCP header length for this segment
++ */
++int tcp_sigpool_hash_skb_data(struct tcp_sigpool *hp,
++ const struct sk_buff *skb,
++ unsigned int header_len)
++{
++ const unsigned int head_data_len = skb_headlen(skb) > header_len ?
++ skb_headlen(skb) - header_len : 0;
++ const struct skb_shared_info *shi = skb_shinfo(skb);
++ const struct tcphdr *tp = tcp_hdr(skb);
++ struct ahash_request *req = hp->req;
++ struct sk_buff *frag_iter;
++ struct scatterlist sg;
++ unsigned int i;
++
++ sg_init_table(&sg, 1);
++
++ sg_set_buf(&sg, ((u8 *)tp) + header_len, head_data_len);
++ ahash_request_set_crypt(req, &sg, NULL, head_data_len);
++ if (crypto_ahash_update(req))
++ return 1;
++
++ for (i = 0; i < shi->nr_frags; ++i) {
++ const skb_frag_t *f = &shi->frags[i];
++ unsigned int offset = skb_frag_off(f);
++ struct page *page;
++
++ page = skb_frag_page(f) + (offset >> PAGE_SHIFT);
++ sg_set_page(&sg, page, skb_frag_size(f), offset_in_page(offset));
++ ahash_request_set_crypt(req, &sg, NULL, skb_frag_size(f));
++ if (crypto_ahash_update(req))
++ return 1;
++ }
++
++ skb_walk_frags(skb, frag_iter)
++ if (tcp_sigpool_hash_skb_data(hp, frag_iter, 0))
++ return 1;
++
++ return 0;
++}
++EXPORT_SYMBOL(tcp_sigpool_hash_skb_data);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Per-CPU pool of crypto requests");
+diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
+index 2c579868fe81f..689c0b383ebf9 100644
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -665,7 +665,7 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, int optname,
+ cmd.tcpm_key, cmd.tcpm_keylen);
+ }
+
+-static int tcp_v6_md5_hash_headers(struct tcp_md5sig_pool *hp,
++static int tcp_v6_md5_hash_headers(struct tcp_sigpool *hp,
+ const struct in6_addr *daddr,
+ const struct in6_addr *saddr,
+ const struct tcphdr *th, int nbytes)
+@@ -686,39 +686,36 @@ static int tcp_v6_md5_hash_headers(struct tcp_md5sig_pool *hp,
+ _th->check = 0;
+
+ sg_init_one(&sg, bp, sizeof(*bp) + sizeof(*th));
+- ahash_request_set_crypt(hp->md5_req, &sg, NULL,
++ ahash_request_set_crypt(hp->req, &sg, NULL,
+ sizeof(*bp) + sizeof(*th));
+- return crypto_ahash_update(hp->md5_req);
++ return crypto_ahash_update(hp->req);
+ }
+
+ static int tcp_v6_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
+ const struct in6_addr *daddr, struct in6_addr *saddr,
+ const struct tcphdr *th)
+ {
+- struct tcp_md5sig_pool *hp;
+- struct ahash_request *req;
++ struct tcp_sigpool hp;
+
+- hp = tcp_get_md5sig_pool();
+- if (!hp)
+- goto clear_hash_noput;
+- req = hp->md5_req;
++ if (tcp_sigpool_start(tcp_md5_sigpool_id, &hp))
++ goto clear_hash_nostart;
+
+- if (crypto_ahash_init(req))
++ if (crypto_ahash_init(hp.req))
+ goto clear_hash;
+- if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, th->doff << 2))
++ if (tcp_v6_md5_hash_headers(&hp, daddr, saddr, th, th->doff << 2))
+ goto clear_hash;
+- if (tcp_md5_hash_key(hp, key))
++ if (tcp_md5_hash_key(&hp, key))
+ goto clear_hash;
+- ahash_request_set_crypt(req, NULL, md5_hash, 0);
+- if (crypto_ahash_final(req))
++ ahash_request_set_crypt(hp.req, NULL, md5_hash, 0);
++ if (crypto_ahash_final(hp.req))
+ goto clear_hash;
+
+- tcp_put_md5sig_pool();
++ tcp_sigpool_end(&hp);
+ return 0;
+
+ clear_hash:
+- tcp_put_md5sig_pool();
+-clear_hash_noput:
++ tcp_sigpool_end(&hp);
++clear_hash_nostart:
+ memset(md5_hash, 0, 16);
+ return 1;
+ }
+@@ -728,10 +725,9 @@ static int tcp_v6_md5_hash_skb(char *md5_hash,
+ const struct sock *sk,
+ const struct sk_buff *skb)
+ {
+- const struct in6_addr *saddr, *daddr;
+- struct tcp_md5sig_pool *hp;
+- struct ahash_request *req;
+ const struct tcphdr *th = tcp_hdr(skb);
++ const struct in6_addr *saddr, *daddr;
++ struct tcp_sigpool hp;
+
+ if (sk) { /* valid for establish/request sockets */
+ saddr = &sk->sk_v6_rcv_saddr;
+@@ -742,30 +738,28 @@ static int tcp_v6_md5_hash_skb(char *md5_hash,
+ daddr = &ip6h->daddr;
+ }
+
+- hp = tcp_get_md5sig_pool();
+- if (!hp)
+- goto clear_hash_noput;
+- req = hp->md5_req;
++ if (tcp_sigpool_start(tcp_md5_sigpool_id, &hp))
++ goto clear_hash_nostart;
+
+- if (crypto_ahash_init(req))
++ if (crypto_ahash_init(hp.req))
+ goto clear_hash;
+
+- if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, skb->len))
++ if (tcp_v6_md5_hash_headers(&hp, daddr, saddr, th, skb->len))
+ goto clear_hash;
+- if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
++ if (tcp_sigpool_hash_skb_data(&hp, skb, th->doff << 2))
+ goto clear_hash;
+- if (tcp_md5_hash_key(hp, key))
++ if (tcp_md5_hash_key(&hp, key))
+ goto clear_hash;
+- ahash_request_set_crypt(req, NULL, md5_hash, 0);
+- if (crypto_ahash_final(req))
++ ahash_request_set_crypt(hp.req, NULL, md5_hash, 0);
++ if (crypto_ahash_final(hp.req))
+ goto clear_hash;
+
+- tcp_put_md5sig_pool();
++ tcp_sigpool_end(&hp);
+ return 0;
+
+ clear_hash:
+- tcp_put_md5sig_pool();
+-clear_hash_noput:
++ tcp_sigpool_end(&hp);
++clear_hash_nostart:
+ memset(md5_hash, 0, 16);
+ return 1;
+ }
+--
+2.53.0
+
--- /dev/null
+From e4a98c4d2af4456541dca21224fa7c707150ae56 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 14:38:50 +0000
+Subject: net: thunderbolt: Tear down DMA paths before stopping the rings
+
+From: Fan XinRan <shinjiangjiang@gmail.com>
+
+[ Upstream commit 68bf02b6b4ad3f748c6db71fd77b6c0402d252f4 ]
+
+tbnet_tear_down() stops both rings and frees their frame buffers before
+calling tb_xdomain_disable_paths(). tb_ring_stop() zeroes the ring's
+descriptor base and tbnet_free_buffers() unmaps and frees the pages the
+frames sit in, so by the time __tb_path_deactivate_hop() polls the hop's
+'pending' bit, anything still in flight has nowhere to drain to.
+
+The teardown sequence has been in this order since the driver was added.
+The setup path has not: commit ff7cd07f3064 ("net: thunderbolt: Enable
+DMA paths only after rings are enabled") moved the path enable to the end
+of tbnet_connected_work() and documented why:
+
+ /* Both logins successful so enable the rings, high-speed DMA
+ * paths and start the network device queue.
+ *
+ * Note we enable the DMA paths last to make sure we have primed
+ * the Rx ring before any incoming packets are allowed to
+ * arrive.
+ */
+
+Teardown was never updated to match, so the rings and the paths now come
+down in the same order they go up instead of in reverse.
+
+On an ASMedia ASM4242 host router the 'pending' bit then never clears:
+every teardown burns the full 500 ms timeout and
+__tb_path_deactivate_hop() returns -ETIMEDOUT. Raising the timeout to
+5 s does not help, so the hop is not slow to drain, it never drains
+at all.
+
+The failure is invisible above the thunderbolt core.
+__tb_path_deactivate_hops() is void and only calls tb_port_warn();
+tb_path_deactivate(), tb_tunnel_deactivate() and
+__tb_disconnect_xdomain_paths() are void as well, and
+tb_disconnect_xdomain_paths() ends in an unconditional "return 0". So
+tb_xdomain_disable_paths() reports success and the netdev_warn() below
+it never fires. Repeated teardowns eventually take the XDomain control
+channel down, after which the peer node is gone and only a power cycle
+brings the controller back.
+
+Deactivating the paths first fixes it. Measured with kretprobes on a
+stock v6.17 tree with no other patches applied, on a link that was up
+and had just carried traffic:
+
+ before: __tb_path_deactivate_hop() returns 0 for the first hop, then
+ -ETIMEDOUT for the second 500335 us later
+ after: 0 for both, 525 us apart
+
+Alternating the two orderings ABBA over three load levels, four
+teardowns per arm: every teardown failed before the change (21 of 21
+that ran), none failed after (0 of 24). The before arms ran short
+because the link died partway through. The same split shows up when
+the interface is enslaved to a bond instead of just brought down, which
+is how I ran into this in the first place. Throughput and latency after
+the change are unchanged.
+
+Hosts whose routers drain the hop despite the stale descriptor base see
+no functional difference, since the paths end up deactivated either way.
+
+Fixes: e69b6c02b4c3 ("net: Add support for networking over Thunderbolt cable")
+Signed-off-by: Fan XinRan <shinjiangjiang@gmail.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Link: https://patch.msgid.link/20260803-b4-tbnet-teardown-v2-1-27de6a13ca2d@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/thunderbolt/main.c | 20 +++++++++++++++-----
+ 1 file changed, 15 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c
+index 960839a651e51..ceaba08cd378a 100644
+--- a/drivers/net/thunderbolt/main.c
++++ b/drivers/net/thunderbolt/main.c
+@@ -389,11 +389,16 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)
+ break;
+ }
+
+- tb_ring_stop(net->rx_ring.ring);
+- tb_ring_stop(net->tx_ring.ring);
+- tbnet_free_buffers(&net->rx_ring);
+- tbnet_free_buffers(&net->tx_ring);
+-
++ /* Tear the paths down before stopping the rings. This mirrors
++ * tbnet_connected_work(), which enables the paths last so the
++ * Rx ring is primed before packets can arrive. Stopping a
++ * ring zeroes its descriptor base and tbnet_free_buffers()
++ * unmaps and frees the frame buffers, leaving anything still
++ * in flight with nowhere to drain to;
++ * __tb_path_deactivate_hop() then waits for the hop's
++ * 'pending' bit, which on some host routers never clears in
++ * that state.
++ */
+ ret = tb_xdomain_disable_paths(net->xd,
+ net->local_transmit_path,
+ net->tx_ring.ring->hop,
+@@ -402,6 +407,11 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)
+ if (ret)
+ netdev_warn(net->dev, "failed to disable DMA paths\n");
+
++ tb_ring_stop(net->rx_ring.ring);
++ tb_ring_stop(net->tx_ring.ring);
++ tbnet_free_buffers(&net->rx_ring);
++ tbnet_free_buffers(&net->tx_ring);
++
+ tb_xdomain_release_in_hopid(net->xd, net->remote_transmit_path);
+ net->remote_transmit_path = 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From 1e43c1acf9529cd4e04e08a0e3abdbe5eff64256 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 20:38:50 +0200
+Subject: netfilter: ipset: switch ext_size to atomic64_t
+
+From: Jozsef Kadlecsik <kadlec@netfilter.org>
+
+[ Upstream commit 712a6f545c359b427daa9a5a782e30d2f8331e25 ]
+
+The hash types do not acquire set->lock, they use 'region locking' where
+only part of the hash table is locked. Parallel inserts and deletes are
+possible and CPUs can race on ->ext_size update. Switch to atomic64_t.
+
+This leaves another bug unresolved: there still can be a race on
+comment extension re-init. This will be handled in a later commit
+when converting to rhashtable backend.
+
+Fixes: f66ee0410b1c ("netfilter: ipset: Fix "INFO: rcu detected stall in hash_xxx" reports")
+Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/netfilter/ipset/ip_set.h | 2 +-
+ net/netfilter/ipset/ip_set_bitmap_gen.h | 4 ++--
+ net/netfilter/ipset/ip_set_core.c | 6 +++---
+ net/netfilter/ipset/ip_set_hash_gen.h | 2 +-
+ net/netfilter/ipset/ip_set_list_set.c | 4 ++--
+ 5 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
+index b98331572ad29..cadae9b2578f1 100644
+--- a/include/linux/netfilter/ipset/ip_set.h
++++ b/include/linux/netfilter/ipset/ip_set.h
+@@ -273,7 +273,7 @@ struct ip_set {
+ /* Number of elements (vs timeout) */
+ u32 elements;
+ /* Size of the dynamic extensions (vs timeout) */
+- size_t ext_size;
++ atomic64_t ext_size;
+ /* Element data size */
+ size_t dsize;
+ /* Offsets to extensions in elements */
+diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h
+index 9523104a90da4..40f0383883f9d 100644
+--- a/net/netfilter/ipset/ip_set_bitmap_gen.h
++++ b/net/netfilter/ipset/ip_set_bitmap_gen.h
+@@ -75,7 +75,7 @@ mtype_flush(struct ip_set *set)
+ mtype_ext_cleanup(set);
+ bitmap_zero(map->members, map->elements);
+ set->elements = 0;
+- set->ext_size = 0;
++ atomic64_set(&set->ext_size, 0);
+ }
+
+ /* Calculate the actual memory size of the set data */
+@@ -91,7 +91,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
+ {
+ const struct mtype *map = set->data;
+ struct nlattr *nested;
+- size_t memsize = mtype_memsize(map, set->dsize) + set->ext_size;
++ size_t memsize = mtype_memsize(map, set->dsize) + atomic64_read(&set->ext_size);
+
+ nested = nla_nest_start(skb, IPSET_ATTR_DATA);
+ if (!nested)
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index f51a1af31513c..29bf5ee74fe36 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -350,7 +350,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
+ size_t len = ext->comment ? strlen(ext->comment) : 0;
+
+ if (unlikely(c)) {
+- set->ext_size -= sizeof(*c) + strlen(c->str) + 1;
++ atomic64_sub(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
+ rcu_assign_pointer(comment->c, NULL);
+ kfree_rcu(c, rcu);
+ }
+@@ -362,7 +362,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
+ if (unlikely(!c))
+ return;
+ strscpy(c->str, ext->comment, len + 1);
+- set->ext_size += sizeof(*c) + strlen(c->str) + 1;
++ atomic64_add(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
+ rcu_assign_pointer(comment->c, c);
+ }
+ EXPORT_SYMBOL_GPL(ip_set_init_comment);
+@@ -392,7 +392,7 @@ ip_set_comment_free(struct ip_set *set, void *ptr)
+ c = rcu_dereference_protected(comment->c, 1);
+ if (unlikely(!c))
+ return;
+- set->ext_size -= sizeof(*c) + strlen(c->str) + 1;
++ atomic64_sub(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
+ rcu_assign_pointer(comment->c, NULL);
+ kfree_rcu(c, rcu);
+ }
+diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
+index 81ad6747bc7a4..53b65f013594a 100644
+--- a/net/netfilter/ipset/ip_set_hash_gen.h
++++ b/net/netfilter/ipset/ip_set_hash_gen.h
+@@ -1288,7 +1288,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
+ rcu_read_lock_bh();
+ t = rcu_dereference_bh(h->table);
+ mtype_ext_size(set, &elements, &ext_size);
+- memsize = mtype_ahash_memsize(h, t) + ext_size + set->ext_size;
++ memsize = mtype_ahash_memsize(h, t) + ext_size + atomic64_read(&set->ext_size);
+ htable_bits = t->htable_bits;
+ rcu_read_unlock_bh();
+
+diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
+index 83e1fdcc752d6..9d6ab69ca1a37 100644
+--- a/net/netfilter/ipset/ip_set_list_set.c
++++ b/net/netfilter/ipset/ip_set_list_set.c
+@@ -421,7 +421,7 @@ list_set_flush(struct ip_set *set)
+ list_for_each_entry_safe(e, n, &map->members, list)
+ list_set_del(set, e);
+ set->elements = 0;
+- set->ext_size = 0;
++ atomic64_set(&set->ext_size, 0);
+ }
+
+ static void
+@@ -455,7 +455,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
+ {
+ const struct list_set *map = set->data;
+ struct nlattr *nested;
+- size_t memsize = list_set_memsize(map, set->dsize) + set->ext_size;
++ size_t memsize = list_set_memsize(map, set->dsize) + atomic64_read(&set->ext_size);
+
+ nested = nla_nest_start(skb, IPSET_ATTR_DATA);
+ if (!nested)
+--
+2.53.0
+
--- /dev/null
+From ed1bf91cdc5ba8071ddc04646dfc9256cc9ac3a6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 30 Jun 2026 14:31:00 -0400
+Subject: NFS: Pin the 'struct nfs_server' during a FREE_STATEID call
+
+From: Anna Schumaker <anna.schumaker@hammerspace.com>
+
+[ Upstream commit cf616096a0f3a2b60f7d68b6b39674a6867ded9c ]
+
+Dan Aloni reports that he was able to hit a use-after-free bug if a
+FREE_STATEID operation gets delayed for whatever reason. Fix this by
+bumping the refcount of the 'struct nfs_server' object for the duration
+of the FREE_STATEID so it doesn't get cleaned up from underneath us
+while operations are still in flight.
+
+Reported-by: Dan Aloni <dan.aloni@vastdata.com>
+Fixes: 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call")
+Tested-by: Dan Aloni <dan.aloni@vastdata.com>
+Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/nfs4proc.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index 42fa7c915e29b..ce3ab0a9c0ef7 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -10383,6 +10383,7 @@ static void nfs41_free_stateid_release(void *calldata)
+ struct nfs_free_stateid_data *data = calldata;
+ struct nfs_client *clp = data->server->nfs_client;
+
++ nfs_sb_deactive(data->server->super);
+ nfs_put_client(clp);
+ kfree(calldata);
+ }
+@@ -10424,6 +10425,10 @@ static int nfs41_free_stateid(struct nfs_server *server,
+
+ if (!refcount_inc_not_zero(&clp->cl_count))
+ return -EIO;
++ if (!nfs_sb_active(server->super)) {
++ nfs_put_client(clp);
++ return -EIO;
++ }
+
+ nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
+ &task_setup.rpc_client, &msg);
+--
+2.53.0
+
--- /dev/null
+From a425b1ed1110b9a585f510df8c6f7e64b67c0b86 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Apr 2024 18:40:09 -0500
+Subject: regulator: devres: add API for reference voltage supplies
+
+From: David Lechner <dlechner@baylibre.com>
+
+[ Upstream commit b250c20b64290808aa4b5cc6d68819a7ee28237f ]
+
+A common use case for regulators is to supply a reference voltage to an
+analog input or output device. This adds a new devres API to get,
+enable, and get the voltage in a single call. This allows eliminating
+boilerplate code in drivers that use reference supplies in this way.
+
+Signed-off-by: David Lechner <dlechner@baylibre.com>
+Link: https://lore.kernel.org/r/20240429-regulator-get-enable-get-votlage-v2-1-b1f11ab766c1@baylibre.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: fddb5ceaf901 ("hwmon: (ads7828) Fix external VREF regulator handling")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../driver-api/driver-model/devres.rst | 1 +
+ drivers/regulator/devres.c | 59 +++++++++++++++++++
+ include/linux/regulator/consumer.h | 7 +++
+ 3 files changed, 67 insertions(+)
+
+diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst
+index 8be086b3f8297..3fe1711dd587c 100644
+--- a/Documentation/driver-api/driver-model/devres.rst
++++ b/Documentation/driver-api/driver-model/devres.rst
+@@ -426,6 +426,7 @@ REGULATOR
+ devm_regulator_bulk_put()
+ devm_regulator_get()
+ devm_regulator_get_enable()
++ devm_regulator_get_enable_read_voltage()
+ devm_regulator_get_enable_optional()
+ devm_regulator_get_exclusive()
+ devm_regulator_get_optional()
+diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c
+index 90bb0d178885a..4f290b9b559b9 100644
+--- a/drivers/regulator/devres.c
++++ b/drivers/regulator/devres.c
+@@ -145,6 +145,65 @@ struct regulator *devm_regulator_get_optional(struct device *dev,
+ }
+ EXPORT_SYMBOL_GPL(devm_regulator_get_optional);
+
++/**
++ * devm_regulator_get_enable_read_voltage - Resource managed regulator get and
++ * enable that returns the voltage
++ * @dev: device to supply
++ * @id: supply name or regulator ID.
++ *
++ * Get and enable regulator for duration of the device life-time.
++ * regulator_disable() and regulator_put() are automatically called on driver
++ * detach. See regulator_get_optional(), regulator_enable(), and
++ * regulator_get_voltage() for more information.
++ *
++ * This is a convenience function for supplies that provide a reference voltage
++ * where the consumer driver just needs to know the voltage and keep the
++ * regulator enabled.
++ *
++ * In cases where the supply is not strictly required, callers can check for
++ * -ENODEV error and handle it accordingly.
++ *
++ * Returns: voltage in microvolts on success, or an error code on failure.
++ */
++int devm_regulator_get_enable_read_voltage(struct device *dev, const char *id)
++{
++ struct regulator *r;
++ int ret;
++
++ /*
++ * Since we need a real voltage, we use devm_regulator_get_optional()
++ * rather than getting a dummy regulator with devm_regulator_get() and
++ * then letting regulator_get_voltage() fail with -EINVAL. This way, the
++ * caller can handle the -ENODEV error code if needed instead of the
++ * ambiguous -EINVAL.
++ */
++ r = devm_regulator_get_optional(dev, id);
++ if (IS_ERR(r))
++ return PTR_ERR(r);
++
++ ret = regulator_enable(r);
++ if (ret)
++ goto err_regulator_put;
++
++ ret = devm_add_action_or_reset(dev, regulator_action_disable, r);
++ if (ret)
++ goto err_regulator_put;
++
++ ret = regulator_get_voltage(r);
++ if (ret < 0)
++ goto err_release_action;
++
++ return 0;
++
++err_release_action:
++ devm_release_action(dev, regulator_action_disable, r);
++err_regulator_put:
++ devm_regulator_put(r);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(devm_regulator_get_enable_read_voltage);
++
+ static int devm_regulator_match(struct device *dev, void *res, void *data)
+ {
+ struct regulator **r = res;
+diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
+index 25d0684d37b3e..9a2f1e9a94a85 100644
+--- a/include/linux/regulator/consumer.h
++++ b/include/linux/regulator/consumer.h
+@@ -209,6 +209,7 @@ struct regulator *__must_check devm_regulator_get_optional(struct device *dev,
+ const char *id);
+ int devm_regulator_get_enable(struct device *dev, const char *id);
+ int devm_regulator_get_enable_optional(struct device *dev, const char *id);
++int devm_regulator_get_enable_read_voltage(struct device *dev, const char *id);
+ void regulator_put(struct regulator *regulator);
+ void devm_regulator_put(struct regulator *regulator);
+
+@@ -374,6 +375,12 @@ static inline int devm_regulator_get_enable_optional(struct device *dev,
+ return 0;
+ }
+
++static inline int devm_regulator_get_enable_read_voltage(struct device *dev,
++ const char *id)
++{
++ return -ENODEV;
++}
++
+ static inline struct regulator *__must_check
+ regulator_get_optional(struct device *dev, const char *id)
+ {
+--
+2.53.0
+
--- /dev/null
+From bcaadac1036df10f32dd5435beeeb6b500d14337 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 12:29:48 +0000
+Subject: Revert "net: thunderbolt: Enable end-to-end flow control also in
+ transmit"
+
+From: Fan Ye <fy15309206903@gmail.com>
+
+[ Upstream commit 1881f2efbf7f78dc0a79a387b29fde6ff56d3731 ]
+
+This reverts commit a8065af3346ebd7c76ebc113451fb3ba94cf7769.
+
+Per the USB4 spec, a Transmit Descriptor Ring with E2E flow control
+disabled does not require any credits to be available before the Host
+Interface Adapter Layer transmits a tunneled packet from it. Once E2E is
+enabled on that ring the controller must first obtain end-to-end
+credits.
+
+The ASMedia ASM4242 USB4 host router (PCI 1b21:2425) never delivers
+those credits. The controller does accept the configuration: reading the
+ring OPTIONS register back right after tb_ring_start() returns exactly
+what was written, including RING_FLAG_E2E_FLOW_CONTROL (bit 28) and the
+E2E HopID field. No credit ever arrives though, so the Tx ring's
+hardware consumer index never advances and the link carries no traffic
+at all.
+
+Measured on two hosts connected point to point, onboard ASM4242 on MSI
+X870E and X870, v6.17, stock drivers/net/thunderbolt/main.c with only
+this revert applied on top:
+
+ before: 100% packet loss to the peer; thunderbolt0 is up and the
+ XDomain handshake completes ("new host found"), but iperf3
+ fails with "No route to host" once the neighbour entry
+ expires
+ after: 0% packet loss, 0.28 ms RTT; iperf3 4.21 Gb/s one way and
+ 5.17 Gb/s the other (5 runs each, stddev <= 0.02), 1
+ retransmit in 10 s
+
+An instrumented build additionally showed a frozen-Tx-consumer watchdog
+firing ~30k times in a 10 s window before this change.
+
+Rx-side E2E is not touched by this revert, so peers that do return
+credits keep receive-side flow control.
+
+ASMedia does not look like an isolated case. The out-of-tree
+thunderbolt-ibverbs project disables native E2E on AMD NHI by default,
+noting that "Strix Halo has reproduced TX completion wedges with
+multiple native E2E rings active" -- the same failure mode, on a
+different vendor. Since the driver has no way to tell in advance which
+host router returns the credits, going back to the previous behaviour
+looks safer than adding a quirk per affected part; Tx-side E2E can be
+reintroduced as an opt-in for controllers that are known to implement
+the credit return.
+
+Note that the reverted commit was not fixing a reported problem, it was
+derived from the spec wording alone, so this revert is not expected to
+regress a known workload. Cc'ing the original author in case there was
+one.
+
+Fixes: a8065af3346e ("net: thunderbolt: Enable end-to-end flow control also in transmit")
+Cc: zhangjianrong <zhangjianrong5@huawei.com>
+Signed-off-by: Fan Ye <fy15309206903@gmail.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Link: https://patch.msgid.link/20260727123002.25225-1-fy15309206903@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/thunderbolt/main.c | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c
+index 5d7d11d75b0b8..960839a651e51 100644
+--- a/drivers/net/thunderbolt/main.c
++++ b/drivers/net/thunderbolt/main.c
+@@ -928,12 +928,8 @@ static int tbnet_open(struct net_device *dev)
+
+ netif_carrier_off(dev);
+
+- flags = RING_FLAG_FRAME;
+- /* Only enable full E2E if the other end supports it too */
+- if (tbnet_e2e && net->svc->prtcstns & TBNET_E2E)
+- flags |= RING_FLAG_E2E;
+-
+- ring = tb_ring_alloc_tx(xd->tb->nhi, -1, TBNET_RING_SIZE, flags);
++ ring = tb_ring_alloc_tx(xd->tb->nhi, -1, TBNET_RING_SIZE,
++ RING_FLAG_FRAME);
+ if (!ring) {
+ netdev_err(dev, "failed to allocate Tx ring\n");
+ return -ENOMEM;
+@@ -952,6 +948,11 @@ static int tbnet_open(struct net_device *dev)
+ sof_mask = BIT(TBIP_PDF_FRAME_START);
+ eof_mask = BIT(TBIP_PDF_FRAME_END);
+
++ flags = RING_FLAG_FRAME;
++ /* Only enable full E2E if the other end supports it too */
++ if (tbnet_e2e && net->svc->prtcstns & TBNET_E2E)
++ flags |= RING_FLAG_E2E;
++
+ ring = tb_ring_alloc_rx(xd->tb->nhi, -1, TBNET_RING_SIZE, flags,
+ net->tx_ring.ring->hop, sof_mask,
+ eof_mask, tbnet_start_poll, net);
+--
+2.53.0
+
--- /dev/null
+From e4f48aeb9e232fbcc71ca314c1af41b44513274a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 11:18:40 -0400
+Subject: sctp: clear control chunk transport if it is being removed
+
+From: Xin Long <lucien.xin@gmail.com>
+
+[ Upstream commit c9158ceaf27780ef64534ad72f44ffde3f8ccc49 ]
+
+sctp_make_heartbeat_ack() caches the destination transport in
+chunk->transport without taking a reference. When src_out_of_asoc_ok is
+enabled, the HEARTBEAT ACK may remain queued on control_chunk_list instead
+of being transmitted immediately.
+
+If the peer transport is removed while the chunk is still queued,
+sctp_assoc_rm_peer() drops the transport and schedules it for RCU freeing,
+but only clears cached transport pointers in out_chunk_list. The queued
+control chunk therefore retains a dangling transport pointer.
+
+Once an ASCONF_ACK clears the suppression and the queued control chunk is
+transmitted, SCTP dereferences the stale transport pointer, leading to a
+use-after-free.
+
+Fix this by also clearing chunk->transport for queued control chunks in
+control_chunk_list when removing the transport.
+
+Fixes: 8a07eb0a50ae ("sctp: Add ASCONF operation on the single-homed host")
+Reported-by: Daniele Linguaglossa <danielelinguaglossa@gmail.com>
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/7e1168cb722132152a29d47e5eafaeac4a3bf6f3.1785943120.git.lucien.xin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/associola.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/net/sctp/associola.c b/net/sctp/associola.c
+index 44f06c5f1f256..ebdc48be47813 100644
+--- a/net/sctp/associola.c
++++ b/net/sctp/associola.c
+@@ -573,6 +573,10 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
+ if (ch->transport == peer)
+ ch->transport = NULL;
+
++ list_for_each_entry(ch, &asoc->outqueue.control_chunk_list, list)
++ if (ch->transport == peer)
++ ch->transport = NULL;
++
+ asoc->peer.transport_count--;
+
+ sctp_ulpevent_notify_peer_addr_change(peer, SCTP_ADDR_REMOVED, 0);
+--
+2.53.0
+
--- /dev/null
+From f7034fc517df12f7c7ae1c022389fce66fe6a512 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 10:55:14 +0800
+Subject: sctp: fix addip_serial increment on ASCONF_ACK allocation failure
+
+From: Qing Luo <luoqing@kylinos.cn>
+
+[ Upstream commit aa2e13ae8d3cbe2c15ef4f7e971b2de0832794aa ]
+
+In sctp_process_asconf(), when sctp_make_asconf_ack() fails to allocate
+the ASCONF_ACK chunk due to memory pressure, the code jumps to the
+done label where asoc->peer.addip_serial is unconditionally incremented.
+
+This leaves the peer's ASCONF (serial N) unacknowledged while the local
+endpoint now expects serial N+1. When the peer retransmits serial N, it
+falls into the serial < addip_serial + 1 branch ,
+which attempts to look up a cached ACK for serial N. No cached ACK
+exists since the allocation failed, so the retransmission is silently
+discarded. The peer eventually times out and ABORTs the association.
+
+Move the addip_serial increment inside the if (asconf_ack) block so that
+the serial number is only advanced when the ASCONF_ACK is successfully
+created and cached. This way, on allocation failure, the serial number
+is unchanged and the peer's retransmitted ASCONF will be correctly
+re-processed.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Qing Luo <luoqing@kylinos.cn>
+Acked-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/20260804025514.241767-1-l1138897701@163.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/sm_make_chunk.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
+index 0f03560fcab44..1a614560223ef 100644
+--- a/net/sctp/sm_make_chunk.c
++++ b/net/sctp/sm_make_chunk.c
+@@ -3354,12 +3354,11 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
+ goto done;
+ }
+ done:
+- asoc->peer.addip_serial++;
+-
+ /* If we are sending a new ASCONF_ACK hold a reference to it in assoc
+ * after freeing the reference to old asconf ack if any.
+ */
+ if (asconf_ack) {
++ asoc->peer.addip_serial++;
+ sctp_chunk_hold(asconf_ack);
+ list_add_tail(&asconf_ack->transmitted_list,
+ &asoc->asconf_ack_list);
+--
+2.53.0
+
--- /dev/null
+From 5e14cad88e4ae3e56d88f7a9edde992bafd950c8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 21:46:35 +0200
+Subject: selftests/ftrace: refactor eprobes test to fix argument checks
+
+From: Martin Kaiser <martin@kaiser.cx>
+
+[ Upstream commit 6e3abef2a27e7402a94111c9eff85d887e64a309 ]
+
+The add/remove eprobe test installs an eprobe for the openat syscall and
+runs ls. It checks the filenames that were opened by ls against a
+whitelist and a blacklist.
+
+Commit 206b25c09080 ("tracing: eprobe: read the complete FILTER_PTR_STRING
+pointer") fixed access to some string fields in eprobes. This triggers
+test failures as the blacklist does not allow relative paths for the
+openat parameters.
+
+What makes this test unstable is the fact that the openat calls vary a
+lot between different systems.
+
+Refactor the test to make it more robust. "cd <directory>" will issue a
+chdir syscall with the target directory as parameter. Set an eprobe on
+the sys_enter_chdir event and filter for the exact directory name. Allow
+(fault) as fallback.
+
+Link: https://lore.kernel.org/all/20260804194705.760893-1-martin@kaiser.cx/
+
+Fixes: 206b25c09080 ("tracing: eprobe: read the complete FILTER_PTR_STRING pointer")
+Reported-by: kernel test robot <oliver.sang@intel.com>
+Closes: https://lore.kernel.org/oe-lkp/202607151010.b68428e1-lkp@intel.com
+Signed-off-by: Martin Kaiser <martin@kaiser.cx>
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ftrace/test.d/dynevent/add_remove_eprobe.tc | 16 +++++-----------
+ 1 file changed, 5 insertions(+), 11 deletions(-)
+
+diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
+index c300eb0202620..e2322693d0c32 100644
+--- a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
++++ b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
+@@ -1,16 +1,16 @@
+ #!/bin/sh
+ # SPDX-License-Identifier: GPL-2.0
+ # description: Generic dynamic event - add/remove eprobe events
+-# requires: dynamic_events events/syscalls/sys_enter_openat "<attached-group>.<attached-event> [<args>]":README
++# requires: dynamic_events events/syscalls/sys_enter_chdir "<attached-group>.<attached-event> [<args>]":README
+
+ echo 0 > events/enable
+
+ clear_dynamic_events
+
+ SYSTEM="syscalls"
+-EVENT="sys_enter_openat"
++EVENT="sys_enter_chdir"
+ FIELD="filename"
+-EPROBE="eprobe_open"
++EPROBE="eprobe_chdir"
+ OPTIONS="file=+0(\$filename):ustring"
+ echo "e:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
+
+@@ -18,20 +18,14 @@ grep -q "$EPROBE" dynamic_events
+ test -d events/eprobes/$EPROBE
+
+ echo 1 > events/eprobes/$EPROBE/enable
+-ls
++cd /sys/kernel/tracing
+ echo 0 > events/eprobes/$EPROBE/enable
+
+-content=`grep '^ *ls-' trace | grep 'file='`
+-nocontent=`grep '^ *ls-' trace | grep 'file=' | grep -v -e '"/' -e '"."' -e '(fault)' ` || true
+-
++content=`grep -e 'file="/sys/kernel/tracing"\|(fault)' trace`
+ if [ -z "$content" ]; then
+ exit_fail
+ fi
+
+-if [ ! -z "$nocontent" ]; then
+- exit_fail
+-fi
+-
+ echo "-:$EPROBE" >> dynamic_events
+
+ ! grep -q "$EPROBE" dynamic_events
+--
+2.53.0
+
mount-honour-sb_nouser-in-the-new-mount-api.patch
selftests-bpf-fail-unbound-udp-on-sockmap-update.patch
s390-zcrypt-fix-missing-mem-scrub-at-clear-key-impor.patch
+arm64-dts-qcom-sdm850-lenovo-yoga-c630-lower-psci-cl.patch
+nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch
+arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch
+arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch
+drm-bridge-ps8640-propagate-aux-transfer-register-er.patch
+revert-net-thunderbolt-enable-end-to-end-flow-contro.patch
+bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch
+net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch
+netfilter-ipset-switch-ext_size-to-atomic64_t.patch
+ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch
+ipvs-return-the-csum-validation-for-forward-hook.patch
+btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch
+bpf-preserve-pointer-state-for-commuted-arithmetic.patch
+net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch
+net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch
+net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch
+devlink-fix-net-namespace-reference-leak-in-reload.patch
+net-mlx5-fw_tracer-return-null-on-create-error.patch
+counter-microchip-tcb-capture-fix-dt-channel-validat.patch
+bpf-tcp-make-mem-flags-configurable-through-bpf_iter.patch
+bpf-tcp-make-sure-iter-batch-always-contains-a-full-.patch
+bpf-tcp-get-rid-of-st_bucket_done.patch
+bpf-tcp-use-bpf_tcp_iter_batch_item-for-bpf_tcp_iter.patch
+bpf-tcp-avoid-socket-skips-and-repeats-during-iterat.patch
+bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch
+vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch
+tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch
+udp-fix-potential-use-after-free-in-tunnel-segmentat.patch
+net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch
+net-openvswitch-check-ethernet-header-length-in-key_.patch
+net-sched-cls_api-add-skip_sw-counter.patch
+net-sched-cls_api-add-filter-counter.patch
+net-sched-make-skip_sw-actually-skip-software.patch
+net-sched-cls_api-fix-slab-use-after-free-in-fl_dump.patch
+net-sched-refine-software-bypass-handling-in-tc_run.patch
+net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch
+hwmon-nzxt-smart2-check-return-value-of-init_device-.patch
+hwmon-lm25066-use-i2c_get_match_data.patch
+hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch
+selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch
+bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch
+bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch
+bnxt_en-fix-ptp-pps-setting-bug.patch
+sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch
+tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch
+net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch
+net-prestera-validate-firmware-header-length.patch
+net-remove-warn_on_once-from-sk_mc_loop.patch
+net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch
+net-thunderbolt-tear-down-dma-paths-before-stopping-.patch
+ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch
+net-tcp-prepare-tcp_md5sig_pool-for-tcp-ao.patch
+net-tcp-add-tcp-ao-config-and-structures.patch
+net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch
+sctp-clear-control-chunk-transport-if-it-is-being-re.patch
+tls-don-t-abort-the-connection-on-signal-interrupted.patch
+hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch
+regulator-devres-add-api-for-reference-voltage-suppl.patch
+hwmon-ads7828-fix-external-vref-regulator-handling.patch
--- /dev/null
+From 09ccb6451412337ba0de04ec60d7d161814e0e66 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jul 2026 20:08:06 -0700
+Subject: tcp: do not change rcv_ssthresh in tcp_measure_rcv_mss()
+
+From: Nathan Gao <zcgao@amazon.com>
+
+[ Upstream commit 0e125ecfe20c077625cf0be8d750d5c3abc0dce9 ]
+
+Commit f5da7c45188e ("tcp: adjust rcvq_space after updating scaling
+ratio") replaced the direct window_clamp update in tcp_measure_rcv_mss()
+with a call to tcp_set_window_clamp(), a helper that implements the
+TCP_WINDOW_CLAMP setsockopt. As a side effect, the helper also shrinks
+rcv_ssthresh via __tcp_adjust_rcv_ssthresh().
+
+As a result, each scaling_ratio decrease detected by
+tcp_measure_rcv_mss() also cuts rcv_ssthresh. Elsewhere in TCP,
+rcv_ssthresh is usually cut under memory pressure and grows via
+tcp_grow_window().
+
+Flows whose segment sizes vary keep scaling_ratio oscillating, which
+leads to an unstable rcv_ssthresh: a dip of rcv_ssthresh only recovers
+via tcp_grow_window(), keeping the advertised window at a relatively
+low level even after the ratio itself has recovered, and can even stall
+the sender.
+
+Observed on a customer's proxy gateway after upgrading from kernel 6.1
+to 6.12: in the worst case, rcv_ssthresh was cut in half by a
+scaling_ratio dip. P99 latency jumped from <10ms on 6.1 to ~100ms on
+6.12, and almost returned to the 6.1 level with this patch applied.
+
+Restore the plain WRITE_ONCE() update of window_clamp, as introduced
+in commit a2cbb1603943 ("tcp: Update window clamping condition"), and
+keep the rcvq_space.space adjustment. Now rcv_ssthresh is decoupled from
+scaling_ratio changes in tcp_measure_rcv_mss().
+
+Fixes: f5da7c45188e ("tcp: adjust rcvq_space after updating scaling ratio")
+Signed-off-by: Nathan Gao <zcgao@amazon.com>
+Link: https://patch.msgid.link/20260725030806.28135-1-zcgao@amazon.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_input.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
+index eb1bf58634741..9efb84658a82d 100644
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -252,7 +252,7 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb)
+ struct tcp_sock *tp = tcp_sk(sk);
+
+ val = tcp_win_from_space(sk, sk->sk_rcvbuf);
+- tcp_set_window_clamp(sk, val);
++ WRITE_ONCE(tp->window_clamp, val);
+
+ if (tp->window_clamp < tp->rcvq_space.space)
+ tp->rcvq_space.space = tp->window_clamp;
+--
+2.53.0
+
--- /dev/null
+From a46dc029eed5866bd2c1669fe423ce66a0f9f9a2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 14:17:38 +0800
+Subject: tcp: fix TFO max_qlen accounting across reuseport migration
+
+From: Jiayuan Chen <jiayuan.chen@linux.dev>
+
+[ Upstream commit a0ab2ba83e35159d81cec830a92e885ecf8139be ]
+
+A listener's TCP_FASTOPEN max_qlen stops being accurate and lets through
+far more pending Fast Open requests than it was configured for.
+
+This only shows up with SO_REUSEPORT listener migration, where closing a
+listener hands its still-pending TFO children over to a surviving one.
+
+fastopenq.qlen is charged in tcp_fastopen_create_child() when the child
+is created and uncharged in reqsk_fastopen_remove() when the handshake
+completes. The uncharge follows rsk_listener of the request the child
+points at, and inet_reqsk_clone() has repointed the child at a new
+request owned by the new listener, so the ++ and the -- land on two
+different sockets. The new listener's qlen drifts negative and its
+limit no longer binds.
+
+Charge the new listener during migration, like reqsk_queue_migrated()
+already does for queue->young and queue->qlen.
+
+Fixes: 54b92e841937 ("tcp: Migrate TCP_ESTABLISHED/TCP_SYN_RECV sockets in accept queues.")
+Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260803061739.134737-1-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/inet_connection_sock.c | 20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
+index c7a1f763e464e..208f8b173a056 100644
+--- a/net/ipv4/inet_connection_sock.c
++++ b/net/ipv4/inet_connection_sock.c
+@@ -930,11 +930,23 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req,
+
+ nreq->rsk_listener = sk;
+
+- /* We need not acquire fastopenq->lock
+- * because the child socket is locked in inet_csk_listen_stop().
+- */
+- if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener)
++ if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener) {
++ struct fastopen_queue *fastopenq;
++
++ /* reqsk_fastopen_remove() will uncharge nreq->rsk_listener,
++ * that is @sk, so charge it here. Unlike the listener
++ * being closed, @sk is live and needs its lock.
++ */
++ fastopenq = &inet_csk(sk)->icsk_accept_queue.fastopenq;
++ spin_lock_bh(&fastopenq->lock);
++ fastopenq->qlen++;
++ spin_unlock_bh(&fastopenq->lock);
++
++ /* We need not acquire fastopenq->lock
++ * because the child socket is locked in inet_csk_listen_stop().
++ */
+ rcu_assign_pointer(tcp_sk(nreq->sk)->fastopen_rsk, nreq);
++ }
+
+ return nreq;
+ }
+--
+2.53.0
+
--- /dev/null
+From c5720e98f7248ca4fb676480759005646192cab9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 08:22:48 +0200
+Subject: tls: don't abort the connection on signal-interrupted sends
+
+From: Maximilian Immanuel Brandtner <maxbr@linux.ibm.com>
+
+[ Upstream commit af0e5cdd031f4f4a8f6d4160bfbda4f36872b0ed ]
+
+When a signal interrupts a blocking send, tls_tx_records() treats the
+resulting -ERESTARTSYS as a transmission failure and marks the socket
+errored via tls_err_abort() with the raw error code. Later syscalls
+return the kernel-internal errno 512 (ERESTARTSYS) to userspace, as the
+signal it stems from is no longer pending during syscall exit and thus
+never translated.
+
+An interrupted send is not a connection error: the partially sent record
+stays queued and is resent later. Interrupt error codes are therefore
+excluded from the abort in the same way as -EAGAIN.
+
+Fixes: b341ca51d267 ("tls: Fix tls_sw_sendmsg error handling")
+Signed-off-by: Maximilian Immanuel Brandtner <maxbr@linux.ibm.com>
+Link: https://patch.msgid.link/20260805063109.1772314-1-maxbr@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tls/tls_sw.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
+index 39021fab3c596..719cc70b26505 100644
+--- a/net/tls/tls_sw.c
++++ b/net/tls/tls_sw.c
+@@ -458,7 +458,7 @@ int tls_tx_records(struct sock *sk, int flags)
+ }
+
+ tx_err:
+- if (rc < 0 && rc != -EAGAIN)
++ if (rc < 0 && rc != -EAGAIN && rc != -EINTR && rc != -ERESTARTSYS)
+ tls_err_abort(sk, rc);
+
+ return rc;
+--
+2.53.0
+
--- /dev/null
+From 4de2cb64ae2f6d0e9c78683919829dc9c96d0e79 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 17:35:54 +0800
+Subject: udp: fix potential use-after-free in tunnel segmentation
+
+From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+
+[ Upstream commit d0f86fb36eb260abd10007b62c9dcc1028e03e61 ]
+
+__skb_udp_tunnel_segment() gets the UDP header before ensuring the
+tunnel header is in the skb head. If the pull reallocates skb->head,
+the saved UDP header pointer is no longer valid.
+
+Get the UDP header after the pull to avoid a potential use-after-free.
+
+Fixes: dbef491ebe7f ("udp: Use uh->len instead of skb->len to compute checksum in segmentation")
+Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+Reviewed-by: Antoine Tenart <atenart@kernel.org>
+Link: https://patch.msgid.link/20260730093554.68127-1-xuanqiang.luo@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/udp_offload.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
+index 84ae2759ff195..b9b21e5af1a7f 100644
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -22,17 +22,19 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
+ int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
+ bool remcsum, need_csum, offload_csum, gso_partial;
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+- struct udphdr *uh = udp_hdr(skb);
+ u16 mac_offset = skb->mac_header;
+ __be16 protocol = skb->protocol;
+ u16 mac_len = skb->mac_len;
+ int udp_offset, outer_hlen;
++ struct udphdr *uh;
+ __wsum partial;
+ bool need_ipsec;
+
+ if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
+ goto out;
+
++ uh = udp_hdr(skb);
++
+ /* Adjust partial header checksum to negate old length.
+ * We cannot rely on the value contained in uh->len as it is
+ * possible that the actual value exceeds the boundaries of the
+--
+2.53.0
+
--- /dev/null
+From 9dbd818c63fb2834e3ad06811735b6e8e388cb79 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Jun 2026 15:02:02 -0700
+Subject: vhost/vdpa: reject overflowing PA map page counts on 32-bit
+
+From: Yousef Alhouseen <alhouseenyousef@gmail.com>
+
+[ Upstream commit 0619aaa34c0c2a2dcb07f0e9c8a34e7efb8c4cdf ]
+
+vhost_vdpa_pa_map() adds the IOVA page offset to the user-controlled map
+size before computing the number of pages to pin. On 32-bit systems,
+where unsigned long is narrower than u64, that addition can overflow and
+the code can pin and map fewer pages than the requested IOTLB range.
+
+Reject sizes that overflow the unsigned long page-count calculation.
+
+Fixes: 22af48cf91aa ("vdpa: factor out vhost_vdpa_pa_map() and vhost_vdpa_pa_unmap()")
+Acked-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Message-ID: <CAMuQ4bX-iDvcUOPPY+NLz95tkRJYwWqvzAr=U48uNaub_HZLGw@mail.gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vhost/vdpa.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
+index 3645d83f240d9..5e2f7f4477679 100644
+--- a/drivers/vhost/vdpa.c
++++ b/drivers/vhost/vdpa.c
+@@ -998,6 +998,7 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
+ unsigned int gup_flags = FOLL_LONGTERM;
+ unsigned long npages, cur_base, map_pfn, last_pfn = 0;
+ unsigned long lock_limit, sz2pin, nchunks, i;
++ unsigned long page_offset;
+ u64 start = iova;
+ long pinned;
+ int ret = 0;
+@@ -1010,7 +1011,13 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
+ if (perm & VHOST_ACCESS_WO)
+ gup_flags |= FOLL_WRITE;
+
+- npages = PFN_UP(size + (iova & ~PAGE_MASK));
++ page_offset = iova & ~PAGE_MASK;
++ if (size > ULONG_MAX - page_offset) {
++ ret = -EINVAL;
++ goto free;
++ }
++
++ npages = PFN_UP(size + page_offset);
+ if (!npages) {
+ ret = -EINVAL;
+ goto free;
+--
+2.53.0
+
--- /dev/null
+From a90890f9986886308a5036e1bef64b29306dc3a3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 11:59:55 -0700
+Subject: accel/amdxdna: Fix locally exploitable BUG_ON in
+ amdxdna_insert_pages()
+
+From: Lizhi Hou <lizhi.hou@amd.com>
+
+[ Upstream commit 4a19f7ab5972ef608b31ae921419bc3e04b3f8ad ]
+
+In amdxdna_insert_pages(), vm_flags_mod() sets VM_MIXEDMAP and clears
+VM_PFNMAP. If an unprivileged userspace process mmaps a non-imported GEM
+object and then calls madvise(MADV_DONTNEED), the PTEs will be
+successfully cleared because VM_MIXEDMAP allows this (unlike VM_PFNMAP).
+
+When userspace subsequently accesses the memory, drm_gem_shmem_fault()
+handles the page fault and attempts to map the backing shmem page via
+vmf_insert_pfn() which calls vmf_insert_pfn_prot(). Because the backing
+shmem page is normal system memory (pfn_valid(pfn) is true) and the VMA
+now has VM_MIXEDMAP set, won't this predictably trigger the explicit
+assertion BUG_ON((vma->vm_flags & VM_MIXEDMAP) && pfn_valid(pfn))
+
+Fix by removing the vm_flags_mod() call and replacing the vm_insert_pages()
+pre-population with the handle_mm_fault() loop that was already used for
+the import (dma-buf) path.
+
+Fixes: e486147c912f ("accel/amdxdna: Add BO import and export")
+Reviewed-by: Max Zhen <max.zhen@amd.com>
+Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
+Link: https://patch.msgid.link/20260731185955.3449311-1-lizhi.hou@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/accel/amdxdna/amdxdna_gem.c | 27 ++++++++-------------------
+ 1 file changed, 8 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/accel/amdxdna/amdxdna_gem.c b/drivers/accel/amdxdna/amdxdna_gem.c
+index 41fb39d095749..fff1c707d040a 100644
+--- a/drivers/accel/amdxdna/amdxdna_gem.c
++++ b/drivers/accel/amdxdna/amdxdna_gem.c
+@@ -402,25 +402,17 @@ static int amdxdna_insert_pages(struct amdxdna_gem_obj *abo,
+ XDNA_ERR(xdna, "Failed shmem mmap %d", ret);
+ return ret;
+ }
+-
+- /* The buffer is based on memory pages. Fix the flag. */
+- vm_flags_mod(vma, VM_MIXEDMAP, VM_PFNMAP);
+- ret = vm_insert_pages(vma, vma->vm_start, abo->base.pages,
+- &num_pages);
++ } else {
++ vma->vm_private_data = NULL;
++ vma->vm_ops = NULL;
++ ret = dma_buf_mmap(abo->dma_buf, vma, 0);
+ if (ret) {
+- XDNA_ERR(xdna, "Failed insert pages %d", ret);
+- amdxdna_mark_mapp_invalid(abo, vma);
++ XDNA_ERR(xdna, "Failed to mmap dma buf %d", ret);
++ return ret;
+ }
+
+- return 0;
+- }
+-
+- vma->vm_private_data = NULL;
+- vma->vm_ops = NULL;
+- ret = dma_buf_mmap(abo->dma_buf, vma, 0);
+- if (ret) {
+- XDNA_ERR(xdna, "Failed to mmap dma buf %d", ret);
+- return ret;
++ /* Drop the reference drm_gem_mmap_obj() acquired.*/
++ drm_gem_object_put(to_gobj(abo));
+ }
+
+ do {
+@@ -437,9 +429,6 @@ static int amdxdna_insert_pages(struct amdxdna_gem_obj *abo,
+ offset += PAGE_SIZE;
+ } while (--num_pages);
+
+- /* Drop the reference drm_gem_mmap_obj() acquired.*/
+- drm_gem_object_put(to_gobj(abo));
+-
+ return 0;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 06d3584193b29dd8e735c47bea538cc00b1b235b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jul 2026 00:42:56 -0700
+Subject: accel/amxdna: Fix page-insertion errors in amdxdna_insert_pages()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Lizhi Hou <lizhi.hou@amd.com>
+
+[ Upstream commit 8d51e0fd3e698919d2adeff71936377f0c0d4aa0 ]
+
+Two error paths in amdxdna_insert_pages() called vma->vm_ops->close(vma)
+before returning an error code to the caller. This is incorrect:
+amdxdna_gem_obj_mmap() registers an HMM interval notifier before calling
+amdxdna_insert_pages(), and on a hard error it jumps to hmm_unreg to undo
+that registration. Calling vm_ops->close() manually — which drops the
+shmem pages_pin_count and the GEM object reference that backs the VMA —
+before the mmap syscall has even returned causes those resources to be
+released while the VMA is still alive. The kernel VMA teardown will call
+vm_ops->close() a second time when the process later unmaps the range,
+producing a reference count underflow.
+
+Replace both hard-error returns with a deferred-fault approach that keeps
+the VMA alive and retries page insertion through the HMM range-fault path.
+
+Fixes: e486147c912f ("accel/amdxdna: Add BO import and export")
+Reviewed-by: Max Zhen <max.zhen@amd.com>
+Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
+Link: https://patch.msgid.link/20260723074256.2435143-1-lizhi.hou@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/accel/amdxdna/amdxdna_gem.c | 24 ++++++++++++++++++++----
+ 1 file changed, 20 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/accel/amdxdna/amdxdna_gem.c b/drivers/accel/amdxdna/amdxdna_gem.c
+index cdf113dadc4db..41fb39d095749 100644
+--- a/drivers/accel/amdxdna/amdxdna_gem.c
++++ b/drivers/accel/amdxdna/amdxdna_gem.c
+@@ -371,6 +371,23 @@ static void amdxdna_gem_dev_obj_free(struct drm_gem_object *gobj)
+ amdxdna_gem_destroy_obj(abo);
+ }
+
++static void amdxdna_mark_mapp_invalid(struct amdxdna_gem_obj *abo,
++ struct vm_area_struct *vma)
++{
++ struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev);
++ struct amdxdna_umap *mapp;
++
++ down_write(&xdna->notifier_lock);
++ abo->mem.map_invalid = true;
++ list_for_each_entry(mapp, &abo->mem.umap_list, node) {
++ if (compare_range(mapp, vma->vm_mm, vma->vm_start, vma->vm_end)) {
++ mapp->invalid = true;
++ break;
++ }
++ }
++ up_write(&xdna->notifier_lock);
++}
++
+ static int amdxdna_insert_pages(struct amdxdna_gem_obj *abo,
+ struct vm_area_struct *vma)
+ {
+@@ -392,8 +409,7 @@ static int amdxdna_insert_pages(struct amdxdna_gem_obj *abo,
+ &num_pages);
+ if (ret) {
+ XDNA_ERR(xdna, "Failed insert pages %d", ret);
+- vma->vm_ops->close(vma);
+- return ret;
++ amdxdna_mark_mapp_invalid(abo, vma);
+ }
+
+ return 0;
+@@ -413,9 +429,9 @@ static int amdxdna_insert_pages(struct amdxdna_gem_obj *abo,
+ fault_ret = handle_mm_fault(vma, vma->vm_start + offset,
+ FAULT_FLAG_WRITE, NULL);
+ if (fault_ret & VM_FAULT_ERROR) {
+- vma->vm_ops->close(vma);
+ XDNA_ERR(xdna, "Fault in page failed");
+- return -EFAULT;
++ amdxdna_mark_mapp_invalid(abo, vma);
++ break;
+ }
+
+ offset += PAGE_SIZE;
+--
+2.53.0
+
--- /dev/null
+From 62d4903edd07f2261af2eabf583bf45ffee38393 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 21:45:05 +0800
+Subject: ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN for Logitech PRO
+ X 2 LIGHTSPEED
+
+From: Rong Zhang <i@rong.moe>
+
+[ Upstream commit c973e61895db8fe4a69d8b33de92068d135cafd8 ]
+
+The UAC mixer of the Logitech PRO X 2 LIGHTSPEED has broken mixer
+GET_CUR behavior but otherwise works fine.
+
+Add a quirk table entry matching VID/PID=0x046d/0x0af7 and apply the
+MIXER_GET_CUR_BROKEN quirk flag to make the mixer usable again.
+
+Quirky device sample (after applying the quirk flag):
+
+ usb 3-2.1: New USB device found, idVendor=046d, idProduct=0af7, bcdDevice= 1.00
+ usb 3-2.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
+ usb 3-2.1: Product: PRO X 2 LIGHTSPEED
+ usb 3-2.1: Manufacturer: Logitech
+ usb 3-2.1: SerialNumber: 0000000000000000
+ usb 3-2.1: 2:0: broken mixer GET_CUR (-18944/0/256 => -2662)
+ usb 3-2.1: 6:0: broken mixer GET_CUR (-18944/0/256 => 0)
+
+Fixes: 86aa1ea1f15c ("ALSA: usb-audio: Do not expose sticky mixers")
+Suggested-by: Brian van den Berg <faxuser@proton.me>
+Reported-by: Brian van den Berg <faxuser@proton.me>
+Link: https://lore.kernel.org/all/370007e6-b73b-4bfc-8410-a860781c7ad7@proton.me/
+Signed-off-by: Rong Zhang <i@rong.moe>
+Link: https://patch.msgid.link/20260731-uac-lg-pro-x-2-ls-v1-1-268eaefe66ab@rong.moe
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/quirks.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
+index 688993bfa8fd1..e97038cf5271e 100644
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -2249,6 +2249,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
+ DEVICE_FLG(0x046d, 0x0a8f, /* Logitech H390 headset */
+ QUIRK_FLAG_CTL_MSG_DELAY_1M |
+ QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE),
++ DEVICE_FLG(0x046d, 0x0af7, /* Logitech PRO X 2 LIGHTSPEED */
++ QUIRK_FLAG_MIXER_GET_CUR_BROKEN),
+ DEVICE_FLG(0x0499, 0x1506, /* Yamaha THR5 */
+ QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+ DEVICE_FLG(0x0499, 0x1509, /* Steinberg UR22 */
+--
+2.53.0
+
--- /dev/null
+From 31e783ee84c8e2a10849ab2e654f916f65a51df2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 May 2026 23:45:20 +0800
+Subject: ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN
+
+From: Rong Zhang <i@rong.moe>
+
+[ Upstream commit ad2c7d2c42af943a3e711bdc1e4fd55b76fcbe55 ]
+
+Since commit 86aa1ea1f15c ("ALSA: usb-audio: Do not expose sticky
+mixers"), the UAC mixer core utilizes volume SET_CUR and GET_CUR to
+identify devices with sticky mixers. Unfortunately, even though most
+devices with sticky GET_CUR also have corresponding sticky SET_CUR,
+which I actually met more since the commit had been merged, there is
+also a rare case that some devices may have volume mixers that responds
+to SET_CUR properly but with its GET_CUR stubbed. This cause the sticky
+check to consider the mixer to be sticky and unnecessarily disable it.
+
+As the sticky check can't distinguish between sticky mixers and working
+SET_CUR but broken GET_CUR, add QUIRK_FLAG_MIXER_GET_CUR_BROKEN to tell
+that the device should fall into the second category when GET_CUR
+returns a constant value. In this case, the sticky check becomes
+non-fatal and only disables GET_CUR instead of the whole mixer. The
+current volume will then be provided by the internal cache that stores
+the last set volume.
+
+An info message prompting users to check MIXER_GET_CUR_BROKEN for
+potential sticky mixers is also added, so that users can learn how to do
+some experiments to determine what's going on. If the mixer surprisingly
+turns out to be non-sticky, they can submit a patch for a new quirk
+table entry.
+
+Signed-off-by: Rong Zhang <i@rong.moe>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Link: https://patch.msgid.link/20260531-uac-quirk-get-cur-vol-v4-1-ede643dca151@rong.moe
+Stable-dep-of: c973e61895db ("ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN for Logitech PRO X 2 LIGHTSPEED")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/sound/alsa-configuration.rst | 12 +++++
+ sound/usb/mixer.c | 60 ++++++++++++++++++----
+ sound/usb/mixer.h | 1 +
+ sound/usb/quirks.c | 1 +
+ sound/usb/usbaudio.h | 13 +++++
+ 5 files changed, 77 insertions(+), 10 deletions(-)
+
+diff --git a/Documentation/sound/alsa-configuration.rst b/Documentation/sound/alsa-configuration.rst
+index 4b30cd63c5a5a..78fb484e8b04f 100644
+--- a/Documentation/sound/alsa-configuration.rst
++++ b/Documentation/sound/alsa-configuration.rst
+@@ -2389,6 +2389,18 @@ quirk_flags
+ from snd_usb_handle_sync_urb. Instead fall through and enqueue a
+ packet_info containing only size-0 packets, so the OUT ring keeps
+ moving (emits silence). Needed by Behringer Flow 8 (1397:050c).
++ * bit 30: ``mixer_get_cur_broken``
++ Some mixers are sticky, which means that setting their current volume
++ is a no-op, and reading the current volume returns a constant value.
++ The sticky check disables these mixers to prevent confusing userspace.
++ However, some devices do have a tunable volume despite the reported
++ current volume being constant. As the sticky check can't distinguish
++ between the two categories, setting this flag tells that the device
++ should fall into the second category when GET_CUR returns a constant
++ value, resulting in the sticky check being non-fatal and only
++ disabling GET_CUR instead of the whole mixer. The current volume will
++ then be provided by the internal cache that stores the last set
++ volume
+
+ This module supports multiple devices, autoprobe and hotplugging.
+
+diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
+index dbcefcaf7c361..142f5ca7a72d2 100644
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -434,6 +434,11 @@ int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval,
+ *value = cval->cache_val[index];
+ return 0;
+ }
++
++ /* The current value is always provided by the cache after initialization. */
++ if (cval->get_cur_broken)
++ return -ENXIO;
++
+ err = get_cur_mix_raw(cval, channel, value);
+ if (err < 0) {
+ if (!cval->head.mixer->ignore_ctl_error)
+@@ -1234,7 +1239,7 @@ static void init_cur_mix_raw(struct usb_mixer_elem_info *cval, int ch, int idx)
+ err = snd_usb_get_cur_mix_value(cval, ch, idx, &val);
+ if (!err)
+ return;
+- if (!cval->head.mixer->ignore_ctl_error)
++ if (!cval->head.mixer->ignore_ctl_error && !cval->get_cur_broken)
+ usb_audio_warn(cval->head.mixer->chip,
+ "%d:%d: failed to get current value for ch %d (%d)\n",
+ cval->head.id, mixer_ctrl_intf(cval->head.mixer),
+@@ -1248,8 +1253,16 @@ static void init_cur_mix_raw(struct usb_mixer_elem_info *cval, int ch, int idx)
+ * Some devices' volume control mixers are sticky, which accept SET_CUR but
+ * do absolutely nothing.
+ *
+- * Prevent sticky mixers from being registered, otherwise they confuses
+- * userspace and results in ineffective volume control.
++ * Check the return values of GET_CUR with different SET_CUR values. Consider
++ * the mixer as sticky if GET_CUR always returns a constant value.
++ *
++ * Some devices have effective SET_CUR despite GET_CUR being constant. Do not
++ * consider the mixer as sticky if a quirk flag indicates that.
++ *
++ * Gate the registration of sticky mixers to prevent confusing userspace, so
++ * that they won't cause ineffective volume control. However, for mixers with
++ * effective SET_CUR but broken GET_CUR, the registration can continue normally
++ * but further GET_CUR requests will be gated.
+ */
+ static int check_sticky_volume_control(struct usb_mixer_elem_info *cval,
+ int channel, int saved)
+@@ -1269,10 +1282,22 @@ static int check_sticky_volume_control(struct usb_mixer_elem_info *cval,
+ return 0;
+ }
+
++ if (cval->head.mixer->chip->quirk_flags & QUIRK_FLAG_MIXER_GET_CUR_BROKEN) {
++ usb_audio_info(cval->head.mixer->chip,
++ "%d:%d: broken mixer GET_CUR (%d/%d/%d => %d)\n",
++ cval->head.id, mixer_ctrl_intf(cval->head.mixer),
++ cval->min, cval->max, cval->res, saved);
++
++ cval->get_cur_broken = 1;
++ return -ENXIO;
++ }
++
+ usb_audio_err(cval->head.mixer->chip,
+ "%d:%d: sticky mixer values (%d/%d/%d => %d), disabling\n",
+ cval->head.id, mixer_ctrl_intf(cval->head.mixer),
+ cval->min, cval->max, cval->res, saved);
++ usb_audio_info(cval->head.mixer->chip,
++ "check MIXER_GET_CUR_BROKEN if you believe the mixer is non-sticky");
+
+ return -ENODEV;
+ }
+@@ -1315,7 +1340,7 @@ static void check_volume_control_res(struct usb_mixer_elem_info *cval,
+ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
+ int default_min, struct snd_kcontrol *kctl)
+ {
+- int i, idx, ret;
++ int i, idx, ret = 0;
+
+ /* for failsafe */
+ cval->min = default_min;
+@@ -1371,8 +1396,10 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
+ goto no_checks;
+
+ ret = check_sticky_volume_control(cval, minchn, saved);
+- if (ret < 0)
++ if (ret == -ENODEV)
+ goto sticky;
++ if (ret)
++ goto no_checks;
+
+ if (cval->min + cval->res < cval->max)
+ check_volume_control_res(cval, minchn, saved);
+@@ -1381,6 +1408,16 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
+ }
+
+ no_checks:
++ /*
++ * Got a non-fatal failure during sanity checks.
++ *
++ * Do not propagate mixer values written by sanity checks.
++ * Instead, rely on init_cur_mix_raw() to initialize the mixer
++ * properly.
++ */
++ if (ret)
++ cval->cached = 0;
++
+ cval->initialized = 1;
+ }
+
+@@ -3538,7 +3575,8 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid)
+ continue;
+ info = mixer_elem_list_to_info(list);
+ /* invalidate cache, so the value is read from the device */
+- info->cached = 0;
++ if (!info->get_cur_broken)
++ info->cached = 0;
+ snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &list->kctl->id);
+ }
+@@ -3635,10 +3673,12 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
+ switch (attribute) {
+ case UAC2_CS_CUR:
+ /* invalidate cache, so the value is read from the device */
+- if (channel)
+- info->cached &= ~BIT(channel);
+- else /* master channel */
+- info->cached = 0;
++ if (!info->get_cur_broken) {
++ if (channel)
++ info->cached &= ~BIT(channel);
++ else /* master channel */
++ info->cached = 0;
++ }
+
+ snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &info->head.kctl->id);
+diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
+index afbb3dd9f177b..3fa1bd96f8588 100644
+--- a/sound/usb/mixer.h
++++ b/sound/usb/mixer.h
+@@ -94,6 +94,7 @@ struct usb_mixer_elem_info {
+ int cache_val[MAX_CHANNELS];
+ u8 initialized;
+ u8 min_mute;
++ u8 get_cur_broken;
+ void *private_data;
+ };
+
+diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
+index 33eb8be48af87..688993bfa8fd1 100644
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -2611,6 +2611,7 @@ static const char *const snd_usb_audio_quirk_flag_names[] = {
+ QUIRK_STRING_ENTRY(MIXER_PLAYBACK_LINEAR_VOL),
+ QUIRK_STRING_ENTRY(MIXER_CAPTURE_LINEAR_VOL),
+ QUIRK_STRING_ENTRY(IFB_SILENCE_ON_EMPTY),
++ QUIRK_STRING_ENTRY(MIXER_GET_CUR_BROKEN),
+ NULL
+ };
+
+diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
+index 9afcad8f143a0..e472aef6eb879 100644
+--- a/sound/usb/usbaudio.h
++++ b/sound/usb/usbaudio.h
+@@ -242,6 +242,17 @@ extern bool snd_usb_skip_validation;
+ * from snd_usb_handle_sync_urb. Instead fall through and enqueue a
+ * packet_info containing only size-0 packets, so the OUT ring keeps
+ * moving (emits silence). Needed by Behringer Flow 8 (1397:050c).
++ * QUIRK_FLAG_MIXER_GET_CUR_BROKEN
++ * Some mixers are sticky, which means that setting their current volume is a
++ * no-op, and reading the current volume returns a constant value. The sticky
++ * check disables these mixers to prevent confusing userspace. However, some
++ * devices do have a tunable volume despite the reported current volume being
++ * constant. As the sticky check can't distinguish between the two categories,
++ * setting this flag tells that the device should fall into the second
++ * category when GET_CUR returns a constant value, resulting in the sticky
++ * check being non-fatal and only disabling GET_CUR instead of the whole mixer.
++ * The current volume will then be provided by the internal cache that stores
++ * the last set volume
+ */
+
+ enum {
+@@ -275,6 +286,7 @@ enum {
+ QUIRK_TYPE_MIXER_PLAYBACK_LINEAR_VOL = 27,
+ QUIRK_TYPE_MIXER_CAPTURE_LINEAR_VOL = 28,
+ QUIRK_TYPE_IFB_SILENCE_ON_EMPTY = 29,
++ QUIRK_TYPE_MIXER_GET_CUR_BROKEN = 30,
+ /* Please also edit snd_usb_audio_quirk_flag_names */
+ };
+
+@@ -310,5 +322,6 @@ enum {
+ #define QUIRK_FLAG_MIXER_PLAYBACK_LINEAR_VOL QUIRK_FLAG(MIXER_PLAYBACK_LINEAR_VOL)
+ #define QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL QUIRK_FLAG(MIXER_CAPTURE_LINEAR_VOL)
+ #define QUIRK_FLAG_IFB_SILENCE_ON_EMPTY QUIRK_FLAG(IFB_SILENCE_ON_EMPTY)
++#define QUIRK_FLAG_MIXER_GET_CUR_BROKEN QUIRK_FLAG(MIXER_GET_CUR_BROKEN)
+
+ #endif /* __USBAUDIO_H */
+--
+2.53.0
+
--- /dev/null
+From 6e863757289511922135720250dc384814df8d46 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Aug 2026 10:34:16 +0200
+Subject: ALSA: usb-audio: Fix sticky mixer regressions on M-Audio Fast Track
+ Ultra
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit a8934c2c6dfd72901cf3cc0de28e85eb902a61a4 ]
+
+The recent fix for sticky mixer volumes caused regressions of M-audio
+Fast Track Ultra device, where the mixer state is kept to the default
+value.
+
+Add the quirk entries to tolerate the broken mixer behavior. As the
+device is known to work in the implicit feedback mode, explicitly
+enable the implicit feedback mode, too.
+
+Since there are two FTU models that are almost identical, both entries
+are added in this patch (0763:2080 and 0763:2081).
+
+Fixes: 86aa1ea1f15c ("ALSA: usb-audio: Do not expose sticky mixers")
+Link: https://bugzilla.suse.com/show_bug.cgi?id=1273166
+Link: https://patch.msgid.link/20260807083418.1712585-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/quirks.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
+index e97038cf5271e..354866a806056 100644
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -2320,6 +2320,10 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
+ QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+ DEVICE_FLG(0x0763, 0x2031, /* M-Audio Fast Track C600 */
+ QUIRK_FLAG_GENERIC_IMPLICIT_FB),
++ DEVICE_FLG(0x0763, 0x2080, /* M-Audio Fast Track Ultra */
++ QUIRK_FLAG_MIXER_GET_CUR_BROKEN | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
++ DEVICE_FLG(0x0763, 0x2081, /* M-Audio Fast Track Ultra */
++ QUIRK_FLAG_MIXER_GET_CUR_BROKEN | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+ DEVICE_FLG(0x07fd, 0x000b, /* MOTU M Series 2nd hardware revision */
+ QUIRK_FLAG_CTL_MSG_DELAY_1M),
+ DEVICE_FLG(0x08bb, 0x2702, /* LineX FM Transmitter */
+--
+2.53.0
+
--- /dev/null
+From b92154d6ef4536bac11fecaecbff73f2cf068ed6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 25 Jul 2026 14:57:22 -0700
+Subject: ARM: dts: BCM5301X: fix PCIe controller 2 second interrupt
+
+From: Rosen Penev <rosenp@gmail.com>
+
+[ Upstream commit bab4d538f8485e0d48538fcb82b285df3779278e ]
+
+PCIe controller 2 has interrupts 0-4 mapping to GIC SPI 138-142. The
+mapping for interrupt 1 was incorrectly set to 138 due to a copy-paste
+error. Fix it to 139.
+
+Assisted-by: opencode:big-pickle
+Signed-off-by: Rosen Penev <rosenp@gmail.com>
+Link: https://lore.kernel.org/r/20260725215722.9323-1-rosenp@gmail.com
+Fixes: 3b3e35b279be ("ARM: dts: BCM5301X: Relicense AXI interrupts code to the GPL 2.0+ / MIT")
+Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/boot/dts/broadcom/bcm-ns.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/broadcom/bcm-ns.dtsi b/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
+index 392a257136696..bd52de0faa3ea 100644
+--- a/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
+@@ -141,7 +141,7 @@ axi@18000000 {
+
+ /* PCIe Controller 2 */
+ <0x00014000 0 &gic GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
+- <0x00014000 1 &gic GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00014000 1 &gic GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 2 &gic GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 3 &gic GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 4 &gic GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+--
+2.53.0
+
--- /dev/null
+From 4283322924643de464c569c760a81eabcbf02d6d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 24 May 2026 23:38:46 -0400
+Subject: ARM: npcm: Fix OF node refcount leaks in SMP setup
+
+From: Yuho Choi <dbgh9129@gmail.com>
+
+[ Upstream commit 8eb052f48331474c2789d07b7f11165c323bd2f9 ]
+
+npcm7xx_smp_boot_secondary() and npcm7xx_smp_prepare_cpus() look up
+the GCR and SCU nodes with of_find_compatible_node(). The returned
+nodes are used for of_iomap(), but the node references are never
+released.
+
+of_iomap() does not consume the device node reference, and iounmap()
+only releases the MMIO mapping. Drop each node reference after the
+corresponding mapping attempt.
+
+Fixes: 7bffa14c9aed ("arm: npcm: add basic support for Nuvoton BMCs")
+Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
+Reviewed-by: Avi Fishman <avifishman70@gmail.com>
+Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/mach-npcm/platsmp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arm/mach-npcm/platsmp.c b/arch/arm/mach-npcm/platsmp.c
+index 41891d3aa1247..4c1fc9983746c 100644
+--- a/arch/arm/mach-npcm/platsmp.c
++++ b/arch/arm/mach-npcm/platsmp.c
+@@ -32,6 +32,7 @@ static int npcm7xx_smp_boot_secondary(unsigned int cpu,
+ goto out;
+ }
+ gcr_base = of_iomap(gcr_np, 0);
++ of_node_put(gcr_np);
+ if (!gcr_base) {
+ pr_err("could not iomap gcr");
+ ret = -ENOMEM;
+@@ -60,6 +61,7 @@ static void __init npcm7xx_smp_prepare_cpus(unsigned int max_cpus)
+ return;
+ }
+ scu_base = of_iomap(scu_np, 0);
++ of_node_put(scu_np);
+ if (!scu_base) {
+ pr_err("could not iomap scu");
+ return;
+--
+2.53.0
+
--- /dev/null
+From f0284b7aa6a3f1c0df86649cb21fce578350e432 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 21:45:27 +0100
+Subject: arm64: dts: broadcom: bcm2712: Remove non-functional EL2 virtual
+ timer
+
+From: Daniel Drake <dan@reactivated.net>
+
+[ Upstream commit 75952cfc7752c52a2b692b59d34ce160d3edabb2 ]
+
+Commit d87773de9efe1 ("clocksource/drivers/arm_arch_timer: Default to EL2
+virtual timer when running VHE") causes boot to hang on Raspberry Pi 5.
+The newly-selected EL2 virtual timer does not generate any interrupts,
+even though the GIC_DIST_ENABLE_SET flag has been confirmed set via
+readback.
+
+It is highly unusual that this timer interrupt is non-operational because
+this is a standard GIC interrupt corresponding to a standard Cortex-A76
+CPU timer. However, Broadcom have confirmed for this SoC:
+
+> the interrupt line was never connected in the first place as this was
+> not identified as being a requirement
+
+Remove the corresponding DeviceTree entry.
+
+Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Closes: https://lore.kernel.org/all/ea15cce1-b393-43f6-8d58-3d6f90f0c0cd@samsung.com/
+Fixes: faa3381267d0 ("arm64: dts: broadcom: Add minimal support for Raspberry Pi 5")
+Signed-off-by: Daniel Drake <dan@reactivated.net>
+Link: https://lore.kernel.org/r/20260716-bcm2712-el2-v2-1-e708f7fb42fa@reactivated.net
+Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+index 761c59d90ffc9..09ff5e9959d3a 100644
+--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+@@ -678,8 +678,6 @@ IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
+ IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_LOW)>,
+- <GIC_PPI 12 (GIC_CPU_MASK_SIMPLE(4) |
+ IRQ_TYPE_LEVEL_LOW)>;
+ };
+
+--
+2.53.0
+
--- /dev/null
+From c0b042d5b01bd95be979b30180d42672779e9887 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 11 Jun 2026 19:00:44 +0000
+Subject: arm64: dts: qcom: glymur: fix PCIe SMMU interrupts
+
+From: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
+
+[ Upstream commit 52c7084c8fe57c259e50ff0a7d4f99ccecfc4c7a ]
+
+The PCIe SMMUv3 wired interrupts are routed to GIC extended SPI INTIDs
+4100, 4098 and 4096. Describe them as ESPIs with the ESPI-relative
+interrupt numbers instead of regular SPIs 964, 962 and 960.
+
+Assisted-by: Codex:GPT-5.5
+Fixes: 41b6e8db400c ("arm64: dts: qcom: Introduce Glymur base dtsi")
+Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Link: https://lore.kernel.org/r/20260611-glymur-pcie-smmu-espi-v1-1-5effbaa3e1af@oss.qualcomm.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/glymur.dtsi | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi
+index 63df60b7e010e..468614d101c02 100644
+--- a/arch/arm64/boot/dts/qcom/glymur.dtsi
++++ b/arch/arm64/boot/dts/qcom/glymur.dtsi
+@@ -5626,9 +5626,9 @@ apps_smmu: iommu@15000000 {
+ pcie_smmu: iommu@15480000 {
+ compatible = "arm,smmu-v3";
+ reg = <0x0 0x15480000 0x0 0x20000>;
+- interrupts = <GIC_SPI 964 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 962 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 960 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_ESPI 4 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_ESPI 2 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_ESPI 0 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "eventq", "cmdq-sync", "gerror";
+ dma-coherent;
+ #iommu-cells = <1>;
+--
+2.53.0
+
--- /dev/null
+From 6a1e0e19ec5d51e27399651d1d965c8d070132c1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 11 Jun 2026 17:22:37 +0000
+Subject: arm64: dts: qcom: glymur: fix QUP serial engine IRQs
+
+From: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
+
+[ Upstream commit a74a98f956ef8e075f28d58507bc5dad7f937fb4 ]
+
+The Geni serial-engine interrupts from QUP wrapper 0 all fall in ESPI
+INTIDs space. While some of the i2c instances has gotten their
+interrupt specifiers corrected, even the other functions on the same
+serial-engines are wrong.
+
+Ensure that all the serial engine interrupts for QUP wrapper 0 matches
+the datasheet.
+
+Assisted-by: Codex:GPT-5.5
+Fixes: 41b6e8db400c ("arm64: dts: qcom: Introduce Glymur base dtsi")
+Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Link: https://lore.kernel.org/r/20260611-glymur-geni-irqs-v1-1-269428faeb6d@oss.qualcomm.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/glymur.dtsi | 26 +++++++++++++-------------
+ 1 file changed, 13 insertions(+), 13 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi
+index 468614d101c02..25df2bd06735d 100644
+--- a/arch/arm64/boot/dts/qcom/glymur.dtsi
++++ b/arch/arm64/boot/dts/qcom/glymur.dtsi
+@@ -1843,7 +1843,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>,
+ spi0: spi@b80000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x00b80000 0x0 0x4000>;
+- interrupts = <GIC_SPI 1052 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_ESPI 92 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>;
+ clock-names = "se";
+ interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS
+@@ -1870,7 +1870,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>,
+ i2c1: i2c@b84000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x0 0x00b84000 0x0 0x4000>;
+- interrupts = <GIC_SPI 1053 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_ESPI 93 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>;
+ clock-names = "se";
+ interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS
+@@ -1897,7 +1897,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>,
+ spi1: spi@b84000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x00b84000 0x0 0x4000>;
+- interrupts = <GIC_SPI 1053 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_ESPI 93 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>;
+ clock-names = "se";
+ interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS
+@@ -1924,7 +1924,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>,
+ i2c2: i2c@b88000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x0 0x00b88000 0x0 0x4000>;
+- interrupts = <GIC_SPI 1054 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_ESPI 94 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>;
+ clock-names = "se";
+ interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS
+@@ -1951,7 +1951,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>,
+ spi2: spi@b88000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x00b88000 0x0 0x4000>;
+- interrupts = <GIC_SPI 1054 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_ESPI 94 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>;
+ clock-names = "se";
+ interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS
+@@ -1978,7 +1978,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>,
+ uart2: serial@b88000 {
+ compatible = "qcom,geni-uart";
+ reg = <0x0 0x00b88000 0x0 0x4000>;
+- interrupts = <GIC_SPI 1054 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_ESPI 94 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>;
+ clock-names = "se";
+ interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS
+@@ -2023,7 +2023,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>,
+ spi3: spi@b8c000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x00b8c000 0x0 0x4000>;
+- interrupts = <GIC_SPI 1055 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_ESPI 95 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>;
+ clock-names = "se";
+ interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS
+@@ -2077,7 +2077,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>,
+ spi4: spi@b90000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x00b90000 0x0 0x4000>;
+- interrupts = <GIC_SPI 1056 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_ESPI 96 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>;
+ clock-names = "se";
+ interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS
+@@ -2131,7 +2131,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>,
+ spi5: spi@b94000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x00b94000 0x0 0x4000>;
+- interrupts = <GIC_SPI 1057 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_ESPI 97 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>;
+ clock-names = "se";
+ interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS
+@@ -2158,7 +2158,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>,
+ i2c6: i2c@b98000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x0 0x00b98000 0x0 0x4000>;
+- interrupts = <GIC_SPI 1058 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_ESPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_QUPV3_WRAP0_S6_CLK>;
+ clock-names = "se";
+ interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS
+@@ -2185,7 +2185,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>,
+ spi6: spi@b98000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x00b98000 0x0 0x4000>;
+- interrupts = <GIC_SPI 1058 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_ESPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_QUPV3_WRAP0_S6_CLK>;
+ clock-names = "se";
+ interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS
+@@ -2212,7 +2212,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>,
+ i2c7: i2c@b9c000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x0 0x00b9c000 0x0 0x4000>;
+- interrupts = <GIC_SPI 1059 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_ESPI 99 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>;
+ clock-names = "se";
+ interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS
+@@ -2239,7 +2239,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>,
+ spi7: spi@b9c000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x0 0x00b9c000 0x0 0x4000>;
+- interrupts = <GIC_SPI 1059 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_ESPI 99 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>;
+ clock-names = "se";
+ interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS
+--
+2.53.0
+
--- /dev/null
+From e0504d42d5fd9d51b83e56ca770ab5992e5ce3d7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Apr 2026 22:15:19 +0200
+Subject: arm64: dts: qcom: monaco: Add default GIC address cells
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
+
+[ Upstream commit d291245e2fb1eba55d751f88613a41e292958a96 ]
+
+Add missing address-cells 0 to GIC interrupt node to silence W=1
+warning:
+
+ monaco.dtsi:2326.4-2329.30: Warning (interrupt_map): /soc@0/pci@1c00000:interrupt-map:
+ Missing property '#address-cells' in node /soc@0/interrupt-controller@17a00000, using 0 as fallback
+
+Value '0' is correct because:
+1. GIC interrupt controller does not have children,
+2. interrupt-map property (in PCI node) consists of five components and
+ the fourth component 'parent unit address', which size is defined by
+ '#address-cells' of the node pointed to by the interrupt-parent
+ component, is not used (=0).
+
+Fixes: 46a7c01e7e9d ("arm64: dts: qcom: qcs8300: enable pcie0")
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
+Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Link: https://lore.kernel.org/r/20260407201518.24949-2-krzysztof.kozlowski@oss.qualcomm.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/monaco.dtsi | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
+index fa13210fc539a..62e6b60087ee3 100644
+--- a/arch/arm64/boot/dts/qcom/monaco.dtsi
++++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
+@@ -7384,6 +7384,7 @@ intc: interrupt-controller@17a00000 {
+ interrupt-controller;
+ #redistributor-regions = <1>;
+ redistributor-stride = <0x0 0x20000>;
++ #address-cells = <0>;
+ };
+
+ watchdog@17c10000 {
+--
+2.53.0
+
--- /dev/null
+From b6e0397d1c682a29e784cd397d503e29e39fd1d6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Apr 2026 02:38:51 +0530
+Subject: arm64: dts: qcom: purwa: Fix GPU IOMMU property
+
+From: Akhil P Oommen <akhilpo@oss.qualcomm.com>
+
+[ Upstream commit 4cd774c1feb3f720265c512174c5c3312eca1be2 ]
+
+Purwa's GPU does not support SID 1, which is typically used for
+LPAC-related traffic. Remove SID 1 from the GPU node's iommus property to
+accurately describe the hardware. This fixes the splat below, seen with
+some versions of Gunyah hypervisor:
+
+ Internal error: synchronous external abort: 0000000096000010 [#1] SMP
+ CPU: 0 UID: 0 PID: 80 Comm: kworker/u33:2 Tainted: G M
+ Tainted: [M]=MACHINE_CHECK
+ Hardware name: Qualcomm Technologies, Inc. Purwa IoT EVK (DT)
+ Workqueue: events_unbound deferred_probe_work_func
+ pstate: 21400005 (nzCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
+ pc : arm_smmu_write_s2cr+0x9c/0xbc
+ lr : arm_smmu_master_install_s2crs+0x78/0xa4
+ sp : ffff80008039b570
+ x29: ffff80008039b570 x28: 0000000000000000 x27: ffffaddd62f1ab78
+ x26: ffff00080a4ff280 x25: 0000000000000018 x24: ffff00080b896480
+ x23: ffff00080ba9b7a0 x22: ffff00080bb05160 x21: 0000000000000000
+ x20: 0000000000000000 x19: 0000000000000001 x18: 00000000ffffffff
+ x17: 0000000000000000 x16: 0000000000000000 x15: ffff80008039b1d0
+ x14: ffff80010039b37d x13: 00746c7561662d74 x12: 0000000000000000
+ x11: ffff00080b7fbd98 x10: ffffffffffffffc0 x9 : ffffffffffffffff
+ x8 : 0000000000000228 x7 : 0000000000000e87 x6 : 0000000000000000
+ x5 : 0000000000000000 x4 : ffff00080a4ff280 x3 : 0000000000000000
+ x2 : ffff800082a40c04 x1 : 0000000000000000 x0 : ffff800082a40000
+ Call trace:
+ arm_smmu_write_s2cr+0x9c/0xbc (P)
+ arm_smmu_master_install_s2crs+0x78/0xa4
+ arm_smmu_attach_dev+0xb0/0x1d8
+ __iommu_device_set_domain+0x84/0x11c
+ __iommu_group_set_domain_internal+0x60/0x120
+ __iommu_attach_group+0x88/0x9c
+ iommu_attach_device+0x6c/0xa0
+ msm_iommu_new.part.0+0x84/0xe4 [msm]
+ msm_iommu_gpu_new+0x3c/0x104 [msm]
+ adreno_iommu_create_vm+0x24/0xc8 [msm]
+ a6xx_create_vm+0x48/0x78 [msm]
+ msm_gpu_init+0x2d8/0x508 [msm]
+ adreno_gpu_init+0x208/0x324 [msm]
+ a6xx_gpu_init+0x604/0x8cc [msm]
+ adreno_bind+0xb4/0x124 [msm]
+ component_bind_all+0x114/0x23c
+ msm_drm_init+0x1b0/0x1ec [msm]
+ msm_drm_bind+0x30/0x3c [msm]
+ try_to_bring_up_aggregate_device+0x164/0x1d0
+ __component_add+0xa4/0x16c
+ component_add+0x14/0x20
+ msm_dp_display_probe_tail+0x4c/0xac [msm]
+ msm_dp_auxbus_done_probe+0x14/0x20 [msm]
+ dp_aux_ep_probe+0x4c/0xf4 [drm_dp_aux_bus]
+ really_probe+0xbc/0x29c
+ __driver_probe_device+0x78/0x12c
+ driver_probe_device+0x3c/0x15c
+ __device_attach_driver+0xb8/0x134
+ bus_for_each_drv+0x88/0xe8
+ __device_attach+0xa0/0x190
+ device_initial_probe+0x50/0x54
+ bus_probe_device+0x38/0xa4
+ deferred_probe_work_func+0x88/0xc0
+ process_one_work+0x148/0x28c
+ worker_thread+0x2cc/0x3d4
+ kthread+0x12c/0x204
+ ret_from_fork+0x10/0x20
+ ---[ end trace 0000000000000000 ]---
+
+Fixes: 1aa0b4e36436 ("arm64: dts: qcom: x1p42100: Add GPU support")
+Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Link: https://lore.kernel.org/r/20260410-purwa-gpu-dt-fix-v1-1-4637892156cf@oss.qualcomm.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/purwa.dtsi | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/qcom/purwa.dtsi b/arch/arm64/boot/dts/qcom/purwa.dtsi
+index 9ab4f26b35f29..5b17840fb62fb 100644
+--- a/arch/arm64/boot/dts/qcom/purwa.dtsi
++++ b/arch/arm64/boot/dts/qcom/purwa.dtsi
+@@ -47,6 +47,8 @@ &gmu {
+ &gpu {
+ compatible = "qcom,adreno-43030c00", "qcom,adreno";
+
++ iommus = <&adreno_smmu 0 0x0>;
++
+ nvmem-cells = <&gpu_speed_bin>;
+ nvmem-cell-names = "speed_bin";
+
+--
+2.53.0
+
--- /dev/null
+From 61d5d2864edaf2976a1476344fe9bd64599b66d9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Apr 2026 01:27:12 +0300
+Subject: arm64: dts: qcom: sdm850-lenovo-yoga-c630: lower PSCI cluster idle
+
+From: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+
+[ Upstream commit 07db10de262f4150e24fd631a7a6c428f7bf80c9 ]
+
+With the default PSCI suspend value for cluster idle state Lenovo Yoga
+C630 isn't stable enough. For example it might reset if display device
+isn't probed early enough. Drop the bit 0x4000 from the PSCI suspend
+value to make C630 work in stable way. The bit was found by
+expertimenting with the cluster idle PSCI value. Most likely it results
+in the less deep sleep and more energy beign spent in the suspend state,
+but it's better than the non-stable system behaviour.
+
+Fixes: a1ade6cac5a2 ("arm64: dts: qcom: sdm845: Switch PSCI cpu idle states from PC to OSI")
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Reviewed-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
+Link: https://lore.kernel.org/r/20260429-c630-fix-idle-v2-1-ac867dad6f21@oss.qualcomm.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
+index e41200839dbec..8cdaef5360d11 100644
+--- a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
++++ b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
+@@ -347,6 +347,10 @@ &cdsp_pas {
+ status = "okay";
+ };
+
++&cluster_sleep_0 {
++ arm,psci-suspend-param = <0x41008244>;
++};
++
+ &gcc {
+ protected-clocks = <GCC_QSPI_CORE_CLK>,
+ <GCC_QSPI_CORE_CLK_SRC>,
+--
+2.53.0
+
--- /dev/null
+From dd5583ad318c68e3e4bb9e3856cbc71e80c86d8b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Apr 2026 23:45:18 +0000
+Subject: arm64: dts: qcom: sm8650: Fix IPA IMEM slice
+
+From: Alexander Koskovich <akoskovich@pm.me>
+
+[ Upstream commit 41d237b1546af5d5cf877175930cd23163422c83 ]
+
+Downstream the IPA IMEM slice for SM8650 is described as:
+qcom,additional-mapping = <0x14683000 0x14683000 0x2000>;
+
+Update upstream ipa_modem_tables to reflect downstream.
+
+Signed-off-by: Alexander Koskovich <akoskovich@pm.me>
+Fixes: 581fc5d5ade6 ("arm64: dts: qcom: sm8650: Explicitly describe the IPA IMEM slice")
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Link: https://lore.kernel.org/r/20260415-fix-8650-ipa-modem-tables-v1-1-95f8f425e416@pm.me
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/sm8650.dtsi | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi
+index e2d98cf6adca8..ecfa3478cbdde 100644
+--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi
++++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi
+@@ -7091,8 +7091,8 @@ sram@14680000 {
+
+ ranges = <0 0 0x14680000 0x2c000>;
+
+- ipa_modem_tables: modem-tables@8000 {
+- reg = <0x8000 0x2000>;
++ ipa_modem_tables: modem-tables@3000 {
++ reg = <0x3000 0x2000>;
+ };
+ };
+
+--
+2.53.0
+
--- /dev/null
+From 33df9dc6ef8524fae209c4067ab1f2f7ce88c2eb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 14:06:28 +0800
+Subject: ata: pata_sl82c105: fix bridge revision use-after-free
+
+From: Hongyan Xu <getshell@seu.edu.cn>
+
+[ Upstream commit 7700a31039cdc6715cb6cce7e7a664ee4e945f67 ]
+
+pci_get_slot() returns a referenced PCI device. Commit 44c10138fd4b
+("PCI: Change all drivers to use pci_device->revision") replaced a
+configuration-space read with direct access to the cached revision field,
+but left that access after pci_dev_put(). The bridge may therefore be freed
+before its revision is read.
+
+Read the revision before dropping the reference.
+
+Fixes: 44c10138fd4b ("PCI: Change all drivers to use pci_device->revision")
+Signed-off-by: Hongyan Xu <getshell@seu.edu.cn>
+Reviewed-by: Niklas Cassel <cassel@kernel.org>
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ata/pata_sl82c105.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
+index 2d24c6b3e9d9f..25bce3fe2a101 100644
+--- a/drivers/ata/pata_sl82c105.c
++++ b/drivers/ata/pata_sl82c105.c
+@@ -264,6 +264,7 @@ static struct ata_port_operations sl82c105_port_ops = {
+ static int sl82c105_bridge_revision(struct pci_dev *pdev)
+ {
+ struct pci_dev *bridge;
++ u8 revision;
+
+ /*
+ * The bridge should be part of the same device, but function 0.
+@@ -285,8 +286,9 @@ static int sl82c105_bridge_revision(struct pci_dev *pdev)
+ /*
+ * We need to find function 0's revision, not function 1
+ */
++ revision = bridge->revision;
+ pci_dev_put(bridge);
+- return bridge->revision;
++ return revision;
+ }
+
+ static void sl82c105_fixup(struct pci_dev *pdev)
+--
+2.53.0
+
--- /dev/null
+From 851259a955366c9e483546cef17293e050c586b8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:22:59 -0700
+Subject: bnge: Fix NULL pointer dereference in aux device release
+
+From: Alok Tiwari <alok.a.tiwari@oracle.com>
+
+[ Upstream commit 1cb4298810e27e037d3ca07286ecbb97e89ba58d ]
+
+If allocation of auxr_dev fails during auxiliary device setup, the error
+path calls auxiliary_device_uninit(), which eventually invokes
+bnge_aux_dev_release().
+
+The release callback unconditionally dereferences aux_priv->auxr_dev->pdev
+to retrieve the parent bnge_dev. Since auxr_dev has not yet been allocated
+on this failure path, the dereference results in a NULL pointer exception
+
+Retrieve the parent bnge_dev from the auxiliary device's parent instead of
+auxr_dev, and free auxr_dev only when it was successfully allocated. This
+allows the release callback to correctly clean up partially initialized
+auxiliary devices.
+
+Fixes: 8ac050ec3b1c ("bng_en: Add RoCE aux device support")
+Signed-off-by: Alok Tiwari <alok.a.tiwari@oracle.com>
+Reviewed-by: Bhargava Marreddy <bhargava.marreddy@broadcom.com>
+Link: https://patch.msgid.link/20260731192301.1427645-1-alok.a.tiwari@oracle.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnge/bnge_auxr.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_auxr.c b/drivers/net/ethernet/broadcom/bnge/bnge_auxr.c
+index 67e93e17d4d9f..0955b488b6fea 100644
+--- a/drivers/net/ethernet/broadcom/bnge/bnge_auxr.c
++++ b/drivers/net/ethernet/broadcom/bnge/bnge_auxr.c
+@@ -141,12 +141,15 @@ static void bnge_aux_dev_release(struct device *dev)
+ {
+ struct bnge_auxr_priv *aux_priv =
+ container_of(dev, struct bnge_auxr_priv, aux_dev.dev);
+- struct bnge_dev *bd = pci_get_drvdata(aux_priv->auxr_dev->pdev);
++ struct bnge_auxr_dev *auxr_dev = aux_priv->auxr_dev;
++ struct bnge_dev *bd = pci_get_drvdata(to_pci_dev(dev->parent));
+
+ ida_free(&bnge_aux_dev_ids, aux_priv->id);
+- kfree(aux_priv->auxr_dev->auxr_info);
++ if (auxr_dev) {
++ kfree(auxr_dev->auxr_info);
++ kfree(auxr_dev);
++ }
+ bd->auxr_dev = NULL;
+- kfree(aux_priv->auxr_dev);
+ kfree(aux_priv);
+ bd->aux_priv = NULL;
+ }
+--
+2.53.0
+
--- /dev/null
+From 067e01bda598d83db5fcb4eaab0e6cfa540bf643 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 15:10:22 +0530
+Subject: bnge: Fix resource leak in bnge_init_nic() error path
+
+From: Bhargava Marreddy <bhargava.marreddy@broadcom.com>
+
+[ Upstream commit bfec39ff1484b4e9f7d93bc4580fdb634bbc7d19 ]
+
+If bnge_init_chip() fails, bnge_init_nic() jumps to err_free_ring_grps
+and returns immediately, skipping cleanup for RX ring pair buffers.
+
+Remove the early return so execution falls through to
+err_free_rx_ring_pair_bufs to properly free resources on error.
+
+Fixes: 23df6aebf803 ("bng_en: Allocate stat contexts")
+Signed-off-by: Bhargava Marreddy <bhargava.marreddy@broadcom.com>
+Reviewed-by: Dharmender Garg <dharmender.garg@broadcom.com>
+Reviewed-by: Rajashekar Hudumula <rajashekar.hudumula@broadcom.com>
+Link: https://patch.msgid.link/20260805094022.15487-1-bhargava.marreddy@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnge/bnge_netdev.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
+index 6f7ef506d4e18..ac4c93e5b634a 100644
+--- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
++++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
+@@ -2768,8 +2768,6 @@ static int bnge_init_nic(struct bnge_net *bn)
+
+ err_free_ring_grps:
+ bnge_free_ring_grps(bn);
+- return rc;
+-
+ err_free_rx_ring_pair_bufs:
+ bnge_free_rx_ring_pair_bufs(bn);
+ return rc;
+--
+2.53.0
+
--- /dev/null
+From 4d7c07f17587437a6d726007f515d86766967ff2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 1 Aug 2026 03:09:20 -0700
+Subject: bnge: use int for bnge_fix_rings_count() return value
+
+From: Alok Tiwari <alok.a.tiwari@oracle.com>
+
+[ Upstream commit 2cbd8a4e5e09aa232a1f8d56ce3d070b18ab2b10 ]
+
+bnge_fix_rings_count() returns 0 on success or a negative errno on failure
+However, bnge_adjust_rings() stores its return value in a u16 variable,
+causing negative error codes such as -ENOMEM to be converted to a large
+positive value.
+
+Use an int for the return code variable so that error values are
+preserved and propagated correctly.
+
+Fixes: 627c67f038d2 ("bng_en: Add resource management support")
+Signed-off-by: Alok Tiwari <alok.a.tiwari@oracle.com>
+Reviewed-by: Bhargava Marreddy <bhargava.marreddy@broadcom.com>
+Link: https://patch.msgid.link/20260801100923.1498570-1-alok.a.tiwari@oracle.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnge/bnge_resc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_resc.c b/drivers/net/ethernet/broadcom/bnge/bnge_resc.c
+index 0e94f092813e0..4711dd4945ffe 100644
+--- a/drivers/net/ethernet/broadcom/bnge/bnge_resc.c
++++ b/drivers/net/ethernet/broadcom/bnge/bnge_resc.c
+@@ -163,7 +163,8 @@ static int bnge_adjust_rings(struct bnge_dev *bd, u16 *rx,
+ u16 tx_chunks = bnge_num_tx_to_cp(bd, *tx);
+
+ if (tx_chunks != *tx) {
+- u16 tx_saved = tx_chunks, rc;
++ u16 tx_saved = tx_chunks;
++ int rc;
+
+ rc = bnge_fix_rings_count(rx, &tx_chunks, max_nq, sh);
+ if (rc)
+--
+2.53.0
+
--- /dev/null
+From 1200751616e5a1d1f77012aa17410aad6530e7de Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:01:31 -0700
+Subject: bnxt: fix memory leak in bnxt_queue_mem_alloc error cases
+
+From: Will Chen <will.chen.tty@gmail.com>
+
+[ Upstream commit d1000fd7995e51deec872d154e0a40d82f7a539f ]
+
+There is a small memory leak in bnxt_queue_mem_alloc:
+when bnxt_alloc_rx_agg_bmap() succeeds
+but bnxt_alloc_one_tpa_info() later fails,
+the rx_agg_bmap allocated by bnxt_alloc_rx_agg_bmap()
+is not freed in the fallthrough cleanup cases.
+
+Free the rx_agg_bmap in the err_free_rx_agg_ring case
+and initialize clone->rx_agg_bmap = NULL earlier in the function
+to allow for safe fallthrough.
+
+Fixes: bd649c5cc958 ("bnxt_en: handle tpa_info in queue API implementation")
+Signed-off-by: Will Chen <will.chen.tty@gmail.com>
+Reviewed-by: Joe Damato <joe@dama.to>
+Reviewed-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260729220132.1256924-1-will.chen.tty@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index d44d3ac255aa4..cb6e45fc9cd98 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -16225,6 +16225,7 @@ static int bnxt_queue_mem_alloc(struct net_device *dev,
+ clone->rx_next_cons = 0;
+ clone->need_head_pool = false;
+ clone->rx_page_size = qcfg->rx_page_size;
++ clone->rx_agg_bmap = NULL;
+
+ rc = bnxt_alloc_rx_page_pool(bp, clone, rxr->page_pool->p.nid);
+ if (rc)
+@@ -16277,6 +16278,8 @@ static int bnxt_queue_mem_alloc(struct net_device *dev,
+ bnxt_free_one_tpa_info(bp, clone);
+ err_free_rx_agg_ring:
+ bnxt_free_ring(bp, &clone->rx_agg_ring_struct.ring_mem);
++ kfree(clone->rx_agg_bmap);
++ clone->rx_agg_bmap = NULL;
+ err_free_rx_ring:
+ bnxt_free_ring(bp, &clone->rx_ring_struct.ring_mem);
+ err_rxq_info_unreg:
+--
+2.53.0
+
--- /dev/null
+From 350f771fd0318644180a9243771678aa8bab9d91 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:34 -0700
+Subject: bnxt_en: Determine and store default RX ring in vnic structure
+
+From: Shravya KN <shravya.k-n@broadcom.com>
+
+[ Upstream commit 53f01cd594e223aabb538d5288e60111523c96f2 ]
+
+Each VNIC has a default RX ring. The purpose of the default RX ring
+is to provide a destination for any packets that cannot be parsed by
+the RSS logic. Up until now, the default RX ring is always Ring 0.
+
+We neglected to take care of this default RX ring when adding the
+queue restart feature. If ring 0 (default ring) is re-started, it
+may now have a new FW ring ID after freeing the old one and
+allocating a new one. The VNIC now may have a stale default ring
+and it may generate an internal exception. This exception may
+appear in dmesg:
+
+FW reported unknown error type 10
+
+The best way to resolve this issue is to use a more appropriate
+ring for the default ring instead of always ring 0. Ring 0 may not
+even be in the RSS table, especially on a new RSS context.
+
+This patch adds the logic to determine and store the proper default
+RX ring for a VNIC. For an RSS VNIC, the default ring is the lowest
+ring number in the RSS table. The next patch will add proper logic
+to update the VNIC if the default ring changes after queue restart.
+
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Shravya KN <shravya.k-n@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-3-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 0b137529a899 ("bnxt_en: Refresh VNIC default ring on queue restart if needed")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 33 +++++++++++++++--------
+ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
+ 2 files changed, 23 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 2fbc98fa14f62..4ea6adfc5c22a 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -6704,25 +6704,36 @@ int bnxt_get_nr_rss_ctxs(struct bnxt *bp, int rx_rings)
+ static void bnxt_fill_hw_rss_tbl(struct bnxt *bp, struct bnxt_vnic_info *vnic)
+ {
+ bool no_rss = !(vnic->flags & BNXT_VNIC_RSS_FLAG);
+- u16 i, j;
++ u16 i, j, min_j = bp->rx_nr_rings - 1;
+
+ if (!vnic->rss_table)
+- return;
++ goto skip_rss_tbl;
+
+ /* Fill the RSS indirection table with ring group ids */
+ for (i = 0, j = 0; i < HW_HASH_INDEX_SIZE; i++) {
+ if (!no_rss)
+ j = bp->rss_indir_tbl[i];
++ min_j = min(j, min_j);
+ vnic->rss_table[i] = cpu_to_le16(vnic->fw_grp_ids[j]);
+ }
++
++skip_rss_tbl:
++ if (vnic->rss_table && !no_rss)
++ vnic->default_rx_ring = min_j;
++ else if (vnic->flags & BNXT_VNIC_RFS_FLAG)
++ vnic->default_rx_ring = vnic->vnic_id - 1;
++ else if ((vnic->vnic_id == 1) && BNXT_CHIP_TYPE_NITRO_A0(bp))
++ vnic->default_rx_ring = bp->rx_nr_rings - 1;
++ else
++ vnic->default_rx_ring = 0;
+ }
+
+ static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp,
+ struct bnxt_vnic_info *vnic)
+ {
++ u16 tbl_size, i, min_j = bp->rx_nr_rings - 1;
+ __le16 *ring_tbl = vnic->rss_table;
+ struct bnxt_rx_ring_info *rxr;
+- u16 tbl_size, i;
+
+ tbl_size = bnxt_get_rxfh_indir_size(bp->dev);
+
+@@ -6735,6 +6746,7 @@ static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp,
+ j = ethtool_rxfh_context_indir(vnic->rss_ctx)[i];
+ else
+ j = bp->rss_indir_tbl[i];
++ min_j = min(j, min_j);
+ rxr = &bp->rx_ring[j];
+
+ ring_id = rxr->rx_ring_struct.fw_ring_id;
+@@ -6742,6 +6754,7 @@ static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp,
+ ring_id = bnxt_cp_ring_for_rx(bp, rxr);
+ *ring_tbl++ = cpu_to_le16(ring_id);
+ }
++ vnic->default_rx_ring = min_j;
+ }
+
+ static void
+@@ -6938,8 +6951,9 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, struct bnxt_vnic_info *vnic)
+ return rc;
+
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
+- struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0];
++ struct bnxt_rx_ring_info *rxr;
+
++ rxr = &bp->rx_ring[vnic->default_rx_ring];
+ req->default_rx_ring_id =
+ cpu_to_le16(rxr->rx_ring_struct.fw_ring_id);
+ req->default_cmpl_ring_id =
+@@ -6972,13 +6986,7 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, struct bnxt_vnic_info *vnic)
+ req->cos_rule = cpu_to_le16(0xffff);
+ }
+
+- if (vnic->flags & BNXT_VNIC_RSS_FLAG)
+- ring = 0;
+- else if (vnic->flags & BNXT_VNIC_RFS_FLAG)
+- ring = vnic->vnic_id - 1;
+- else if ((vnic->vnic_id == 1) && BNXT_CHIP_TYPE_NITRO_A0(bp))
+- ring = bp->rx_nr_rings - 1;
+-
++ ring = vnic->default_rx_ring;
+ grp_idx = bp->rx_ring[ring].bnapi->index;
+ req->dflt_ring_grp = cpu_to_le16(bp->grp_info[grp_idx].fw_grp_id);
+ req->lb_rule = cpu_to_le16(0xffff);
+@@ -11171,6 +11179,9 @@ static int bnxt_setup_nitroa0_vnic(struct bnxt *bp)
+ return rc;
+ }
+
++ /* Setup the proper default RX ring */
++ bnxt_fill_hw_rss_tbl(bp, vnic);
++
+ rc = bnxt_hwrm_vnic_cfg(bp, vnic);
+ if (rc) {
+ netdev_err(bp->dev, "Cannot allocate special vnic for NS2 A0: %x\n",
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+index fa13cee557798..8e04cc934c32b 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+@@ -1334,6 +1334,7 @@ struct bnxt_vnic_info {
+ #define BNXT_VNIC_RSSCTX_FLAG 0x40
+ struct ethtool_rxfh_context *rss_ctx;
+ u32 vnic_id;
++ u16 default_rx_ring;
+ };
+
+ struct bnxt_rss_ctx {
+--
+2.53.0
+
--- /dev/null
+From 194d0e47a3648717069a69ee40a69793a20823b3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:36 -0700
+Subject: bnxt_en: Disable EOP for TPA on all chips to prevent data corruption
+
+From: Michael Chan <michael.chan@broadcom.com>
+
+[ Upstream commit c3faf548a00f4c17100cc9204746975fa46a73b9 ]
+
+EOP (End of frame padding) on the AGG ring may cause overlapping of
+zero padding at the end of one segment with the next segment's data.
+If Relaxed Ordering (RO) is enabled, the zero padding may overwrite
+valid data in the next segment and corrupt the data. Older chips
+(P5 and older) do not automatically disable RO when EOP is enabled.
+On some ARM systems, data corruption was reported on 57508 (P5)
+chips with RO enabled.
+
+Always disable EOP on all chips on the AGG rings when TPA is enabled
+to fix the data corruption.
+
+Fixes: bfcd8d791ec1 ("bnxt_en: Add fast path logic for TPA on 57500 chips.")
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-5-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index e7145537f3e73..1cd6e88d4e814 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -4611,11 +4611,14 @@ static void bnxt_init_one_rx_agg_ring_rxbd(struct bnxt *bp,
+ type = ((u32)rxr->rx_page_size << RX_BD_LEN_SHIFT) |
+ RX_BD_TYPE_RX_AGG_BD;
+
+- /* On P7, setting EOP will cause the chip to disable
+- * Relaxed Ordering (RO) for TPA data. Disable EOP for
+- * potentially higher performance with RO.
++ /* Disable EOP if TPA is enabled to prevent overlapping zero
++ * padding with the next segment's data. On P7_PLUS, EOP will
++ * automatically disable Relaxed Ordering (RO) to prevent
++ * potential data corruption (and may degrade performance). On
++ * older chips, RO will not be automatically disabled and may
++ * cause corruption.
+ */
+- if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
++ if (!(bp->flags & BNXT_FLAG_TPA))
+ type |= RX_BD_FLAGS_AGG_EOP;
+
+ bnxt_init_rxbd_pages(ring, type);
+--
+2.53.0
+
--- /dev/null
+From c983bb02d31d9dd3d292f3069a856ec5f961ec5e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:37 -0700
+Subject: bnxt_en: Fix PTP PPS setting bug
+
+From: Keegan Freyhof <keegan.freyhof@broadcom.com>
+
+[ Upstream commit 80eaf88efec33ac77ed7726d066c4f2f932cc329 ]
+
+The existing driver logic is always turning on PTP_CLK_REQ_PPS
+regardless of the "on" parameter passed to bnxt_ptp_enable().
+During shutdown, PTP_CLK_REQ_PPS may be turned off and this
+bug will do the opposite and may trigger a PCIe PTM request TLP.
+On some systems this can trigger a PCIe AER.
+
+Fix it by properly configuring PTP_CLK_REQ_PPS based on the "on"
+parameter.
+
+Fixes: 9e518f25802c ("bnxt_en: 1PPS functions to configure TSIO pins")
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Keegan Freyhof <keegan.freyhof@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-6-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
+index 5d41dc1bc7820..b89293dfd2d1e 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
+@@ -495,12 +495,15 @@ static int bnxt_ptp_enable(struct ptp_clock_info *ptp_info,
+ return rc;
+ case PTP_CLK_REQ_PPS:
+ /* Configure PHC PPS IN */
+- rc = bnxt_ptp_cfg_pin(bp, 0, BNXT_PPS_PIN_PPS_IN);
++ pin_id = 0;
++ if (!on)
++ break;
++ rc = bnxt_ptp_cfg_pin(bp, pin_id, BNXT_PPS_PIN_PPS_IN);
+ if (rc)
+ return rc;
+ rc = bnxt_ptp_cfg_event(bp, BNXT_PPS_EVENT_INTERNAL);
+ if (!rc)
+- ptp->pps_info.pins[0].event = BNXT_PPS_EVENT_INTERNAL;
++ ptp->pps_info.pins[pin_id].event = BNXT_PPS_EVENT_INTERNAL;
+ return rc;
+ default:
+ netdev_err(ptp->bp->dev, "Unrecognized PIN function\n");
+--
+2.53.0
+
--- /dev/null
+From 8e27366cbe015e104fcd13086e80361b8f0151a3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:33 -0700
+Subject: bnxt_en: Move RSS table fill outside __bnxt_hwrm_vnic_set_rss()
+
+From: Shravya KN <shravya.k-n@broadcom.com>
+
+[ Upstream commit 1d0fc6c7ea49994b8ff50d02979d1e4207ec6c4f ]
+
+This is a refactor patch with no change in behavior. The caller
+will now fill the RSS table before calling __bnxt_hwrm_vnic_set_rss().
+In the next patch, we'll add code to determine the default ring for
+the VNIC when we fill the RSS table.
+
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Shravya KN <shravya.k-n@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-2-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 0b137529a899 ("bnxt_en: Refresh VNIC default ring on queue restart if needed")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index cb6e45fc9cd98..2fbc98fa14f62 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -6706,6 +6706,9 @@ static void bnxt_fill_hw_rss_tbl(struct bnxt *bp, struct bnxt_vnic_info *vnic)
+ bool no_rss = !(vnic->flags & BNXT_VNIC_RSS_FLAG);
+ u16 i, j;
+
++ if (!vnic->rss_table)
++ return;
++
+ /* Fill the RSS indirection table with ring group ids */
+ for (i = 0, j = 0; i < HW_HASH_INDEX_SIZE; i++) {
+ if (!no_rss)
+@@ -6745,13 +6748,8 @@ static void
+ __bnxt_hwrm_vnic_set_rss(struct bnxt *bp, struct hwrm_vnic_rss_cfg_input *req,
+ struct bnxt_vnic_info *vnic)
+ {
+- if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
+- bnxt_fill_hw_rss_tbl_p5(bp, vnic);
+- if (bp->flags & BNXT_FLAG_CHIP_P7)
+- req->flags |= VNIC_RSS_CFG_REQ_FLAGS_IPSEC_HASH_TYPE_CFG_SUPPORT;
+- } else {
+- bnxt_fill_hw_rss_tbl(bp, vnic);
+- }
++ if (bp->flags & BNXT_FLAG_CHIP_P7)
++ req->flags |= VNIC_RSS_CFG_REQ_FLAGS_IPSEC_HASH_TYPE_CFG_SUPPORT;
+
+ if (bp->rss_hash_delta) {
+ req->hash_type = cpu_to_le32(bp->rss_hash_delta);
+@@ -6803,6 +6801,7 @@ static int bnxt_hwrm_vnic_set_rss_p5(struct bnxt *bp,
+ if (!set_rss)
+ return hwrm_req_send(bp, req);
+
++ bnxt_fill_hw_rss_tbl_p5(bp, vnic);
+ __bnxt_hwrm_vnic_set_rss(bp, req, vnic);
+ ring_tbl_map = vnic->rss_table_dma_addr;
+ nr_ctxs = bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings);
+@@ -10866,6 +10865,7 @@ static int __bnxt_setup_vnic(struct bnxt *bp, struct bnxt_vnic_info *vnic)
+ }
+
+ skip_rss_ctx:
++ bnxt_fill_hw_rss_tbl(bp, vnic);
+ /* configure default vnic, ring grp */
+ rc = bnxt_hwrm_vnic_cfg(bp, vnic);
+ if (rc) {
+--
+2.53.0
+
--- /dev/null
+From 2480bc4ab31d47c5b49b9e9aff79bc8cdf3bbe29 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:09:35 -0700
+Subject: bnxt_en: Refresh VNIC default ring on queue restart if needed
+
+From: Shravya KN <shravya.k-n@broadcom.com>
+
+[ Upstream commit 0b137529a8997caf67190ca1d71ba8bbdb44fbfb ]
+
+When a queue is restarted, refresh VNIC_CFG for all VNICs whose
+default RX ring is the restarted ring. This will eliminate this
+possible FW warning caused by a stale default ring in the VNIC:
+
+FW reported unknown error type 10
+
+Fixes: 5ac066b7b062 ("bnxt_en: Fix queue start to update vnic RSS table")
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Shravya KN <shravya.k-n@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260731190937.807270-4-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 4ea6adfc5c22a..e7145537f3e73 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -11098,6 +11098,11 @@ static int bnxt_set_vnic_mru_p5(struct bnxt *bp, struct bnxt_vnic_info *vnic,
+ vnic->vnic_id, rc);
+ return rc;
+ }
++ if (rxr_id == vnic->default_rx_ring) {
++ rc = bnxt_hwrm_vnic_cfg(bp, vnic);
++ if (rc)
++ return rc;
++ }
+ }
+ vnic->mru = mru;
+ bnxt_hwrm_vnic_update(bp, vnic,
+--
+2.53.0
+
--- /dev/null
+From ee79950d43091222dc6e901c19361f695a0c9afe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 25 Jul 2026 23:39:30 +0000
+Subject: bonding: alb: re-check primary_is_promisc under RTNL in
+ bond_alb_monitor
+
+From: Xiang Mei (Microsoft) <xmei5@asu.edu>
+
+[ Upstream commit 683c6ba6e58e6ed1037831ea97dd58d9c0e76b8d ]
+
+bond_alb_monitor() reads primary_is_promisc under RCU, then drops RCU and
+takes RTNL via rtnl_trylock() before undoing the promiscuity it set on the
+active slave. In that window the active slave can change under RTNL
+(RTM_DELLINK -> __bond_release_one() -> bond_alb_handle_active_change()),
+which already drops the promiscuity and clears primary_is_promisc. The
+monitor still acts on the stale decision: if the slave was removed with no
+failover, curr_active_slave is now NULL and the deref faults; if it failed
+over, the stale dev_set_promiscuity(-1) underflows the new slave's
+promiscuity counter and pins it in IFF_PROMISC.
+
+ Oops: general protection fault, probably for non-canonical address ...
+ KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
+ Workqueue: b42 bond_alb_monitor
+ RIP: 0010:bond_alb_monitor (drivers/net/bonding/bond_alb.c:1600)
+ process_one_work (kernel/workqueue.c:3322)
+ worker_thread (kernel/workqueue.c:3486)
+ kthread (kernel/kthread.c:436)
+ ret_from_fork (arch/x86/kernel/process.c:158)
+ Kernel panic - not syncing: Fatal exception
+
+Re-check primary_is_promisc (and curr_active_slave) after taking RTNL so
+the monitor only undoes an increment it still owns. The other bonding
+monitors already re-read state under RTNL in their commit phase
+(bond_miimon_commit/bond_ab_arp_commit); bond_alb_monitor() was the only
+one acting on the pre-trylock decision.
+
+Fixes: d0e81b7e2246 ("bonding: Acquire correct locks in alb for promisc change")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
+Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
+Acked-by: Jay Vosburgh <jv@jvosburgh.net>
+Link: https://patch.msgid.link/20260725233930.2957317-1-xmei5@asu.edu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/bonding/bond_alb.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
+index 2d37b07c8215c..839f7482dc182 100644
+--- a/drivers/net/bonding/bond_alb.c
++++ b/drivers/net/bonding/bond_alb.c
+@@ -1534,8 +1534,8 @@ void bond_alb_monitor(struct work_struct *work)
+ struct bonding *bond = container_of(work, struct bonding,
+ alb_work.work);
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
++ struct slave *slave, *curr;
+ struct list_head *iter;
+- struct slave *slave;
+
+ if (!bond_has_slaves(bond)) {
+ atomic_set(&bond_info->tx_rebalance_counter, 0);
+@@ -1597,9 +1597,11 @@ void bond_alb_monitor(struct work_struct *work)
+ * because a slave was disabled then
+ * it can now leave promiscuous mode.
+ */
+- dev_set_promiscuity(rtnl_dereference(bond->curr_active_slave)->dev,
+- -1);
+- bond_info->primary_is_promisc = 0;
++ curr = rtnl_dereference(bond->curr_active_slave);
++ if (bond_info->primary_is_promisc && curr) {
++ dev_set_promiscuity(curr->dev, -1);
++ bond_info->primary_is_promisc = 0;
++ }
+
+ rtnl_unlock();
+ rcu_read_lock();
+--
+2.53.0
+
--- /dev/null
+From a5d5175879d9f58a9de17888de75188f41ca70a3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 22:29:01 +0800
+Subject: bpf: Check sk_state before sk_protocol in bpf_tcp_*_syncookie
+
+From: Luxiao Xu <rakukuip@gmail.com>
+
+[ Upstream commit 31a420a822ff92e2090bd5d65efe8e34e2d6d9b8 ]
+
+bpf_tcp_gen_syncookie and bpf_tcp_check_syncookie accept a socket pointer
+'sk' with argument type ARG_PTR_TO_BTF_ID_SOCK_COMMON. However, they access
+sk->sk_protocol without validating whether 'sk' represents a full socket.
+
+Fix this issue by checking sk->sk_state != TCP_LISTEN before inspecting
+sk->sk_protocol in both bpf_tcp_gen_syncookie and bpf_tcp_check_syncookie.
+Since mini-sockets are never in the TCP_LISTEN state, the condition
+short-circuits and prevents dereferencing fullsock-specific fields.
+
+Fixes: 399040847084 ("bpf: add helper to check for a valid SYN cookie")
+Fixes: 70d66244317e ("bpf: add bpf_tcp_gen_syncookie helper")
+Reported-by: Vega <vega@nebusec.ai>
+Signed-off-by: Luxiao Xu <rakukuip@gmail.com>
+Signed-off-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Link: https://lore.kernel.org/bpf/6218aa3534d0d2d3f448fde70a8dc2769d7a8201.1785823138.git.rakukuip@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/filter.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/core/filter.c b/net/core/filter.c
+index 66837e93d3f25..233adfdc1c340 100644
+--- a/net/core/filter.c
++++ b/net/core/filter.c
+@@ -7645,7 +7645,7 @@ BPF_CALL_5(bpf_tcp_check_syncookie, struct sock *, sk, void *, iph, u32, iph_len
+ return -EINVAL;
+
+ /* sk_listener() allows TCP_NEW_SYN_RECV, which makes no sense here. */
+- if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN)
++ if (sk->sk_state != TCP_LISTEN || sk->sk_protocol != IPPROTO_TCP)
+ return -EINVAL;
+
+ if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies))
+@@ -7718,7 +7718,7 @@ BPF_CALL_5(bpf_tcp_gen_syncookie, struct sock *, sk, void *, iph, u32, iph_len,
+ if (unlikely(!sk || th_len < sizeof(*th) || th_len != th->doff * 4))
+ return -EINVAL;
+
+- if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN)
++ if (sk->sk_state != TCP_LISTEN || sk->sk_protocol != IPPROTO_TCP)
+ return -EINVAL;
+
+ if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies))
+--
+2.53.0
+
--- /dev/null
+From 1b11dcb8a320b9256b87cc7ba103e0642aa397da Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 1 Aug 2026 00:09:21 +0800
+Subject: bpf: Fix netns reference imbalance in conntrack kfuncs
+
+From: Chengfeng Ye <nicoyip.dev@gmail.com>
+
+[ Upstream commit fdeba03fea78407a8c52faa99177c9f7f29f90eb ]
+
+The opts argument of the BPF conntrack kfuncs can point to a shared
+map value. __bpf_nf_ct_lookup() and __bpf_nf_ct_alloc_entry() read
+opts->netns_id separately when acquiring and releasing the network
+namespace reference.
+
+The reference imbalance can occur as follows:
+
+ CPU 0 CPU 1
+ read opts->netns_id (-1)
+ skip get_net_ns_by_id()
+ write opts->netns_id (id)
+ read opts->netns_id (id)
+ put_net(net) /* no matching get */
+
+The reverse transition leaks the reference. Repeating the unmatched put
+can destroy a live namespace and crash later users.
+
+The kernel reported:
+
+ Oops: general protection fault, probably for non-canonical address
+ KASAN: null-ptr-deref in range [0x00000000000000e8-0x00000000000000ef]
+ RIP: 0010:bpf_prog_test_run_xdp+0x52c/0x1700
+ Call Trace:
+ __sys_bpf+0x1662/0x50c0
+ __x64_sys_bpf+0x73/0xb0
+ do_syscall_64+0xf9/0x540
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+ Kernel panic - not syncing: Fatal exception
+
+Snapshot every input field of opts with READ_ONCE() before validating or
+using it. The netns_id snapshot keeps the namespace get/put pair
+balanced, while the other snapshots keep the remaining options from
+changing partway through an invocation. The individual reads can still
+observe an inconsistent combination during a concurrent update, but each
+selected field value remains stable for that invocation.
+
+Fixes: aed8ee7feb44 ("net: netfilter: Deduplicate code in bpf_{xdp,skb}_ct_lookup")
+Fixes: d7e79c97c00c ("net: netfilter: Add kfuncs to allocate and insert CT")
+Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
+Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
+Link: https://lore.kernel.org/bpf/20260731160921.3245840-1-nicoyip.dev@gmail.com
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_bpf.c | 72 +++++++++++++++++++++-----------
+ 1 file changed, 48 insertions(+), 24 deletions(-)
+
+diff --git a/net/netfilter/nf_conntrack_bpf.c b/net/netfilter/nf_conntrack_bpf.c
+index f98d1d4b42c3d..c2df7c9482812 100644
+--- a/net/netfilter/nf_conntrack_bpf.c
++++ b/net/netfilter/nf_conntrack_bpf.c
+@@ -122,42 +122,54 @@ __bpf_nf_ct_alloc_entry(struct net *net, struct bpf_sock_tuple *bpf_tuple,
+ struct nf_conntrack_tuple otuple, rtuple;
+ struct nf_conntrack_zone ct_zone;
+ struct nf_conn *ct;
++ u8 ct_zone_dir = 0;
++ u16 ct_zone_id;
++ s32 netns_id;
++ u8 l4proto;
+ int err;
+
+ if (!(opts_len == NF_BPF_CT_OPTS_SZ || opts_len == 12))
+ return ERR_PTR(-EINVAL);
++
++ netns_id = READ_ONCE(opts->netns_id);
++ l4proto = READ_ONCE(opts->l4proto);
++ ct_zone_id = READ_ONCE(opts->ct_zone_id);
+ if (opts_len == NF_BPF_CT_OPTS_SZ) {
+- if (opts->reserved[0] || opts->reserved[1] || opts->reserved[2])
++ ct_zone_dir = READ_ONCE(opts->ct_zone_dir);
++ if (READ_ONCE(opts->reserved[0]) ||
++ READ_ONCE(opts->reserved[1]) ||
++ READ_ONCE(opts->reserved[2]))
+ return ERR_PTR(-EINVAL);
+ } else {
+- if (opts->ct_zone_id)
++ if (ct_zone_id)
+ return ERR_PTR(-EINVAL);
+ }
+
+- if (unlikely(opts->netns_id < BPF_F_CURRENT_NETNS))
++ if (unlikely(netns_id < BPF_F_CURRENT_NETNS))
+ return ERR_PTR(-EINVAL);
+
+- err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto,
++ err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, l4proto,
+ IP_CT_DIR_ORIGINAL, &otuple);
+ if (err < 0)
+ return ERR_PTR(err);
+
+- err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto,
++ err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, l4proto,
+ IP_CT_DIR_REPLY, &rtuple);
+ if (err < 0)
+ return ERR_PTR(err);
+
+- if (opts->netns_id >= 0) {
+- net = get_net_ns_by_id(net, opts->netns_id);
++ if (netns_id >= 0) {
++ net = get_net_ns_by_id(net, netns_id);
+ if (unlikely(!net))
+ return ERR_PTR(-ENONET);
+ }
+
+ if (opts_len == NF_BPF_CT_OPTS_SZ) {
+- if (opts->ct_zone_dir == 0)
+- opts->ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;
+- nf_ct_zone_init(&ct_zone,
+- opts->ct_zone_id, opts->ct_zone_dir, 0);
++ if (ct_zone_dir == 0) {
++ ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;
++ opts->ct_zone_dir = ct_zone_dir;
++ }
++ nf_ct_zone_init(&ct_zone, ct_zone_id, ct_zone_dir, 0);
+ } else {
+ ct_zone = nf_ct_zone_dflt;
+ }
+@@ -171,7 +183,7 @@ __bpf_nf_ct_alloc_entry(struct net *net, struct bpf_sock_tuple *bpf_tuple,
+ __nf_ct_set_timeout(ct, timeout * HZ);
+
+ out:
+- if (opts->netns_id >= 0)
++ if (netns_id >= 0)
+ put_net(net);
+
+ return ct;
+@@ -186,46 +198,58 @@ static struct nf_conn *__bpf_nf_ct_lookup(struct net *net,
+ struct nf_conntrack_tuple tuple;
+ struct nf_conntrack_zone ct_zone;
+ struct nf_conn *ct;
++ u8 ct_zone_dir = 0;
++ u16 ct_zone_id;
++ s32 netns_id;
++ u8 l4proto;
+ int err;
+
+ if (!opts || !bpf_tuple)
+ return ERR_PTR(-EINVAL);
+ if (!(opts_len == NF_BPF_CT_OPTS_SZ || opts_len == 12))
+ return ERR_PTR(-EINVAL);
++
++ netns_id = READ_ONCE(opts->netns_id);
++ l4proto = READ_ONCE(opts->l4proto);
++ ct_zone_id = READ_ONCE(opts->ct_zone_id);
+ if (opts_len == NF_BPF_CT_OPTS_SZ) {
+- if (opts->reserved[0] || opts->reserved[1] || opts->reserved[2])
++ ct_zone_dir = READ_ONCE(opts->ct_zone_dir);
++ if (READ_ONCE(opts->reserved[0]) ||
++ READ_ONCE(opts->reserved[1]) ||
++ READ_ONCE(opts->reserved[2]))
+ return ERR_PTR(-EINVAL);
+ } else {
+- if (opts->ct_zone_id)
++ if (ct_zone_id)
+ return ERR_PTR(-EINVAL);
+ }
+- if (unlikely(opts->l4proto != IPPROTO_TCP && opts->l4proto != IPPROTO_UDP))
++ if (unlikely(l4proto != IPPROTO_TCP && l4proto != IPPROTO_UDP))
+ return ERR_PTR(-EPROTO);
+- if (unlikely(opts->netns_id < BPF_F_CURRENT_NETNS))
++ if (unlikely(netns_id < BPF_F_CURRENT_NETNS))
+ return ERR_PTR(-EINVAL);
+
+- err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto,
++ err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, l4proto,
+ IP_CT_DIR_ORIGINAL, &tuple);
+ if (err < 0)
+ return ERR_PTR(err);
+
+- if (opts->netns_id >= 0) {
+- net = get_net_ns_by_id(net, opts->netns_id);
++ if (netns_id >= 0) {
++ net = get_net_ns_by_id(net, netns_id);
+ if (unlikely(!net))
+ return ERR_PTR(-ENONET);
+ }
+
+ if (opts_len == NF_BPF_CT_OPTS_SZ) {
+- if (opts->ct_zone_dir == 0)
+- opts->ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;
+- nf_ct_zone_init(&ct_zone,
+- opts->ct_zone_id, opts->ct_zone_dir, 0);
++ if (ct_zone_dir == 0) {
++ ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;
++ opts->ct_zone_dir = ct_zone_dir;
++ }
++ nf_ct_zone_init(&ct_zone, ct_zone_id, ct_zone_dir, 0);
+ } else {
+ ct_zone = nf_ct_zone_dflt;
+ }
+
+ hash = nf_conntrack_find_get(net, &ct_zone, &tuple);
+- if (opts->netns_id >= 0)
++ if (netns_id >= 0)
+ put_net(net);
+ if (!hash)
+ return ERR_PTR(-ENOENT);
+--
+2.53.0
+
--- /dev/null
+From 5163f7ec698d791ab29f954522bf13e93fb6c8ac Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:18:28 +0000
+Subject: bpf: Preserve pointer state for commuted arithmetic
+
+From: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+
+[ Upstream commit a4c6f804b44c5c790269b25e0e61cf4e9f117c86 ]
+
+When scalar += pointer is handled in adjust_ptr_min_max_vals(), the
+destination register inherits the pointer state from the source pointer.
+Copying only selected fields is fragile because pointer provenance is
+tracked by several bpf_reg_state fields.
+
+Use the caller's temporary offset register to preserve the scalar operand
+while replacing the destination with the full pointer state. This preserves
+the frame number for PTR_TO_STACK registers and keeps parent identity
+fields consistent.
+
+Fixes: f4d7e40a5b71 ("bpf: introduce function calls (verification)")
+Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+Tested-by: Daniel Wade <danjwade95@gmail.com>
+Acked-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-2-8ee297e2346b@mails.tsinghua.edu.cn
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 523f00e609e2b..ab88988d483d2 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -13837,11 +13837,12 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ return -EACCES;
+ }
+
+- /* In case of 'scalar += pointer', dst_reg inherits pointer type and id.
+- * The id may be overwritten later if we create a new variable offset.
++ /* For 'scalar += pointer', dst_reg inherits the complete pointer
++ * register state. Individual fields may be adjusted later by pointer
++ * arithmetic. Callers guarantee that below does not overwrite off_reg.
+ */
+- dst_reg->type = ptr_reg->type;
+- dst_reg->id = ptr_reg->id;
++ if (dst_reg != ptr_reg)
++ *dst_reg = *ptr_reg;
+
+ if (!check_reg_sane_offset_scalar(env, off_reg, ptr_reg->type) ||
+ !check_reg_sane_offset_ptr(env, ptr_reg, ptr_reg->type))
+@@ -13893,7 +13894,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ }
+ break;
+ case BPF_SUB:
+- if (dst_reg == off_reg) {
++ if (dst_reg != ptr_reg) {
+ /* scalar -= pointer. Creates an unknown scalar */
+ verbose(env, "R%d tried to subtract pointer from scalar\n",
+ dst);
+@@ -15137,8 +15138,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
+ err = mark_chain_precision(env, insn->dst_reg);
+ if (err)
+ return err;
+- return adjust_ptr_min_max_vals(env, insn,
+- src_reg, dst_reg);
++ off_reg = *dst_reg;
++ return adjust_ptr_min_max_vals(env, insn, src_reg, &off_reg);
+ }
+ } else if (ptr_reg) {
+ /* pointer += scalar */
+--
+2.53.0
+
--- /dev/null
+From 2027d045fd3797c2842e48603b1cbb20f9a9d295 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:18:29 +0000
+Subject: bpf: Propagate untrusted pointer state in commuted arithmetic
+
+From: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+
+[ Upstream commit cdf19b1b3c01791de074ce282089131026f52261 ]
+
+The untrusted PTR_TO_MEM early return skips pointer offset tracking
+because accesses go through probe-read handling. Moving it after full
+pointer-state propagation ensures scalar += untrusted_pointer leaves the
+destination as PTR_TO_MEM instead of an unrelated scalar.
+
+Fixes: f2362a57aeff ("bpf: allow void* cast using bpf_rdonly_cast()")
+Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
+Tested-by: Daniel Wade <danjwade95@gmail.com>
+Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-3-8ee297e2346b@mails.tsinghua.edu.cn
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index ab88988d483d2..5bad71f003dcc 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -13801,13 +13801,6 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ return -EACCES;
+ }
+
+- /*
+- * Accesses to untrusted PTR_TO_MEM are done through probe
+- * instructions, hence no need to track offsets.
+- */
+- if (base_type(ptr_reg->type) == PTR_TO_MEM && (ptr_reg->type & PTR_UNTRUSTED))
+- return 0;
+-
+ switch (base_type(ptr_reg->type)) {
+ case PTR_TO_CTX:
+ case PTR_TO_MAP_VALUE:
+@@ -13844,6 +13837,13 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
+ if (dst_reg != ptr_reg)
+ *dst_reg = *ptr_reg;
+
++ /*
++ * Accesses to untrusted PTR_TO_MEM are done through probe
++ * instructions, hence no need to track offsets.
++ */
++ if (base_type(ptr_reg->type) == PTR_TO_MEM && (ptr_reg->type & PTR_UNTRUSTED))
++ return 0;
++
+ if (!check_reg_sane_offset_scalar(env, off_reg, ptr_reg->type) ||
+ !check_reg_sane_offset_ptr(env, ptr_reg, ptr_reg->type))
+ return -EINVAL;
+--
+2.53.0
+
--- /dev/null
+From 7ad64f3a887853151edde8d3a317b75ff5a6f51f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 22:32:47 +0000
+Subject: bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()
+
+From: Jose Fernandez (Anthropic) <jose.fernandez@linux.dev>
+
+[ Upstream commit e5fd3f514e27db1f05fbd72ba615d74941e23c51 ]
+
+reqsk_queue_hash_req() publishes a TCP_NEW_SYN_RECV request_sock onto
+the ehash chain, drops the bucket lock, and only afterwards sets
+rsk_refcnt to 3.
+
+Lockless readers such as __inet_lookup_established() handle this with
+refcount_inc_not_zero(), but bpf_iter_tcp_established_batch() uses plain
+sock_hold() while holding the bucket lock, on the assumption that the
+lock guarantees sk_refcnt > 0. That assumption does not hold for
+request_sock:
+
+ CPU 0 CPU 1
+ ----- -----
+ tcp_conn_request()
+ reqsk_queue_hash_req()
+ inet_ehash_insert(req)
+ spin_lock(bucket)
+ __sk_nulls_add_node_rcu(req) // rsk_refcnt == 0
+ spin_unlock(bucket)
+ bpf_iter_tcp_established_batch()
+ spin_lock(bucket)
+ sock_hold(req) <-- addition on 0
+ spin_unlock(bucket)
+ refcount_set(&req->rsk_refcnt, 3) // clobbers saturated value
+
+which surfaces as:
+
+ refcount_t: addition on 0; use-after-free.
+ WARNING: lib/refcount.c:25 at refcount_warn_saturate+0x48/0x90, CPU#1
+ Call Trace:
+ bpf_iter_tcp_established_batch+0x14e/0x170
+ bpf_iter_tcp_batch+0x53/0x200
+ bpf_iter_tcp_seq_next+0x27/0x70
+ bpf_seq_read+0x107/0x410
+ vfs_read+0xb9/0x380
+
+The iterator's stolen reference is lost when the publishing CPU's
+refcount_set() overwrites the count, leaving the socket one reference
+short. When the last legitimate owner drops its reference the reqsk is
+freed while still reachable, leading to use-after-free.
+
+This reproduces in seconds with tcp_syncookies=0, a handful of threads
+doing connect()/close() to a local listener while others read an
+iter/tcp link in a tight loop.
+
+Use refcount_inc_not_zero() and skip the socket on failure. A skipped
+socket is still part of the bucket, so keep counting it in expected.
+The reallocations are sized from expected, and a request sock whose
+refcount gets published while the lock is held across the last realloc
+must already have room.
+
+A skipped socket is counted in expected but never batched, so end_sk
+can be short of expected on a batch that is actually complete. Decide
+completeness by whether the walk left any socket behind instead. The
+WARN after the locked realloc checks the same, replacing an
+end_sk == expected check that could not hold on that path since
+commit cdec67a489d4 ("bpf: tcp: Make sure iter->batch always
+contains a full bucket snapshot").
+
+If every matching socket in a bucket is mid-init (refcount 0), end_sk
+stays 0. Advance to the next bucket rather than returning a batch entry
+that was never filled this round.
+
+Fixes: 04c7820b776f ("bpf: tcp: Bpf iter batching and lock_sock")
+Assisted-by: Claude:unspecified
+Signed-off-by: Jose Fernandez (Anthropic) <jose.fernandez@linux.dev>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Link: https://lore.kernel.org/bpf/20260730-bpf-iter-tcp-refcnt-v3-1-754b9c8a6717@linux.dev
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 43 ++++++++++++++++++++++++-------------------
+ 1 file changed, 24 insertions(+), 19 deletions(-)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index ce572025eeeba..4b59d258c2667 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -3079,24 +3079,24 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq,
+ {
+ struct bpf_tcp_iter_state *iter = seq->private;
+ struct hlist_nulls_node *node;
+- unsigned int expected = 1;
+- struct sock *sk;
+-
+- sock_hold(*start_sk);
+- iter->batch[iter->end_sk++].sk = *start_sk;
++ struct sock *sk = *start_sk;
++ unsigned int expected = 0;
+
+- sk = sk_nulls_next(*start_sk);
+ *start_sk = NULL;
+ sk_nulls_for_each_from(sk, node) {
+- if (seq_sk_match(seq, sk)) {
+- if (iter->end_sk < iter->max_sk) {
+- sock_hold(sk);
+- iter->batch[iter->end_sk++].sk = sk;
+- } else if (!*start_sk) {
+- /* Remember where we left off. */
+- *start_sk = sk;
+- }
+- expected++;
++ if (!seq_sk_match(seq, sk))
++ continue;
++ expected++;
++ if (iter->end_sk < iter->max_sk) {
++ /* reqsk_queue_hash_req() inserts with sk_refcnt == 0
++ * and refcount_set()s it after the bucket lock drops.
++ */
++ if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
++ continue;
++ iter->batch[iter->end_sk++].sk = sk;
++ } else if (!*start_sk) {
++ /* Remember where we left off. */
++ *start_sk = sk;
+ }
+ }
+
+@@ -3134,12 +3134,13 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ struct sock *sk;
+ int err;
+
++again:
+ sk = bpf_iter_tcp_resume(seq);
+ if (!sk)
+ return NULL; /* Done */
+
+ expected = bpf_iter_fill_batch(seq, &sk);
+- if (likely(iter->end_sk == expected))
++ if (likely(!sk))
+ goto done;
+
+ /* Batch size was too small. */
+@@ -3158,7 +3159,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ return NULL; /* Done */
+
+ expected = bpf_iter_fill_batch(seq, &sk);
+- if (likely(iter->end_sk == expected))
++ if (likely(!sk))
+ goto done;
+
+ /* Batch size was still too small. Hold onto the lock while we try
+@@ -3171,10 +3172,14 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq)
+ return ERR_PTR(err);
+ }
+
+- expected = bpf_iter_fill_batch(seq, &sk);
+- WARN_ON_ONCE(iter->end_sk != expected);
++ bpf_iter_fill_batch(seq, &sk);
++ WARN_ON_ONCE(sk);
+ done:
+ bpf_iter_tcp_unlock_bucket(seq);
++ if (unlikely(!iter->end_sk)) {
++ ++iter->state.bucket;
++ goto again;
++ }
+ return iter->batch[0].sk;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 57fed36c720dac94ba6dde7a0adf00a0d2babf52 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 16:37:39 +0930
+Subject: btrfs: disable bs > ps support if no transparent hugepage support
+
+From: Qu Wenruo <wqu@suse.com>
+
+[ Upstream commit 4c375ac546ea667e619ab77d34cca6edcab7c448 ]
+
+Btrfs relies on mapping_set_folio_order_range() to set the minimal
+folio order for all its data inodes, but that function will be no-op if
+transparent hugepage is not enabled.
+
+Guard the bs > ps support behind CONFIG_TRANSPARENT_HUGEPAGE, just like
+all other filesystems.
+
+Fixes: 98077f7f2180 ("btrfs: enable experimental bs > ps support")
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/Kconfig | 3 ++-
+ fs/btrfs/fs.c | 12 ++++++++++--
+ 2 files changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig
+index 55eba4f1b6c79..e1931281dddd0 100644
+--- a/fs/btrfs/Kconfig
++++ b/fs/btrfs/Kconfig
+@@ -110,7 +110,8 @@ config BTRFS_EXPERIMENTAL
+
+ - extent tree v2 - complex rework of extent tracking
+
+- - block size > page size support
++ - block size > page size support - needs transparent huge page and
++ non-HIGHMEM system
+
+ - asynchronous checksum generation for data writes
+
+diff --git a/fs/btrfs/fs.c b/fs/btrfs/fs.c
+index 14d83565cdee1..dcf12979af33c 100644
+--- a/fs/btrfs/fs.c
++++ b/fs/btrfs/fs.c
+@@ -166,9 +166,17 @@ bool __attribute_const__ btrfs_supported_blocksize(u32 blocksize)
+ *
+ * Considering HIGHMEM is such a pain to deal with and it's going
+ * to be deprecated eventually, just reject HIGHMEM && bs > ps cases.
++ *
++ * Finally, for bs > ps cases, we need to set the minimal folio order,
++ * which requires transparent hugepage.
+ */
+- if (IS_ENABLED(CONFIG_HIGHMEM) && blocksize > PAGE_SIZE)
+- return false;
++ if (blocksize > PAGE_SIZE) {
++ if (IS_ENABLED(CONFIG_HIGHMEM))
++ return false;
++
++ if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
++ return false;
++ }
+ return true;
+ #endif
+ return false;
+--
+2.53.0
+
--- /dev/null
+From b842fef77217aeecac1baa74ea1bccd2a3aff47d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 14:53:52 +0300
+Subject: btrfs: fix memory leak in btrfs_do_encoded_write()
+
+From: Dmitry Antipov <dmantipov@yandex.ru>
+
+[ Upstream commit d2a4e4e626b2f4670b69b430c357f03f53eb6632 ]
+
+Local fuzzing of 6.12.94 has found the following memory leak:
+
+Unreferenced object 0xffff888018050a80 (size 64):
+ comm "syz.0.17", pid 10297, jiffies 4294953601
+ hex dump (first 32 bytes):
+ 00 10 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................
+ 10 0a 05 18 80 88 ff ff 10 0a 05 18 80 88 ff ff ................
+ backtrace (crc a8a6fc29):
+ kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
+ slab_post_alloc_hook mm/slub.c:4152 [inline]
+ slab_alloc_node mm/slub.c:4197 [inline]
+ __kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358
+ kmalloc_noprof include/linux/slab.h:878 [inline]
+ extent_changeset_alloc fs/btrfs/extent_io.h:207 [inline]
+ qgroup_reserve_data+0x1c5/0x7d0 fs/btrfs/qgroup.c:4305
+ btrfs_qgroup_reserve_data+0x2e/0xb0 fs/btrfs/qgroup.c:4355
+ btrfs_do_encoded_write+0x92e/0x1040 fs/btrfs/inode.c:9746
+ btrfs_encoded_write fs/btrfs/file.c:1482 [inline]
+ btrfs_do_write_iter+0x280/0x610 fs/btrfs/file.c:1507
+ btrfs_ioctl_encoded_write+0x3d6/0x490 fs/btrfs/ioctl.c:4738
+ btrfs_ioctl+0x6f9/0xc90 fs/btrfs/ioctl.c:-1
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:906 [inline]
+ __se_sys_ioctl+0xf9/0x170 fs/ioctl.c:892
+ do_syscall_x64 arch/x86/entry/common.c:47 [inline]
+ do_syscall_64+0xbe/0x1a0 arch/x86/entry/common.c:78
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Unreferenced object 0xffff888018050a00 (size 64):
+ comm "syz.0.17", pid 10297, jiffies 4294953601
+ hex dump (first 32 bytes):
+ 00 00 00 00 00 00 00 00 ff 0f 00 00 00 00 00 00 ................
+ 90 0a 05 18 80 88 ff ff 90 0a 05 18 80 88 ff ff ................
+ backtrace (crc cb5c9580):
+ kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline]
+ slab_post_alloc_hook mm/slub.c:4152 [inline]
+ slab_alloc_node mm/slub.c:4197 [inline]
+ __kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358
+ kmalloc_noprof include/linux/slab.h:878 [inline]
+ kzalloc_noprof include/linux/slab.h:1014 [inline]
+ ulist_prealloc+0x9c/0x110 fs/btrfs/ulist.c:114
+ extent_changeset_prealloc fs/btrfs/extent_io.h:217 [inline]
+ __set_extent_bit+0x16b/0x1a70 fs/btrfs/extent-io-tree.c:1086
+ set_record_extent_bits+0x50/0x90 fs/btrfs/extent-io-tree.c:1821
+ qgroup_reserve_data+0x274/0x7d0 fs/btrfs/qgroup.c:4312
+ btrfs_qgroup_reserve_data+0x2e/0xb0 fs/btrfs/qgroup.c:4355
+ btrfs_do_encoded_write+0x92e/0x1040 fs/btrfs/inode.c:9746
+ btrfs_encoded_write fs/btrfs/file.c:1482 [inline]
+ btrfs_do_write_iter+0x280/0x610 fs/btrfs/file.c:1507
+ btrfs_ioctl_encoded_write+0x3d6/0x490 fs/btrfs/ioctl.c:4738
+ btrfs_ioctl+0x6f9/0xc90 fs/btrfs/ioctl.c:-1
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:906 [inline]
+ __se_sys_ioctl+0xf9/0x170 fs/ioctl.c:892
+ do_syscall_x64 arch/x86/entry/common.c:47 [inline]
+ do_syscall_64+0xbe/0x1a0 arch/x86/entry/common.c:78
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Fix this by freeing an extent changeset before returning from
+btrfs_do_encoded_write().
+
+Fixes: 7c0c7269f7b5 ("btrfs: add BTRFS_IOC_ENCODED_WRITE")
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/inode.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index dc5148f176e77..a953d47eb2dd5 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -10193,6 +10193,7 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
+ if (cb)
+ cleanup_compressed_bio(cb);
+ out:
++ extent_changeset_free(data_reserved);
+ if (ret >= 0)
+ iocb->ki_pos += encoded->len;
+ return ret;
+--
+2.53.0
+
--- /dev/null
+From d4bccdeceb398dc1b1b18d5db2e7b790ecba3adb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 10:14:49 +0930
+Subject: btrfs: initialize inode mapping flags for cached inodes
+
+From: Qu Wenruo <wqu@suse.com>
+
+[ Upstream commit 0ef349734a93227b45f65fc50a3311d1cc5f03e9 ]
+
+[BUG]
+When running generic/795 with 8K block size, 4K page size, the test
+always fails, triggering some ASSERT()s related to folio size:
+
+ 795 (241074): drop_caches: 3
+ assertion failed: IS_ALIGNED(start, blocksize) && IS_ALIGNED(end + 1, blocksize), in extent_io.c:1404 (blocksize=8192 root=262 ino=258 start=16826368 end=16830463 mapping min order=0)
+ ------------[ cut here ]------------
+ kernel BUG at extent_io.c:1404!
+ Oops: invalid opcode: 0000 [#1] SMP
+ CPU: 8 UID: 0 PID: 241105 Comm: fsstress Tainted: G OE 7.2.0-rc5-custom+ #442 PREEMPT(full) f4bfb352566f3949f29c233ce6f735050a03b245
+ Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE
+ Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS unknown 02/02/2022
+ RIP: 0010:assert_folio_range.cold+0x3d/0x3f [btrfs]
+ Call Trace:
+ <TASK>
+ btrfs_read_folio+0x9e/0x170 [btrfs 4cd1dd93b341b8ef766643f9512f4a86259567a3]
+ prepare_one_folio.constprop.0+0x104/0x2a0 [btrfs 4cd1dd93b341b8ef766643f9512f4a86259567a3]
+ btrfs_buffered_write+0x285/0xa50 [btrfs 4cd1dd93b341b8ef766643f9512f4a86259567a3]
+ btrfs_do_write_iter+0x1aa/0x210 [btrfs 4cd1dd93b341b8ef766643f9512f4a86259567a3]
+ iter_file_splice_write+0x31a/0x540
+ direct_splice_actor+0x53/0x170
+ splice_direct_to_actor+0xe9/0x240
+ do_splice_direct+0x76/0xb0
+ vfs_copy_file_range+0x1fd/0x630
+ __x64_sys_copy_file_range+0xf9/0x220
+ do_syscall_64+0xe1/0x790
+ entry_SYSCALL_64_after_hwframe+0x4b/0x53
+ </TASK>
+ ---[ end trace 0000000000000000 ]---
+
+The ASSERT() itself is added by a later patch.
+The crash is triggered with that new debug patch, and without this fix.
+
+[CAUSE]
+In the above case, the start 16826368 is properly 8K aligned, but the
+end (16830463 + 1) is not 8K aligned.
+Furthermore the mapping's minimal folio order is 0, not the expected 1
+for 8K block size with 4K page size.
+
+So this means some inodes do not have btrfs_set_inode_mapping_order()
+called on it.
+
+The missing btrfs_set_inode_mapping_order() call happens for cached
+inodes, through the following events:
+
+- btrfs_create_new_inode() called for inode X
+ Which properly sets minimal folio order for the VFS inode.
+
+- btrfs_update_inode() called for inode X
+ Which calls btrfs_delayed_update_inode() to create a delayed_node
+ into root->delayed_nodes xarray.
+
+- Drop cache/memory pressure, evicting in-memory inode X
+ Which evicted the inode X, but delayed_node is still in
+ root->delayed_nodes for future reuse.
+
+- btrfs_iget() for inode X called again
+
+ btrfs_iget()
+ |- btrfs_iget_locked()
+ | |- iget5_locked_rcu()
+ | Which creates a new vfs_inode for btrfs, whose mapping still
+ | has the minimal order as 0.
+ |
+ |- btrfs_read_locked_inode()
+ |- btrfs_fill_inode()
+ | |- btrfs_get_delayed_node()
+ | Which found out the previous node, and use that delayed
+ | node to initialize the new inode.
+ |
+ |- filled = true;
+ |- if (filled) goto cache_index;
+ Which skips the btrfs_update_inode_mapping_flags() and
+ btrfs_set_inode_mapping_order() calls.
+ So the inode still has minimal folio order set as 0, not
+ the required 1.
+
+Thus later page cache read will get a folio whose size is smaller than
+block size, as the mapping has its minimal folio order set as 0 not 1,
+then trigger the ASSERT().
+
+[FIX]
+Move the btrfs_update_inode_mapping_flags() and
+btrfs_set_inode_mapping_order() calls under cache_index label,
+so that the mapping flags and minimal folio order is always set
+no matter if we have a cached inode.
+
+Assisted-by: LLM (analysis)
+Fixes: ecde48a1a6b3 ("btrfs: expose per-inode stable writes flag")
+Fixes: cc38d178ff33 ("btrfs: enable large data folio support under CONFIG_BTRFS_EXPERIMENTAL")
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/inode.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index a953d47eb2dd5..1271be0fbfcfa 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -4167,10 +4167,11 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path
+
+ btrfs_inode_split_flags(btrfs_inode_flags(leaf, inode_item),
+ &inode->flags, &inode->ro_flags);
++
++cache_index:
+ btrfs_update_inode_mapping_flags(inode);
+ btrfs_set_inode_mapping_order(inode);
+
+-cache_index:
+ /*
+ * If we were modified in the current generation and evicted from memory
+ * and then re-read we need to do a full sync since we don't have any
+--
+2.53.0
+
--- /dev/null
+From 735303f7de97f12cab6ab47f21ae361672432c8d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 8 Jun 2026 08:23:49 +0930
+Subject: btrfs: lzo: add error message for invalid headers
+
+From: Qu Wenruo <wqu@suse.com>
+
+[ Upstream commit 1cb15b153c636096740519f62040ec6dc3e50aef ]
+
+Inside btrfs we always pair -EUCLEAN error with an error message to
+indicate which data is corrupted.
+
+However there are 3 cases inside lzo decompression where there is no
+error message for corrupted headers.
+
+Add those missing error messages to show exactly where the corruption
+is.
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Stable-dep-of: 0fa78ef637de ("btrfs: lzo: reject inline extents without valid headers")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/lzo.c | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c
+index 6e4aa22853aba..1531adb117d15 100644
+--- a/fs/btrfs/lzo.c
++++ b/fs/btrfs/lzo.c
+@@ -552,17 +552,26 @@ int lzo_decompress(struct list_head *ws, const u8 *data_in,
+ size_t max_segment_len = workspace_buf_length(fs_info);
+ int ret;
+
+- if (unlikely(srclen < LZO_LEN || srclen > max_segment_len + LZO_LEN * 2))
++ if (unlikely(srclen < LZO_LEN || srclen > max_segment_len + LZO_LEN * 2)) {
++ btrfs_err(fs_info, "invalid lzo header length, has %zu expect (%u, %zu)",
++ srclen, LZO_LEN, max_segment_len + LZO_LEN * 2);
+ return -EUCLEAN;
++ }
+
+ in_len = get_unaligned_le32(data_in);
+- if (unlikely(in_len != srclen))
++ if (unlikely(in_len != srclen)) {
++ btrfs_err(fs_info, "invalid lzo header length, has %zu expect %zu",
++ in_len, srclen);
+ return -EUCLEAN;
++ }
+ data_in += LZO_LEN;
+
+ in_len = get_unaligned_le32(data_in);
+- if (unlikely(in_len != srclen - LZO_LEN * 2))
++ if (unlikely(in_len != srclen - LZO_LEN * 2)) {
++ btrfs_err(fs_info, "invalid lzo segment length, has %zu expect %zu",
++ in_len, srclen - LZO_LEN * 2);
+ return -EUCLEAN;
++ }
+ data_in += LZO_LEN;
+
+ out_len = sectorsize;
+--
+2.53.0
+
--- /dev/null
+From d82242b80c354beb82b569d5e1ec89bd20ed48a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Jul 2026 09:05:14 +0000
+Subject: btrfs: lzo: reject inline extents without valid headers
+
+From: David Lee <david.lee@trailofbits.com>
+
+[ Upstream commit 0fa78ef637deb5dbe341582f88553a4bce496de0 ]
+
+[BUG]
+For a crafted btrfs image, the following KASAN can be triggered when
+reading an inline lzo compressed file extent:
+
+ BUG: KASAN: slab-out-of-bounds in lzo_decompress+0x57d/0x700
+ Read of size 4 at addr ffff888006f2e644 by task btrfs_lzo_inlin/77
+
+ Call Trace:
+ <TASK>
+ dump_stack_lvl+0x5b/0x70
+ print_report+0xd1/0x610
+ kasan_report+0xe0/0x110
+ __asan_report_load_n_noabort+0x13/0x20
+ lzo_decompress+0x57d/0x700
+ btrfs_decompress+0x140/0x1c0
+ uncompress_inline+0x147/0x1b0
+ btrfs_get_extent+0xb23/0x10a0
+ btrfs_do_readpage.constprop.0+0x538/0x1ac0
+ btrfs_readahead+0x32f/0x5f0
+ read_pages+0x16f/0x850
+ page_cache_ra_unbounded+0x296/0x490
+ do_page_cache_ra+0xd9/0x130
+ page_cache_sync_ra+0x3ee/0x6f0
+ filemap_get_pages+0x306/0x15c0
+ filemap_read+0x329/0xd00
+ btrfs_file_read_iter+0x1f8/0x2b0
+ vfs_read+0x4ef/0x720
+ ksys_read+0xf8/0x1d0
+ __x64_sys_read+0x71/0xb0
+ x64_sys_call+0x1ab0/0x1b70
+ do_syscall_64+0x61/0x470
+ entry_SYSCALL_64_after_hwframe+0x4b/0x53
+ </TASK>
+
+[CAUSE]
+For an inline lzo compressed file extent, there should always be one lzo
+header, recording the total length of the compressed data, followed by
+one segment header, recording the compressed lzo payload.
+
+But if a crafted inline lzo compressed file extent contains only an lzo
+header, without the segment header or payload, lzo_decompress() will
+still try to read the segment header, causing a read beyond the item
+boundary.
+
+Furthermore if the inline lzo compressed file extent is the first item
+of the leaf, it will be at the extent buffer boundary. The above
+out-of-boundary read will go beyond the extent buffer boundary,
+triggering the above KASAN report.
+
+[FIX]
+Validate the total length of the inlined lzo compressed file extent, to
+make sure there is at least one LZO header and one segment header, and a
+non-zero payload.
+
+Fixes: a6fa6fae40ec ("btrfs: Add lzo compression support")
+Assisted-by: Codex:gpt-5.5
+Signed-off-by: David Lee <david.lee@trailofbits.com>
+[ Rework the commit message to remove slop ]
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/lzo.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c
+index 1531adb117d15..2f0996692da05 100644
+--- a/fs/btrfs/lzo.c
++++ b/fs/btrfs/lzo.c
+@@ -552,9 +552,10 @@ int lzo_decompress(struct list_head *ws, const u8 *data_in,
+ size_t max_segment_len = workspace_buf_length(fs_info);
+ int ret;
+
+- if (unlikely(srclen < LZO_LEN || srclen > max_segment_len + LZO_LEN * 2)) {
++ if (unlikely(srclen <= LZO_LEN * 2 ||
++ srclen > max_segment_len + LZO_LEN * 2)) {
+ btrfs_err(fs_info, "invalid lzo header length, has %zu expect (%u, %zu)",
+- srclen, LZO_LEN, max_segment_len + LZO_LEN * 2);
++ srclen, LZO_LEN * 2, max_segment_len + LZO_LEN * 2);
+ return -EUCLEAN;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 3d8483065b9a103c8f10a57dd8638ce0f29b1dba Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Apr 2026 10:20:25 +0930
+Subject: btrfs: move large data folios out of experimental features
+
+From: Qu Wenruo <wqu@suse.com>
+
+[ Upstream commit 9bce95edb1b4d2802de9273b5170bfcff3090d24 ]
+
+This feature was introduced in v6.17 under experimental, and we had
+several small bugs related to or exposed by that:
+
+ e9e3b22ddfa7 ("btrfs: fix beyond-EOF write handling")
+ 18de34daa7c6 ("btrfs: truncate ordered extent when skipping writeback past i_size")
+
+Otherwise, the feature has been frequently tested by btrfs developers.
+
+The latest fix only arrived in v6.19. After three releases, I think it's
+time to move this feature out of experimental.
+
+And since we're here, also remove the comment about the bitmap size
+limit, which is no longer relevant in the context. It will soon be
+outdated for the incoming huge folio support.
+
+Reviewed-by: Neal Gompa <neal@gompa.dev>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Stable-dep-of: 4c375ac546ea ("btrfs: disable bs > ps support if no transparent hugepage support")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/Kconfig | 2 +-
+ fs/btrfs/btrfs_inode.h | 3 ---
+ fs/btrfs/defrag.c | 17 -----------------
+ 3 files changed, 1 insertion(+), 21 deletions(-)
+
+diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig
+index 5e75438e0b738..55eba4f1b6c79 100644
+--- a/fs/btrfs/Kconfig
++++ b/fs/btrfs/Kconfig
+@@ -110,7 +110,7 @@ config BTRFS_EXPERIMENTAL
+
+ - extent tree v2 - complex rework of extent tracking
+
+- - large folio and block size (> page size) support
++ - block size > page size support
+
+ - asynchronous checksum generation for data writes
+
+diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
+index beb75f152d5cd..8a802e3675cd8 100644
+--- a/fs/btrfs/btrfs_inode.h
++++ b/fs/btrfs/btrfs_inode.h
+@@ -533,12 +533,9 @@ static inline void btrfs_set_inode_mapping_order(struct btrfs_inode *inode)
+ /* Metadata inode should not reach here. */
+ ASSERT(is_data_inode(inode));
+
+- /* We only allow BITS_PER_LONGS blocks for each bitmap. */
+-#ifdef CONFIG_BTRFS_EXPERIMENTAL
+ mapping_set_folio_order_range(inode->vfs_inode.i_mapping,
+ inode->root->fs_info->block_min_order,
+ inode->root->fs_info->block_max_order);
+-#endif
+ }
+
+ void btrfs_calculate_block_csum_folio(struct btrfs_fs_info *fs_info,
+diff --git a/fs/btrfs/defrag.c b/fs/btrfs/defrag.c
+index 7e2db5d3a4d4c..9111308351f82 100644
+--- a/fs/btrfs/defrag.c
++++ b/fs/btrfs/defrag.c
+@@ -859,23 +859,6 @@ static struct folio *defrag_prepare_one_folio(struct btrfs_inode *inode, pgoff_t
+ if (IS_ERR(folio))
+ return folio;
+
+- /*
+- * Since we can defragment files opened read-only, we can encounter
+- * transparent huge pages here (see CONFIG_READ_ONLY_THP_FOR_FS).
+- *
+- * The IO for such large folios is not fully tested, thus return
+- * an error to reject such folios unless it's an experimental build.
+- *
+- * Filesystem transparent huge pages are typically only used for
+- * executables that explicitly enable them, so this isn't very
+- * restrictive.
+- */
+- if (!IS_ENABLED(CONFIG_BTRFS_EXPERIMENTAL) && folio_test_large(folio)) {
+- folio_unlock(folio);
+- folio_put(folio);
+- return ERR_PTR(-ETXTBSY);
+- }
+-
+ ret = set_folio_extent_mapped(folio);
+ if (ret < 0) {
+ folio_unlock(folio);
+--
+2.53.0
+
--- /dev/null
+From 9b1857ea19a74ca7e4d9eaa93dd5ff57deec855b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jul 2026 04:29:10 +0000
+Subject: counter: microchip-tcb-capture: Fix DT channel validation
+
+From: Babanpreet Singh <bbnpreetsingh@gmail.com>
+
+[ Upstream commit f1a3a9946aab611dd2200c01ff122f64b033dad2 ]
+
+mchp_tc_probe() reads the devicetree "reg" cell - a u32, per the API
+contract of of_property_read_u32_index() - into a signed int, so the
+bounds check "channel > 2" fails to reject cell values at or above
+0x80000000: reinterpreted as a negative int, they compare below 2 and
+pass validation.
+
+A malformed devicetree can therefore drive a negative channel into the
+ATMEL_TC_REG() offset arithmetic, making the driver access syscon
+regmap offsets outside the TC block's register window, and into the
+"t%d_clk" clock-name formatting, where it truncates clk_name (sized
+for "t0_clk".."t2_clk").
+
+Declare channel as u32, matching the API contract; the unsigned
+comparison then rejects everything except channels 0..2. Adjust the
+format specifier to %u accordingly, which also resolves the W=1
+warning that exposed the gap:
+
+ microchip-tcb-capture.c:520:56: warning: '%d' directive output may
+ be truncated writing between 1 and 11 bytes into a region of size
+ 6 [-Wformat-truncation=]
+ note: directive argument in the range [-2147483648, 2]
+
+No behavior change for well-formed devicetrees: channels 0..2 take
+identical paths before and after.
+
+Fixes: 106b104137fd ("counter: Add microchip TCB capture counter")
+Assisted-by: Claude:claude-fable-5 [gcc W=1]
+Signed-off-by: Babanpreet Singh <bbnpreetsingh@gmail.com>
+Reviewed-by: Joshua Crofts <joshua.crofts1@gmail.com>
+Link: https://lore.kernel.org/r/20260714042910.7-1-bbnpreetsingh@gmail.com
+Signed-off-by: William Breathitt Gray <wbg@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/counter/microchip-tcb-capture.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/counter/microchip-tcb-capture.c b/drivers/counter/microchip-tcb-capture.c
+index 19d457ae4c3bb..e53a8390756b7 100644
+--- a/drivers/counter/microchip-tcb-capture.c
++++ b/drivers/counter/microchip-tcb-capture.c
+@@ -483,7 +483,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
+ char clk_name[7];
+ struct regmap *regmap;
+ struct clk *clk[3];
+- int channel;
++ u32 channel;
+ int ret, i;
+
+ counter = devm_counter_alloc(&pdev->dev, sizeof(*priv));
+@@ -517,7 +517,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
+
+ priv->channel[i] = channel;
+
+- snprintf(clk_name, sizeof(clk_name), "t%d_clk", channel);
++ snprintf(clk_name, sizeof(clk_name), "t%u_clk", channel);
+
+ clk[i] = of_clk_get_by_name(np->parent, clk_name);
+ if (IS_ERR(clk[i])) {
+--
+2.53.0
+
--- /dev/null
+From 3b56739cb890e2403f7c51cc9fe8522723f23d12 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 11:06:00 +0300
+Subject: devlink: fix net namespace reference leak in reload
+
+From: Or Har-Toov <ohartoov@nvidia.com>
+
+[ Upstream commit 1c4dac9bf1d2ac31da63b794bdec697777cbd0fd ]
+
+devlink_nl_reload_doit() calls devlink_netns_get(), which returns a net
+with a held reference. When the requested namespace differs from the
+current one and the reload action is not DRIVER_REINIT, the function
+returns -EOPNOTSUPP without releasing the reference. Add the missing
+put_net() on this error path.
+
+Fixes: 2edd92570441 ("devlink: don't allow to change net namespace for FW_ACTIVATE reload action")
+Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
+Reviewed-by: Jiri Pirko <jiri@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Reviewed-by: Antoine Tenart <atenart@kernel.org>
+Link: https://patch.msgid.link/20260729080600.2427721-1-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/devlink/dev.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/devlink/dev.c b/net/devlink/dev.c
+index 57b2b8f035436..fd5633fa88ecd 100644
+--- a/net/devlink/dev.c
++++ b/net/devlink/dev.c
+@@ -578,6 +578,7 @@ int devlink_nl_reload_doit(struct sk_buff *skb, struct genl_info *info)
+ action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) {
+ NL_SET_ERR_MSG_MOD(info->extack,
+ "Changing namespace is only supported for reinit action");
++ put_net(dest_net);
+ return -EOPNOTSUPP;
+ }
+ }
+--
+2.53.0
+
--- /dev/null
+From 0fee183f09573f4cc7ee0766e506ae38a1fee70e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jul 2026 10:38:06 +0800
+Subject: drm/bridge: ps8640: propagate AUX transfer register errors
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 20697ecb299cd77b4cf8b28f655e56606b0472d8 ]
+
+ps8640_aux_transfer_msg() programs the AUX address registers, starts the
+AUX transfer, waits for SWAUX_SEND to clear, and reads the AUX status
+register. Several of those regmap operations have return values, but the
+function only checks a stale ret after the status read.
+
+Propagate failures from the address write, transfer start, completion
+poll, and status read. This avoids returning a transfer length when the
+bridge register transaction or AUX completion wait failed.
+
+Fixes: 13afcdd7277e ("drm/bridge: parade-ps8640: Add support for AUX channel")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Link: https://patch.msgid.link/20260723103509.2-ps8640-v2-pengpeng@iscas.ac.cn
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/bridge/parade-ps8640.c | 27 ++++++++++++++++++++------
+ 1 file changed, 21 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
+index 825777a5758f6..db8e5889dc7f1 100644
+--- a/drivers/gpu/drm/bridge/parade-ps8640.c
++++ b/drivers/gpu/drm/bridge/parade-ps8640.c
+@@ -257,8 +257,14 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
+ addr_len[PAGE0_SWAUX_LENGTH - base] = (len == 0) ? SWAUX_NO_PAYLOAD :
+ ((len - 1) & SWAUX_LENGTH_MASK);
+
+- regmap_bulk_write(map, PAGE0_SWAUX_ADDR_7_0, addr_len,
+- ARRAY_SIZE(addr_len));
++ ret = regmap_bulk_write(map, PAGE0_SWAUX_ADDR_7_0, addr_len,
++ ARRAY_SIZE(addr_len));
++ if (ret) {
++ DRM_DEV_ERROR(dev,
++ "failed to write AUX address %#x, len %zu: %d\n",
++ msg->address, len, ret);
++ return ret;
++ }
+
+ if (len && (request == DP_AUX_NATIVE_WRITE ||
+ request == DP_AUX_I2C_WRITE)) {
+@@ -274,13 +280,22 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
+ }
+ }
+
+- regmap_write(map, PAGE0_SWAUX_CTRL, SWAUX_SEND);
++ ret = regmap_write(map, PAGE0_SWAUX_CTRL, SWAUX_SEND);
++ if (ret) {
++ DRM_DEV_ERROR(dev, "failed to start AUX transfer: %d\n", ret);
++ return ret;
++ }
+
+ /* Zero delay loop because i2c transactions are slow already */
+- regmap_read_poll_timeout(map, PAGE0_SWAUX_CTRL, data,
+- !(data & SWAUX_SEND), 0, 50 * 1000);
++ ret = regmap_read_poll_timeout(map, PAGE0_SWAUX_CTRL, data,
++ !(data & SWAUX_SEND), 0, 50 * 1000);
++ if (ret) {
++ DRM_DEV_ERROR(dev, "failed to complete AUX transfer: %d\n",
++ ret);
++ return ret;
++ }
+
+- regmap_read(map, PAGE0_SWAUX_STATUS, &data);
++ ret = regmap_read(map, PAGE0_SWAUX_STATUS, &data);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to read PAGE0_SWAUX_STATUS: %d\n",
+ ret);
+--
+2.53.0
+
--- /dev/null
+From 008c255d9804831110a18e6915fdd0450d17bf91 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Jun 2026 13:14:20 +0200
+Subject: drm/xe: Fix memory leak in exec_queue_set_hang_replay_state()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Michał Winiarski <michal.winiarski@intel.com>
+
+[ Upstream commit c5f500161709f27719701334190dff2325868ef0 ]
+
+The q->replay_state is blindly overwritten, which can potentially leak
+memory that was previously allocated by vmemdup_user().
+Return an error if q->replay_state is not empty.
+
+Discovered using AI-assisted static analysis confirmed by Intel Product
+Security.
+
+Reported-by: Martin Hodo <martin.hodo@intel.com>
+Fixes: 1026c1a73a96 ("drm/xe: Implement DRM_XE_EXEC_QUEUE_SET_HANG_REPLAY_STATE")
+Reviewed-by: Matthew Brost <matthew.brost@intel.com>
+Link: https://patch.msgid.link/20260624111421.1258364-1-michal.winiarski@intel.com
+Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
+(cherry picked from commit f6b6cc1118bdbc4265fa8b3bdf8565b26f13e56e)
+Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_exec_queue.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
+index 071b8c41df43e..85778958f5803 100644
+--- a/drivers/gpu/drm/xe/xe_exec_queue.c
++++ b/drivers/gpu/drm/xe/xe_exec_queue.c
+@@ -801,6 +801,9 @@ static int exec_queue_set_hang_replay_state(struct xe_device *xe,
+ u64 __user *address = u64_to_user_ptr(value);
+ void *ptr;
+
++ if (q->replay_state)
++ return -EINVAL;
++
+ ptr = vmemdup_user(address, size);
+ if (XE_IOCTL_DBG(xe, IS_ERR(ptr)))
+ return PTR_ERR(ptr);
+--
+2.53.0
+
--- /dev/null
+From c16111e40bf11f32380c81c3d1068b0dd224e48c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 09:59:45 +0200
+Subject: drm/xe/uc: Apply RCS/CCS yield policy to SR-IOV VFs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
+
+[ Upstream commit d1643db3b037b57f2af7f85c3821d6fe69c492f6 ]
+
+VFs were missing the call to apply the global scheduling policy.
+Call xe_guc_submit_enable() during vf_uc_load_hw() to ensure VFs
+get the same policy enforcement as PF.
+
+Fixes: 26caeae9fb48 ("drm/xe/guc: Set RCS/CCS yield policy")
+Suggested-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
+Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
+Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Reviewed-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
+Link: https://patch.msgid.link/20260709075945.1337660-1-marcin.bernatowicz@linux.intel.com
+Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
+(cherry picked from commit f09360e857130f7ab7f069e2421e6b4a6e502531)
+Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_uc.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_uc.c b/drivers/gpu/drm/xe/xe_uc.c
+index 75091bde0d50c..65f59f06177fd 100644
+--- a/drivers/gpu/drm/xe/xe_uc.c
++++ b/drivers/gpu/drm/xe/xe_uc.c
+@@ -15,6 +15,7 @@
+ #include "xe_guc_pc.h"
+ #include "xe_guc_rc.h"
+ #include "xe_guc_engine_activity.h"
++#include "xe_guc_submit.h"
+ #include "xe_huc.h"
+ #include "xe_sriov.h"
+ #include "xe_wopcm.h"
+@@ -159,12 +160,14 @@ static int vf_uc_load_hw(struct xe_uc *uc)
+ if (err)
+ return err;
+
+- uc->guc.submission_state.enabled = true;
+-
+ err = xe_guc_opt_in_features_enable(&uc->guc);
+ if (err)
+ return err;
+
++ err = xe_guc_submit_enable(&uc->guc);
++ if (err)
++ return err;
++
+ err = xe_gt_record_default_lrcs(uc_to_gt(uc));
+ if (err)
+ return err;
+--
+2.53.0
+
--- /dev/null
+From 8073aba65d4ec447580482577f606c62c327bb3f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 23:26:30 -0700
+Subject: enic: fix tx_hang_reset use-after-free on device removal
+
+From: Satish Kharat <satishkh@cisco.com>
+
+[ Upstream commit ec680ea4ba1bca92a767fb7e7869758bfdd886e3 ]
+
+enic_remove() cancels the reset and change_mtu_work items but does not
+cancel tx_hang_reset. A TX timeout that fires while the device is being
+removed can schedule enic_tx_hang_reset() so that it runs after
+free_netdev(), resulting in a use-after-free.
+
+cancel_work_sync() alone is not sufficient here: the still-live watchdog
+and notify paths can re-schedule these work items in the window between
+the cancel and unregister_netdev(). Use disable_work_sync(), which
+cancels the work and blocks any subsequent schedule_work() from
+requeuing it, and apply it to the reset and change_mtu_work items as
+well so the same requeue race is closed for all teardown work.
+
+Fixes: 937317c7c109 ("enic: do hang reset only in case of tx timeout")
+Signed-off-by: Satish Kharat <satishkh@cisco.com>
+Link: https://patch.msgid.link/20260728062730.2394873-1-satishkh@cisco.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cisco/enic/enic_main.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
+index e7125b8180879..d98f7e7ccab9b 100644
+--- a/drivers/net/ethernet/cisco/enic/enic_main.c
++++ b/drivers/net/ethernet/cisco/enic/enic_main.c
+@@ -3011,8 +3011,9 @@ static void enic_remove(struct pci_dev *pdev)
+ if (netdev) {
+ struct enic *enic = netdev_priv(netdev);
+
+- cancel_work_sync(&enic->reset);
+- cancel_work_sync(&enic->change_mtu_work);
++ disable_work_sync(&enic->reset);
++ disable_work_sync(&enic->tx_hang_reset);
++ disable_work_sync(&enic->change_mtu_work);
+ unregister_netdev(netdev);
+ enic_dev_deinit(enic);
+ vnic_dev_close(enic->vdev);
+--
+2.53.0
+
--- /dev/null
+From 8c9958524684c89821eb179c37be4d4fcb30a45e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:16:45 +0800
+Subject: hwmon: (ads7828) Fix external VREF regulator handling
+
+From: Qingshuang Fu <fuqingshuang@kylinos.cn>
+
+[ Upstream commit fddb5ceaf901b050ed2a1a7deeecbf97e003435a ]
+
+The driver currently has two issues with the external VREF regulator
+handling in ads7828_probe():
+
+1. All errors from devm_regulator_get_optional() are ignored, causing the
+ driver to incorrectly fall back to internal VREF even for transient
+ errors like -EPROBE_DEFER or genuine failures like -ENOMEM.
+
+2. The external regulator is never enabled. The driver calls
+ regulator_get_voltage() without first calling regulator_enable(),
+ so the VREF pin may remain unpowered if the regulator is not
+ configured as always-on.
+
+Fix both issues by switching to devm_regulator_get_enable_read_voltage(),
+which handles regulator get, enable, and voltage read in one call.
+Only -ENODEV (no regulator specified in device tree) should trigger the
+fallback to internal VREF. All other errors are propagated to the caller.
+
+Fixes: a8ddfea09566 ("hwmon: (ads7828) Accept optional parameters from device tree")
+Signed-off-by: Qingshuang Fu <fuqingshuang@kylinos.cn>
+Link: https://lore.kernel.org/r/20260805061645.1331652-1-fffsqian@163.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ads7828.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
+index 149cfcec78dcc..f8f2f621dfeaf 100644
+--- a/drivers/hwmon/ads7828.c
++++ b/drivers/hwmon/ads7828.c
+@@ -106,12 +106,11 @@ static int ads7828_probe(struct i2c_client *client)
+ struct ads7828_data *data;
+ struct device *hwmon_dev;
+ unsigned int vref_mv = ADS7828_INT_VREF_MV;
+- unsigned int vref_uv;
++ int vref_uv;
+ bool diff_input = false;
+ bool ext_vref = false;
+ unsigned int regval;
+ enum ads7828_chips chip;
+- struct regulator *reg;
+
+ data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL);
+ if (!data)
+@@ -125,9 +124,11 @@ static int ads7828_probe(struct i2c_client *client)
+ } else if (dev->of_node) {
+ diff_input = of_property_read_bool(dev->of_node,
+ "ti,differential-input");
+- reg = devm_regulator_get_optional(dev, "vref");
+- if (!IS_ERR(reg)) {
+- vref_uv = regulator_get_voltage(reg);
++ vref_uv = devm_regulator_get_enable_read_voltage(dev, "vref");
++ if (vref_uv < 0) {
++ if (vref_uv != -ENODEV)
++ return vref_uv;
++ } else {
+ vref_mv = DIV_ROUND_CLOSEST(vref_uv, 1000);
+ if (vref_mv < ADS7828_EXT_VREF_MV_MIN ||
+ vref_mv > ADS7828_EXT_VREF_MV_MAX)
+--
+2.53.0
+
--- /dev/null
+From 6a0da1d266bd488945ea7838ee5e32f5f34a9fe1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 07:19:20 +0000
+Subject: hwmon: (corsair-psu) fix possible out-of-bounds access on missing
+ string termination
+
+From: Wilken Gottwalt <wilken.gottwalt@posteo.net>
+
+[ Upstream commit 36c4d73ce05d1d8896c2669eb0730d35a02a2ec1 ]
+
+In theory it could be possible that the REPLY_SIZE sized buffers for
+holding the vendor and product strings could be end up missing the null
+termination (for example by malicious hardware built on purpose)
+required by the seq_printf() call. That limits the debugfs printf calls
+to a maximum string length of REPLY_SIZE.
+
+Fixes: d115b51e0e567 ("hwmon: add Corsair PSU HID controller driver")
+Signed-off-by: Wilken Gottwalt <wilken.gottwalt@posteo.net>
+Link: https://lore.kernel.org/r/anLj9gPWRoRDbQBV@monster.localdomain
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/corsair-psu.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c
+index ce958cdaef58a..3c01ae3fc4af2 100644
+--- a/drivers/hwmon/corsair-psu.c
++++ b/drivers/hwmon/corsair-psu.c
+@@ -701,7 +701,7 @@ static int vendor_show(struct seq_file *seqf, void *unused)
+ {
+ struct corsairpsu_data *priv = seqf->private;
+
+- seq_printf(seqf, "%s\n", priv->vendor);
++ seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->vendor);
+
+ return 0;
+ }
+@@ -711,7 +711,7 @@ static int product_show(struct seq_file *seqf, void *unused)
+ {
+ struct corsairpsu_data *priv = seqf->private;
+
+- seq_printf(seqf, "%s\n", priv->product);
++ seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->product);
+
+ return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From 3c8acb662062397d0076ba27c2a1d697dc426736 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 14:21:39 +0000
+Subject: hwmon: (corsair-psu) serialize debugfs access against hwmon
+
+From: Ali Ahmet Memis <ali@iusegentoo.com>
+
+[ Upstream commit 2da6050809d437a805e7a3aa22398a15073b0234 ]
+
+corsairpsu_request() sends a rail select command and then the actual
+read as two separate transfers, both going through the single shared
+cmd_buffer and wait_completion in corsairpsu_usb_cmd(). The hwmon core
+serializes its own callers, but the debugfs files call
+corsairpsu_get_value() directly and never take that lock, so a debugfs
+read can land between another reader's rail select and its value read.
+
+The result is a value from the wrong rail reported as the right one,
+because corsairpsu_usb_cmd() only checks the command echo and both
+transfers echo the command it expects. It can also make a caller consume
+the reply meant for the other one, since raw_event() writes into the
+shared buffer and completes whoever happens to be waiting.
+
+Locking was dropped in commit 4207069edbf0 ("hwmon: (corsair-psu) Rely
+on subsystem locking") on the grounds that the subsystem serializes for
+us, which holds for sysfs but not for these files. Take
+the same lock in the debugfs paths that issue commands, using the guard
+added in commit d1e720c7328e ("hwmon: Support guard() and scoped_guard
+for subsystem locks").
+
+The lock cannot go into corsairpsu_request() itself: the hwmon core
+already holds it across ->read, so every sysfs read would deadlock.
+vendor_show() and product_show() only print strings cached during probe
+and issue no command, and corsairpsu_get_criticals() and
+corsairpsu_check_cmd_support() run before either interface is
+registered, so none of them need it.
+
+Fixes: 4207069edbf0 ("hwmon: (corsair-psu) Rely on subsystem locking")
+Signed-off-by: Ali Ahmet Memis <ali@iusegentoo.com>
+Tested-by: Wilken Gottwalt <wilken.gottwalt@posteo.net>
+Link: https://lore.kernel.org/r/20260806142139.168611-1-ali@iusegentoo.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/corsair-psu.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c
+index 3c01ae3fc4af2..ebcaddf337d80 100644
+--- a/drivers/hwmon/corsair-psu.c
++++ b/drivers/hwmon/corsair-psu.c
+@@ -664,6 +664,8 @@ static void print_uptime(struct seq_file *seqf, u8 cmd)
+ long val;
+ int ret;
+
++ guard(hwmon_lock)(priv->hwmon_dev);
++
+ ret = corsairpsu_get_value(priv, cmd, 0, &val);
+ if (ret < 0) {
+ seq_puts(seqf, "N/A\n");
+@@ -723,6 +725,8 @@ static int ocpmode_show(struct seq_file *seqf, void *unused)
+ long val;
+ int ret;
+
++ guard(hwmon_lock)(priv->hwmon_dev);
++
+ /*
+ * The rail mode is switchable on the fly. The RAW interface can be used for this. But it
+ * will not be included here, because I consider it somewhat dangerous for the health of the
+--
+2.53.0
+
--- /dev/null
+From 45bab68cd045244b4315e082cc3391f2e00e3bb8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 15:42:42 -0700
+Subject: hwmon: (ltc4282) Avoid overflow in maximum power calculation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit edd11a94335747423569500a194c6eaa915f2963 ]
+
+During device initialization in ltc4282_set_max_limits(), the calculation
+of the maximum power limit can suffer from a 32-bit integer overflow.
+
+static int ltc4282_set_max_limits(struct ltc4282_state *st)
+{
+ ...
+ st->power_max = DIV_ROUND_CLOSEST(st->vsense_max * DECA * MILLI,
+ st->rsense) * st->vfs_out;
+ ...
+}
+
+The result of DIV_ROUND_CLOSEST() evaluates to a 32-bit unsigned integer
+on 32-bit architectures. This result is then multiplied by st->vfs_out,
+which is a 16-bit unsigned integer. According to C promotion rules, since
+both operands are 32-bit or smaller, the multiplication is performed in
+32-bit precision.
+
+If the device is configured with a low sense resistor value via the device
+tree (for example, 100 nano-ohms, resulting in st->rsense = 1) and the
+voltage is high, the division result can reach 343,750,000 and st->vfs_out
+can be 33,280. The product of these values is approximately 11.44 trillion,
+which exceeds the maximum capacity of a 32-bit integer and overflows
+before being stored in st->power_max.
+
+This overflow causes a truncated value to be assigned to st->power_max and
+written to the hardware limit register. An incorrect maximum power limit
+can trigger spurious power-bad faults or alarms, which may lead to the
+shutdown of the monitored power rail.
+
+Avoid the problem by calculating and storing the maximum power using 64-bit
+variables.
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282")
+Cc: Nuno Sa <nuno.sa@analog.com>
+Reviewed-by: Nuno Sá <nuno.sa@analog.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ltc4282.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c
+index bdbf370233d71..9ccad99f42e7f 100644
+--- a/drivers/hwmon/ltc4282.c
++++ b/drivers/hwmon/ltc4282.c
+@@ -138,7 +138,7 @@ struct ltc4282_state {
+ */
+ struct ltc4282_cache in0_1_cache[LTC4282_CHAN_VGPIO];
+ u32 vsense_max;
+- long power_max;
++ s64 power_max;
+ u32 rsense;
+ u16 vdd;
+ u16 vfs_out;
+@@ -614,13 +614,12 @@ static int ltc4282_read(struct device *dev, enum hwmon_sensor_types type,
+ }
+
+ static int ltc4282_write_power_byte(const struct ltc4282_state *st, u32 reg,
+- long val)
++ s64 val)
+ {
+ u32 power;
+ u64 temp;
+
+- if (val > st->power_max)
+- val = st->power_max;
++ val = clamp(val, 0, st->power_max);
+
+ temp = val * int_pow(U8_MAX, 2) * st->rsense;
+ power = DIV64_U64_ROUND_CLOSEST(temp,
+@@ -630,7 +629,7 @@ static int ltc4282_write_power_byte(const struct ltc4282_state *st, u32 reg,
+ }
+
+ static int ltc4282_write_power_word(const struct ltc4282_state *st, u32 reg,
+- long val)
++ u64 val)
+ {
+ u64 temp = int_pow(U16_MAX, 2) * st->rsense, temp_2;
+ __be16 __raw;
+@@ -1223,7 +1222,8 @@ static int ltc4282_set_max_limits(struct ltc4282_state *st)
+ return ret;
+
+ /* Power is given by ISENSE * Vout. */
+- st->power_max = DIV_ROUND_CLOSEST(st->vsense_max * DECA * MILLI, st->rsense) * st->vfs_out;
++ st->power_max = DIV_ROUND_CLOSEST_ULL((u64)st->vsense_max * DECA * MILLI,
++ st->rsense) * st->vfs_out;
+ ret = ltc4282_write_power_byte(st, LTC4282_POWER_MAX, st->power_max);
+ if (ret)
+ return ret;
+--
+2.53.0
+
--- /dev/null
+From 408cdd6a05775fb38cdb009b69641c8867c24498 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 16:26:05 -0700
+Subject: hwmon: (ltc4282) Clamp negative current limits
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit e253dd5f9f6d875a317895bf43ec9534ed7523cb ]
+
+When a negative value is passed to ltc4282_write_curr(), the signed long
+val is cast directly to u64:
+
+drivers/hwmon/ltc4282.c:ltc4282_write_curr() {
+ /* need to pass it in millivolt */
+ u32 in = DIV_ROUND_CLOSEST_ULL((u64)val * st->rsense, DECA * MICRO);
+ ...
+}
+
+This cast converts negative inputs into large positive values. The
+subsequent division result overflows the u32 in variable, truncating
+to a pseudo-random positive value. When this is passed to
+ltc4282_write_voltage_byte(), it is clamped to the maximum limit instead
+of zero.
+
+Clamp val to 0 and to the maximum supported upper limit before the cast
+and assign the result to a 64-bit temporary variable before the division
+to avoid the underflow and an also possible overflow.
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282")
+Cc: Nuno Sa <nuno.sa@analog.com>
+Reviewed-by: Nuno Sá <nuno.sa@analog.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ltc4282.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c
+index 9ccad99f42e7f..9c88e98e101e2 100644
+--- a/drivers/hwmon/ltc4282.c
++++ b/drivers/hwmon/ltc4282.c
+@@ -14,6 +14,7 @@
+ #include <linux/hwmon.h>
+ #include <linux/i2c.h>
+ #include <linux/math.h>
++#include <linux/math64.h>
+ #include <linux/minmax.h>
+ #include <linux/module.h>
+ #include <linux/mod_devicetable.h>
+@@ -930,8 +931,11 @@ static int ltc4282_curr_reset_hist(struct ltc4282_state *st)
+ static int ltc4282_write_curr(struct ltc4282_state *st, u32 attr,
+ long val)
+ {
++ s32 ulimit = min_t(u64, INT_MAX,
++ div_u64((u64)INT_MAX * DECA * MICRO, st->rsense));
++ u64 val64 = clamp(val, 0, ulimit);
+ /* need to pass it in millivolt */
+- u32 in = DIV_ROUND_CLOSEST_ULL((u64)val * st->rsense, DECA * MICRO);
++ u32 in = DIV_ROUND_CLOSEST_ULL(val64 * st->rsense, DECA * MICRO);
+
+ switch (attr) {
+ case hwmon_curr_max:
+--
+2.53.0
+
--- /dev/null
+From ebb36540dfed859270a95ef9bd73784b91ca7b9e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 17:30:42 -0700
+Subject: hwmon: (ltc4282) Fix parsing adi,current-limit-sense-microvolt
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit 335698fd7f60b6707b21fda725f97f35fa956b07 ]
+
+ltc4282_parse_dt() evaluates the wrong variable when parsing the current
+limit.
+
+When the adi,current-limit-sense-microvolt property is parsed into
+st->vsense_max, the subsequent switch statement evaluates the unrelated
+val variable instead of st->vsense_max:
+
+drivers/hwmon/ltc4282.c:ltc4282_parse_dt() {
+ ...
+ ret = device_property_read_u32(dev, "adi,current-limit-sense-microvolt",
+ &st->vsense_max);
+ if (!ret) {
+ int reg_val;
+
+ switch (val) {
+ case 12500:
+ reg_val = 0;
+ break;
+ ...
+}
+
+Because val holds a small integer representing vin_mode (from 0 to 3), it
+never matches any of the valid current limit cases.
+
+This causes it to always fall through to the default error case, return
+-EINVAL, and aborts probe initialization for any device tree using this
+property.
+
+Validate st->vsense_max instead to fix the problem.
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282")
+Cc: Nuno Sa <nuno.sa@analog.com>
+Reviewed-by: Nuno Sá <nuno.sa@analog.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ltc4282.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c
+index 9c88e98e101e2..d7c6226081440 100644
+--- a/drivers/hwmon/ltc4282.c
++++ b/drivers/hwmon/ltc4282.c
+@@ -1395,7 +1395,7 @@ static int ltc4282_setup(struct ltc4282_state *st, struct device *dev)
+ if (!ret) {
+ int reg_val;
+
+- switch (val) {
++ switch (st->vsense_max) {
+ case 12500:
+ reg_val = 0;
+ break;
+--
+2.53.0
+
--- /dev/null
+From 6d49b2cdae7eec6bd485853063f0b04c3be3e0ed Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 15:48:42 +0800
+Subject: hwmon: (nzxt-smart2) Check return value of init_device() in probe
+
+From: Qingshuang Fu <fuqingshuang@kylinos.cn>
+
+[ Upstream commit d533882ce1060866a590257f2c77ee23eabef5b8 ]
+
+The init_device() call in nzxt_smart2_hid_probe() can fail because it
+sends HID output reports to the hardware to detect fans and set the
+update interval. If the hardware is not responding or the HID reports
+fail, init_device() returns a negative error code.
+
+However, the return value was ignored, causing the probe to continue
+and register an hwmon device even though the device was never properly
+initialized. This leads to an inconsistent state where the driver
+reports stale data or blocks on wait queues that will never be woken.
+
+The same function's return value is already checked in the
+reset_resume() handler, confirming the author's intent that errors
+should be propagated.
+
+Note that this fix was not possible before commit 59d104b54b0b
+("hwmon: (nzxt-smart2) Stop device IO before calling hid_hw_stop")
+because the out_hw_close error path was missing hid_device_io_stop(),
+which would have opened a use-after-free risk window.
+
+Fixes: 53e68c20aeb1 ("hwmon: add driver for NZXT RGB&Fan Controller/Smart Device v2.")
+Signed-off-by: Qingshuang Fu <fuqingshuang@kylinos.cn>
+Link: https://lore.kernel.org/r/20260804074842.505923-1-fffsqian@163.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/nzxt-smart2.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/nzxt-smart2.c b/drivers/hwmon/nzxt-smart2.c
+index ff0c0bee0e839..efc78a8f58c88 100644
+--- a/drivers/hwmon/nzxt-smart2.c
++++ b/drivers/hwmon/nzxt-smart2.c
+@@ -754,7 +754,11 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev,
+
+ hid_device_io_start(hdev);
+
+- init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS);
++ ret = init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS);
++ if (ret) {
++ dev_err(&hdev->dev, "init_device failed: %d\n", ret);
++ goto out_hw_close;
++ }
+
+ drvdata->hwmon =
+ hwmon_device_register_with_info(&hdev->dev, "nzxtsmart2", drvdata,
+--
+2.53.0
+
--- /dev/null
+From 3a88d6a66279be50634c6680587234b77332b75b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 11:40:50 -0700
+Subject: hwmon: (pmbus/core) Avoid race condition during probe
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit 71638a456852a18a4578f52d51926ba1d223053b ]
+
+pmbus_write_smbalert_mask() is not guarded, which can cause race conditions
+with concurrent sysfs attribute accesses.
+
+Similar, PMBus accesses in pmbus_init_debugfs() are not guarded, also
+resulting in potential race conditions.
+
+Add guards to both functions to prevent the races.
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Fixes: 221819ca4c36e ("hwmon: (pmbus/core) Add interrupt support")
+Fixes: 1e069dfd96dfe ("hwmon: (pmbus) Add debugfs for status registers")
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/pmbus/pmbus_core.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
+index 5567d37f13fe2..095e128709af4 100644
+--- a/drivers/hwmon/pmbus/pmbus_core.c
++++ b/drivers/hwmon/pmbus/pmbus_core.c
+@@ -3427,6 +3427,8 @@ static int pmbus_write_smbalert_mask(struct i2c_client *client, u8 page, u8 reg,
+ {
+ int ret;
+
++ guard(pmbus_lock)(client);
++
+ ret = _pmbus_write_word_data(client, page, PMBUS_SMBALERT_MASK, reg | (val << 8));
+
+ /*
+@@ -3662,6 +3664,8 @@ static void pmbus_init_debugfs(struct i2c_client *client,
+ if (!entries)
+ return;
+
++ guard(pmbus_lock)(client);
++
+ /*
+ * Add device-specific entries.
+ * Please note that the PMBUS standard allows all registers to be
+--
+2.53.0
+
--- /dev/null
+From a6a7b662b6e5bfbcc3ca78d66da230ff8e2bd035 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jul 2026 10:57:35 -0700
+Subject: hwmon: (pmbus) Fix type confusion in notification logic
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit 59bd68ab05a8f9c9a60b6ec44682084184803ff4 ]
+
+Sashiko reports:
+
+At the start of the loop in pmbus_notify(), the code unconditionally casts
+every attribute to a struct sensor_device_attribute:
+
+drivers/hwmon/pmbus/pmbus_core.c:pmbus_notify() {
+ for (i = 0; i < data->num_attributes; i++) {
+ struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int index = attr->index;
+...
+}
+
+However, data->group.attrs can contain other types like struct
+pmbus_samples_reg or struct pmbus_sensor, which only embed a base
+struct device_attribute.
+
+If da is a struct pmbus_samples_reg, dev_attr is the last member. Casting
+it to struct sensor_device_attribute and reading the index field appears
+to access memory past the end of the allocation, which might trigger a
+slab-out-of-bounds read.
+
+Additionally, if da is a struct pmbus_sensor, casting it causes the index
+field to overlap with the page, phase, and reg fields. Could this produce
+a garbage mask on little-endian systems that spuriously matches the target
+reg, page, and flags during an alert?
+
+Fix the problem by using struct sensor_device_attr in struct pmbus_sensor
+and struct pmbus_label. Since those attributes never trigger a
+notification, set the value of attr->index to -1 for them. Use this value
+to distinguish from boolean attributes which _can_ trigger a notification
+and use the index field to encode mask, page, and register values.
+
+Fixes: f469bde9afd1 ("hwmon: (pmbus/core) Notify hwmon events")
+Cc: Vincent Jardin <vjardin@free.fr>
+Tested-by: Vincent Jardin <vjardin@free.fr>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/pmbus/pmbus_core.c | 61 +++++++++++++++++++-------------
+ 1 file changed, 37 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
+index 095e128709af4..3b219ed5386fb 100644
+--- a/drivers/hwmon/pmbus/pmbus_core.c
++++ b/drivers/hwmon/pmbus/pmbus_core.c
+@@ -45,7 +45,7 @@ module_param(wp, int, 0444);
+ struct pmbus_sensor {
+ struct pmbus_sensor *next;
+ char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */
+- struct device_attribute attribute;
++ struct sensor_device_attribute attribute;
+ u8 page; /* page number */
+ u8 phase; /* phase number, 0xff for all phases */
+ u16 reg; /* register */
+@@ -68,7 +68,7 @@ struct pmbus_boolean {
+
+ struct pmbus_label {
+ char name[PMBUS_NAME_SIZE]; /* sysfs label name */
+- struct device_attribute attribute;
++ struct sensor_device_attribute attribute;
+ char label[PMBUS_NAME_SIZE]; /* label */
+ };
+ #define to_pmbus_label(_attr) \
+@@ -1241,7 +1241,8 @@ static ssize_t pmbus_show_sensor(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+ {
+ struct i2c_client *client = to_i2c_client(dev->parent);
+- struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ struct pmbus_sensor *sensor = to_pmbus_sensor(attr);
+ struct pmbus_data *data = i2c_get_clientdata(client);
+ s64 val;
+
+@@ -1261,7 +1262,8 @@ static ssize_t pmbus_set_sensor(struct device *dev,
+ {
+ struct i2c_client *client = to_i2c_client(dev->parent);
+ struct pmbus_data *data = i2c_get_clientdata(client);
+- struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ struct pmbus_sensor *sensor = to_pmbus_sensor(attr);
+ s64 val;
+ int ret;
+ u16 regval;
+@@ -1283,7 +1285,8 @@ static ssize_t pmbus_set_sensor(struct device *dev,
+ static ssize_t pmbus_show_label(struct device *dev,
+ struct device_attribute *da, char *buf)
+ {
+- struct pmbus_label *label = to_pmbus_label(da);
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
++ struct pmbus_label *label = to_pmbus_label(attr);
+
+ return sysfs_emit(buf, "%s\n", label->label);
+ }
+@@ -1436,8 +1439,8 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
+ bool update, bool readonly,
+ bool writeonly, bool convert)
+ {
++ struct sensor_device_attribute *a;
+ struct pmbus_sensor *sensor;
+- struct device_attribute *a;
+
+ sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
+@@ -1461,12 +1464,11 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
+ sensor->update = update;
+ sensor->convert = convert;
+ sensor->data = -ENODATA;
+- pmbus_dev_attr_init(a, sensor->name,
+- readonly ? 0444 : 0644,
+- writeonly ? pmbus_show_zero : pmbus_show_sensor,
+- pmbus_set_sensor);
++ pmbus_attr_init(a, sensor->name, readonly ? 0444 : 0644,
++ writeonly ? pmbus_show_zero : pmbus_show_sensor,
++ pmbus_set_sensor, -1);
+
+- if (pmbus_add_attribute(data, &a->attr))
++ if (pmbus_add_attribute(data, &a->dev_attr.attr))
+ return NULL;
+
+ sensor->next = data->sensors;
+@@ -1483,8 +1485,8 @@ static int pmbus_add_label(struct pmbus_data *data,
+ const char *name, int seq,
+ const char *lstring, int index, int phase)
+ {
++ struct sensor_device_attribute *a;
+ struct pmbus_label *label;
+- struct device_attribute *a;
+
+ label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL);
+ if (!label)
+@@ -1508,8 +1510,8 @@ static int pmbus_add_label(struct pmbus_data *data,
+ lstring, index, phase);
+ }
+
+- pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL);
+- return pmbus_add_attribute(data, &a->attr);
++ pmbus_attr_init(a, label->name, 0444, pmbus_show_label, NULL, -1);
++ return pmbus_add_attribute(data, &a->dev_attr.attr);
+ }
+
+ /*
+@@ -2397,7 +2399,7 @@ struct pmbus_samples_attr {
+ struct pmbus_samples_reg {
+ int page;
+ struct pmbus_samples_attr *attr;
+- struct device_attribute dev_attr;
++ struct sensor_device_attribute attribute;
+ };
+
+ static struct pmbus_samples_attr pmbus_samples_registers[] = {
+@@ -2419,14 +2421,15 @@ static struct pmbus_samples_attr pmbus_samples_registers[] = {
+ }
+ };
+
+-#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, dev_attr)
++#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, attribute)
+
+ static ssize_t pmbus_show_samples(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+ {
+ int val;
+ struct i2c_client *client = to_i2c_client(dev->parent);
+- struct pmbus_samples_reg *reg = to_samples_reg(devattr);
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ struct pmbus_samples_reg *reg = to_samples_reg(attr);
+
+ scoped_guard(pmbus_lock, client) {
+ val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg);
+@@ -2444,7 +2447,8 @@ static ssize_t pmbus_set_samples(struct device *dev,
+ int ret;
+ long val;
+ struct i2c_client *client = to_i2c_client(dev->parent);
+- struct pmbus_samples_reg *reg = to_samples_reg(devattr);
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ struct pmbus_samples_reg *reg = to_samples_reg(attr);
+
+ if (kstrtol(buf, 0, &val) < 0)
+ return -EINVAL;
+@@ -2459,6 +2463,7 @@ static ssize_t pmbus_set_samples(struct device *dev,
+ static int pmbus_add_samples_attr(struct pmbus_data *data, int page,
+ struct pmbus_samples_attr *attr)
+ {
++ struct sensor_device_attribute *a;
+ struct pmbus_samples_reg *reg;
+
+ reg = devm_kzalloc(data->dev, sizeof(*reg), GFP_KERNEL);
+@@ -2468,10 +2473,12 @@ static int pmbus_add_samples_attr(struct pmbus_data *data, int page,
+ reg->attr = attr;
+ reg->page = page;
+
+- pmbus_dev_attr_init(®->dev_attr, attr->name, 0644,
+- pmbus_show_samples, pmbus_set_samples);
++ a = ®->attribute;
++
++ pmbus_attr_init(a, attr->name, 0644,
++ pmbus_show_samples, pmbus_set_samples, -1);
+
+- return pmbus_add_attribute(data, ®->dev_attr.attr);
++ return pmbus_add_attribute(data, &a->dev_attr.attr);
+ }
+
+ static int pmbus_add_samples_attributes(struct i2c_client *client,
+@@ -2979,9 +2986,15 @@ static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags)
+ struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int index = attr->index;
+- u16 smask = pb_index_to_mask(index);
+- u8 spage = pb_index_to_page(index);
+- u16 sreg = pb_index_to_reg(index);
++ u16 smask, sreg;
++ u8 spage;
++
++ if (index == -1)
++ continue;
++
++ smask = pb_index_to_mask(index);
++ spage = pb_index_to_page(index);
++ sreg = pb_index_to_reg(index);
+
+ if (reg == sreg && page == spage && (smask & flags)) {
+ dev_dbg(data->dev, "sysfs notify: %s", da->attr.name);
+--
+2.53.0
+
--- /dev/null
+From 1dca2ccd6013ea578be70772580511241eadd1af Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 14:12:31 -0700
+Subject: hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit 0dabe8a56f772f0ece46d2597799f412c277d874 ]
+
+In lm25066_probe(), the PMBus coefficients for current and power are
+scaled based on the shunt resistor value. The calculation evaluates the
+multiplication using 32-bit arithmetic because info->m is an int and
+shunt is a u32:
+
+static int lm25066_probe(struct i2c_client *client) {
+ ...
+ info->m[PSC_CURRENT_IN] = info->m[PSC_CURRENT_IN] * shunt / 1000;
+ info->m[PSC_POWER] = info->m[PSC_POWER] * shunt / 1000;
+ ...
+}
+
+For large coefficients like 26882 (LM25056) or 15076 (LM5066i), a device
+tree shunt-resistor-micro-ohms value exceeding approximately 159,000
+(159 mOhm, which is physically valid for low-current applications) causes
+the intermediate product to exceed UINT_MAX (4,294,967,295). This results
+in a silent wraparound before the division by 1000.
+
+Furthermore, if the wrapped value has the most significant bit set,
+converting it back to the signed int info->m results in negative
+coefficients. This logic error leads to drastically corrupted current and
+power readings, which can cause erratic thermal or power management
+behavior in the system.
+
+Fix the problem by using 64-bit operations for the multiply/divide
+operations. This can still overflow, but only for unreasonably large
+shunt resistor values.
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Fixes: 94ee5fcc240fe ("hwmon: (pmbus/lm25066) Support configurable sense resistor values")
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/pmbus/lm25066.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c
+index 0f7df7e2c9c5b..cb42832cebf0c 100644
+--- a/drivers/hwmon/pmbus/lm25066.c
++++ b/drivers/hwmon/pmbus/lm25066.c
+@@ -14,6 +14,7 @@
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
+ #include <linux/log2.h>
++#include <linux/math.h>
+ #include <linux/of.h>
+ #include "pmbus.h"
+
+@@ -540,8 +541,8 @@ static int lm25066_probe(struct i2c_client *client)
+ if (of_property_read_u32(client->dev.of_node, "shunt-resistor-micro-ohms", &shunt))
+ shunt = 1000;
+
+- info->m[PSC_CURRENT_IN] = info->m[PSC_CURRENT_IN] * shunt / 1000;
+- info->m[PSC_POWER] = info->m[PSC_POWER] * shunt / 1000;
++ info->m[PSC_CURRENT_IN] = DIV_ROUND_CLOSEST_ULL((u64)info->m[PSC_CURRENT_IN] * shunt, 1000);
++ info->m[PSC_POWER] = DIV_ROUND_CLOSEST_ULL((u64)info->m[PSC_POWER] * shunt, 1000);
+
+ #if IS_ENABLED(CONFIG_SENSORS_LM25066_REGULATOR)
+ /* LM25056 doesn't support OPERATION */
+--
+2.53.0
+
--- /dev/null
+From 768cc92123fd5d3f3d58f988224b1eef0fad0c4b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 07:14:33 -0700
+Subject: hwmon: Support guard() and scoped_guard for subsystem locks
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit d1e720c7328e046049b792d03fae093d4d3a72e4 ]
+
+Add support for guard() and scoped_guard() for the hwmon subsystem lock
+to simplify its use.
+
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Stable-dep-of: 2da6050809d4 ("hwmon: (corsair-psu) serialize debugfs access against hwmon")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/hwmon/hwmon-kernel-api.rst | 7 ++++---
+ include/linux/hwmon.h | 3 +++
+ 2 files changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/Documentation/hwmon/hwmon-kernel-api.rst b/Documentation/hwmon/hwmon-kernel-api.rst
+index 1d7f1397a8274..9fcde32a140df 100644
+--- a/Documentation/hwmon/hwmon-kernel-api.rst
++++ b/Documentation/hwmon/hwmon-kernel-api.rst
+@@ -85,9 +85,10 @@ removal.
+ When using ``[devm_]hwmon_device_register_with_info()`` to register the
+ hardware monitoring device, accesses using the associated access functions
+ are serialised by the hardware monitoring core. If a driver needs locking
+-for other functions such as interrupt handlers or for attributes which are
+-fully implemented in the driver, hwmon_lock() and hwmon_unlock() can be used
+-to ensure that calls to those functions are serialized.
++for other functions such as interrupt handlers, attributes which are fully
++implemented in the driver, or debugfs functions, hwmon_lock() and hwmon_unlock()
++can be used to ensure that calls to those functions are serialized. Those
++functions also support guard() and scoped_guard() variants.
+
+ Using devm_hwmon_device_register_with_info()
+ --------------------------------------------
+diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h
+index 301a83afbd663..f5330e7ae247c 100644
+--- a/include/linux/hwmon.h
++++ b/include/linux/hwmon.h
+@@ -13,6 +13,7 @@
+ #define _HWMON_H_
+
+ #include <linux/bitops.h>
++#include <linux/cleanup.h>
+
+ struct device;
+ struct attribute_group;
+@@ -495,6 +496,8 @@ char *devm_hwmon_sanitize_name(struct device *dev, const char *name);
+ void hwmon_lock(struct device *dev);
+ void hwmon_unlock(struct device *dev);
+
++DEFINE_GUARD(hwmon_lock, struct device *, hwmon_lock(_T), hwmon_unlock(_T))
++
+ /**
+ * hwmon_is_bad_char - Is the char invalid in a hwmon name
+ * @ch: the char to be considered
+--
+2.53.0
+
--- /dev/null
+From ec87973180f65d920783cd2ffa28310218446cf6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 21:35:05 +0300
+Subject: ipvs: avoid out-of-bounds write in ip_vs_nat_icmp
+
+From: Julian Anastasov <ja@ssi.bg>
+
+[ Upstream commit 646922a0379496154e8c8faca4f8e2fd9100cacc ]
+
+Sashiko warns that local attacker can modify the packet
+while it is processed by IPVS. Some places read the
+IP ihl field multiple times which can cause out-of-bounds
+access. One such place is ip_vs_nat_icmp where we
+can write after the validated area.
+
+Fix it by providing ciph argument just like it is done for
+IPv6 and use ciph->len as offset to the embedded transport
+header.
+
+Modify some IPv4 header checks by reading the ihl field
+only once.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Link: https://sashiko.dev/#/patchset/20260722101517.36313-1-ja%40ssi.bg
+Signed-off-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/ip_vs.h | 2 +-
+ net/netfilter/ipvs/ip_vs_core.c | 67 +++++++++++++++++----------------
+ net/netfilter/ipvs/ip_vs_xmit.c | 2 +-
+ 3 files changed, 36 insertions(+), 35 deletions(-)
+
+diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
+index 8d98f7e0a9fb2..ebd88f58afe16 100644
+--- a/include/net/ip_vs.h
++++ b/include/net/ip_vs.h
+@@ -2040,7 +2040,7 @@ static inline bool ip_vs_conn_use_hash2(struct ip_vs_conn *cp)
+
+ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct ip_vs_conn *cp, int dir, unsigned int toff,
+- bool has_ports);
++ bool has_ports, struct ip_vs_iphdr *ciph);
+
+ #ifdef CONFIG_IP_VS_IPV6
+ void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
+diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
+index 6b79e0c4d9e28..0bdaeb4ed61e4 100644
+--- a/net/netfilter/ipvs/ip_vs_core.c
++++ b/net/netfilter/ipvs/ip_vs_core.c
+@@ -925,28 +925,27 @@ static int ip_vs_route_me_harder(struct netns_ipvs *ipvs, int af,
+ */
+ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct ip_vs_conn *cp, int inout, unsigned int toff,
+- bool has_ports)
++ bool has_ports, struct ip_vs_iphdr *ciph)
+ {
+ struct iphdr *iph = ip_hdr(skb);
+ struct icmphdr *icmph = (struct icmphdr *)(skb->data + toff);
+- struct iphdr *ciph = (struct iphdr *)(icmph + 1);
+- unsigned int coff __maybe_unused = toff + sizeof(struct icmphdr);
++ struct iphdr *cih = (struct iphdr *)(icmph + 1);
+
+ if (inout) {
+ iph->saddr = cp->vaddr.ip;
+ ip_send_check(iph);
+- ciph->daddr = cp->vaddr.ip;
+- ip_send_check(ciph);
++ cih->daddr = cp->vaddr.ip;
++ ip_send_check(cih);
+ } else {
+ iph->daddr = cp->daddr.ip;
+ ip_send_check(iph);
+- ciph->saddr = cp->daddr.ip;
+- ip_send_check(ciph);
++ cih->saddr = cp->daddr.ip;
++ ip_send_check(cih);
+ }
+
+ /* the TCP/UDP/SCTP port */
+ if (has_ports) {
+- __be16 *ports = (void *)ciph + ciph->ihl*4;
++ __be16 *ports = (void *)(skb->data + ciph->len);
+
+ if (inout)
+ ports[1] = cp->vport;
+@@ -960,10 +959,10 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ if (inout)
+- IP_VS_DBG_PKT(11, AF_INET, pp, skb, coff,
++ IP_VS_DBG_PKT(11, AF_INET, pp, skb, ciph->off,
+ "Forwarding altered outgoing ICMP");
+ else
+- IP_VS_DBG_PKT(11, AF_INET, pp, skb, coff,
++ IP_VS_DBG_PKT(11, AF_INET, pp, skb, ciph->off,
+ "Forwarding altered incoming ICMP");
+ }
+
+@@ -1056,7 +1055,7 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
+ ip_vs_nat_icmp_v6(skb, pp, cp, 1, toff, has_ports, ciph);
+ else
+ #endif
+- ip_vs_nat_icmp(skb, pp, cp, 1, toff, has_ports);
++ ip_vs_nat_icmp(skb, pp, cp, 1, toff, has_ports, ciph);
+
+ if (ip_vs_route_me_harder(cp->ipvs, af, skb, hooknum))
+ goto out;
+@@ -1092,7 +1091,7 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ struct ip_vs_iphdr ciph;
+ struct ip_vs_conn *cp;
+ struct ip_vs_protocol *pp;
+- unsigned int offset, ihl;
++ unsigned int offset;
+ union nf_inet_addr snet;
+
+ *related = 1;
+@@ -1105,7 +1104,6 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ return NF_ACCEPT;
+ }
+
+- ihl = ipvsh->len;
+ offset = ipvsh->len;
+ ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
+ if (ic == NULL)
+@@ -1131,11 +1129,15 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+
+ /* Now find the contained IP header */
+ offset += sizeof(_icmph);
++ if (!ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, true, &ciph))
++ return NF_ACCEPT; /* The packet looks wrong, ignore */
++
+ cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+- if (!(cih && cih->version == 4 && cih->ihl >= 5))
++ if (!(cih && cih->version == 4 &&
++ ciph.len - ciph.off >= sizeof(struct iphdr)))
+ return NF_ACCEPT; /* The packet looks wrong, ignore */
+
+- pp = ip_vs_proto_get(cih->protocol);
++ pp = ip_vs_proto_get(ciph.protocol);
+ if (!pp)
+ return NF_ACCEPT;
+
+@@ -1146,8 +1148,6 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ IP_VS_DBG_PKT(11, AF_INET, pp, skb, offset,
+ "Checking outgoing ICMP for");
+
+- ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, true, &ciph);
+-
+ /* The embedded headers contain source and dest in reverse order */
+ cp = INDIRECT_CALL_1(pp->conn_out_get, ip_vs_conn_out_get_proto,
+ ipvs, AF_INET, skb, &ciph);
+@@ -1155,8 +1155,8 @@ static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
+ return NF_ACCEPT;
+
+ snet.ip = ipvsh->saddr.ip;
+- return handle_response_icmp(AF_INET, skb, &snet, cp, pp, &ciph, ihl,
+- hooknum);
++ return handle_response_icmp(AF_INET, skb, &snet, cp, pp, &ciph,
++ ipvsh->len, hooknum);
+ }
+
+ #ifdef CONFIG_IP_VS_IPV6
+@@ -1803,10 +1803,12 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ /* Now find the contained IP header */
+ offset += sizeof(_icmph);
+ cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+- if (!(cih && cih->version == 4 && cih->ihl >= 5))
++ if (!cih)
+ return NF_ACCEPT; /* The packet looks wrong, ignore */
+- raddr = (union nf_inet_addr *)&cih->daddr;
+ hlen_ipip = cih->ihl * 4;
++ if (!(cih->version == 4 && hlen_ipip >= sizeof(struct iphdr)))
++ return NF_ACCEPT; /* The packet looks wrong, ignore */
++ raddr = (union nf_inet_addr *)&cih->daddr;
+
+ /* Special case for errors for IPIP/UDP/GRE tunnel packets */
+ tunnel = false;
+@@ -1823,9 +1825,6 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ if (!dest || dest->tun_type != IP_VS_CONN_F_TUNNEL_TYPE_IPIP)
+ return NF_ACCEPT;
+ offset += hlen_ipip;
+- cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+- if (!(cih && cih->version == 4 && cih->ihl >= 5))
+- return NF_ACCEPT; /* The packet looks wrong, ignore */
+ tunnel = true;
+ } else if ((cih->protocol == IPPROTO_UDP || /* Can be UDP encap */
+ cih->protocol == IPPROTO_GRE) && /* Can be GRE encap */
+@@ -1850,21 +1849,25 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ /* Skip IP and UDP/GRE tunnel headers */
+ offset = offset2 + ulen;
+ /* Now we should be at the original IP header */
+- cih = skb_header_pointer(skb, offset, sizeof(_ciph),
+- &_ciph);
+- if (cih && cih->version == 4 && cih->ihl >= 5 &&
+- iproto == IPPROTO_IPIP)
++ if (iproto == IPPROTO_IPIP)
+ tunnel = true;
+ else
+ return NF_ACCEPT;
+ }
+ }
+
+- pd = ip_vs_proto_data_get(ipvs, cih->protocol);
++ if (!ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, !tunnel, &ciph))
++ return NF_ACCEPT;
++ pd = ip_vs_proto_data_get(ipvs, ciph.protocol);
+ if (!pd)
+ return NF_ACCEPT;
+ pp = pd->pp;
+
++ cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
++ if (!(cih && cih->version == 4 &&
++ ciph.len - ciph.off >= sizeof(struct iphdr)))
++ return NF_ACCEPT; /* The packet looks wrong, ignore */
++
+ /* Is the embedded protocol header present? */
+ if (unlikely(cih->frag_off & htons(IP_OFFSET) && !pp->dont_defrag))
+ return NF_ACCEPT;
+@@ -1872,9 +1875,6 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ IP_VS_DBG_PKT(11, AF_INET, pp, skb, offset,
+ "Checking incoming ICMP for");
+
+- offset2 = offset;
+- ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, !tunnel, &ciph);
+-
+ /* The embedded headers contain source and dest in reverse order.
+ * For IPIP/UDP/GRE tunnel this is error for request, not for reply.
+ */
+@@ -1904,11 +1904,12 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
+ }
+
+ if (tunnel) {
+- unsigned int hlen_orig = cih->ihl * 4;
++ unsigned int hlen_orig = ciph.len - ciph.off;
+ __be32 info = ic->un.gateway;
+ __u8 type = ic->type;
+ __u8 code = ic->code;
+
++ offset2 = offset;
+ /* Update the MTU */
+ if (ic->type == ICMP_DEST_UNREACH &&
+ ic->code == ICMP_FRAG_NEEDED) {
+diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
+index 0b0c5304993a9..c4508f3f43dd3 100644
+--- a/net/netfilter/ipvs/ip_vs_xmit.c
++++ b/net/netfilter/ipvs/ip_vs_xmit.c
+@@ -1580,7 +1580,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
+ if (skb_cow(skb, rt->dst.dev->hard_header_len))
+ goto tx_error;
+
+- ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports);
++ ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports, ciph);
+
+ /* Another hack: avoid icmp_send in ip_fragment */
+ skb->ignore_df = 1;
+--
+2.53.0
+
--- /dev/null
+From 3ba9ebe662d19910af31d6872e54516f1b223609 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 21:35:06 +0300
+Subject: ipvs: return the csum validation for forward hook
+
+From: Julian Anastasov <ja@ssi.bg>
+
+[ Upstream commit 99609cb0aa789c8d071050ce8579989551882cc6 ]
+
+Sashiko notes that playing games with the skb dst and rt
+flags instead of providing hooknum is not a good idea
+when validating the checksums.
+
+Also, skipping checksum validation for FORWARD packets
+risk silent data corruption, even if the only user is
+the FTP-CMD packets coming from the real server.
+
+Sashiko also noticed that by using common checksum
+helper in the previous commit we actually fixed old bug
+where the TCP/UDP checksum for IPv6 on CHECKSUM_COMPLETE
+was not validated correctly.
+
+Fixes: e876b75b9020 ("ipvs: fix the checksum validations")
+Link: https://sashiko.dev/#/patchset/20260722211420.153933-1-pablo%40netfilter.org
+Link: https://sashiko.dev/#/patchset/20260727185024.67534-1-ja%40ssi.bg
+Link: https://sashiko.dev/#/patchset/20260728202520.59179-1-ja%40ssi.bg
+Signed-off-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/ip_vs.h | 19 +++++--------------
+ net/netfilter/ipvs/ip_vs_proto_sctp.c | 2 +-
+ 2 files changed, 6 insertions(+), 15 deletions(-)
+
+diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
+index ebd88f58afe16..ac82e6af55ec6 100644
+--- a/include/net/ip_vs.h
++++ b/include/net/ip_vs.h
+@@ -25,9 +25,7 @@
+ #include <linux/netfilter.h> /* for union nf_inet_addr */
+ #include <linux/ip.h>
+ #include <linux/ipv6.h> /* for struct ipv6hdr */
+-#include <net/route.h>
+ #include <net/ipv6.h>
+-#include <net/ip6_fib.h>
+ #if IS_ENABLED(CONFIG_NF_CONNTRACK)
+ #include <net/netfilter/nf_conntrack.h>
+ #endif
+@@ -2073,30 +2071,23 @@ static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum)
+ return csum_partial(diff, sizeof(diff), oldsum);
+ }
+
+-static inline bool ip_vs_checksum_needed(struct sk_buff *skb, int af)
++static inline bool ip_vs_checksum_needed(struct sk_buff *skb)
+ {
+ /* Checksum unnecessary or already validated? */
+ if (skb_csum_unnecessary(skb))
+ return false;
+- /* LOCAL_OUT ? */
+- if (!skb->dev || skb->dev->flags & IFF_LOOPBACK)
++ /* Locally generated ? */
++ if (!skb->dev)
+ return false;
+- /* !LOCAL_IN (FORWARD) ? */
+- if (af == AF_INET6) {
+- if (!(dst_rt6_info(skb_dst(skb))->rt6i_flags & RTF_LOCAL))
+- return false;
+- } else {
+- if (!(skb_rtable(skb)->rt_flags & RTCF_LOCAL))
+- return false;
+- }
+ return true;
+ }
+
+ static inline bool ip_vs_checksum_common_check(struct sk_buff *skb,
+ int offset, int proto, int af)
+ {
+- if (!ip_vs_checksum_needed(skb, af))
++ if (!ip_vs_checksum_needed(skb))
+ return true;
++ /* Validate csum even for FORWARD */
+ return !nf_checksum(skb, NF_INET_LOCAL_IN, offset, proto, af);
+ }
+
+diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
+index 3dbd3096e1637..c80567c73469b 100644
+--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
++++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
+@@ -193,7 +193,7 @@ sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct sctphdr *sh;
+ __le32 cmp, val;
+
+- if (!ip_vs_checksum_needed(skb, af))
++ if (!ip_vs_checksum_needed(skb))
+ return 1;
+ sh = (struct sctphdr *)(skb->data + sctphoff);
+ cmp = sh->checksum;
+--
+2.53.0
+
--- /dev/null
+From 049a92d550a4238c596a4ed1aabf7373bb04aa4d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 13:15:08 +0000
+Subject: net/atm: fix slab-out-of-bounds read in vcc_setsockopt()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit d0c80dbb970439bd2eeb0e5effff8c16a5f4e1e3 ]
+
+vcc_setsockopt() contained an ineffective optlen check:
+ if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
+ return -EINVAL;
+
+If __SO_LEVEL_MATCH(optname, level) evaluated to false (e.g. if the caller
+passed a mismatched level), the length check optlen != __SO_SIZE(optname)
+was short-circuited and bypassed. Execution then fell through to switch(optname),
+calling copy_from_sockptr() assuming optval contained sufficient space.
+
+Furthermore, even if level matched, a cgroup BPF setsockopt filter could shrink
+optlen after entry. Because copy_from_sockptr() on kernel pointers uses memcpy(),
+this leads to a KASAN slab-out-of-bounds read when optlen is smaller than the
+expected structure size.
+
+Fix this by using copy_safe_from_sockptr(), which unconditionally validates
+that optlen is at least the expected size before copying. Also change the local
+'value' variable type from 'unsigned long' to 'int' so that SO_SETCLP matches
+its sizeof(int) ABI encoding on 64-bit systems.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: syzbot+53ecc09fb81df10ef4de@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=53ecc09fb81df10ef4de
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260805131508.3227331-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/atm/common.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/net/atm/common.c b/net/atm/common.c
+index 6eb78c34c2843..c3fbbb63c5d89 100644
+--- a/net/atm/common.c
++++ b/net/atm/common.c
+@@ -760,7 +760,7 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
+ sockptr_t optval, unsigned int optlen)
+ {
+ struct atm_vcc *vcc;
+- unsigned long value;
++ int value;
+ int error;
+
+ if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
+@@ -772,8 +772,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
+ {
+ struct atm_qos qos;
+
+- if (copy_from_sockptr(&qos, optval, sizeof(qos)))
+- return -EFAULT;
++ error = copy_safe_from_sockptr(&qos, sizeof(qos), optval,
++ optlen);
++ if (error)
++ return error;
+ error = check_qos(&qos);
+ if (error)
+ return error;
+@@ -786,8 +788,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
+ return 0;
+ }
+ case SO_SETCLP:
+- if (copy_from_sockptr(&value, optval, sizeof(value)))
+- return -EFAULT;
++ error = copy_safe_from_sockptr(&value, sizeof(value), optval,
++ optlen);
++ if (error)
++ return error;
+ if (value)
+ vcc->atm_options |= ATM_ATMOPT_CLP;
+ else
+--
+2.53.0
+
--- /dev/null
+From aa3622d8e3550cb1d0ca6b9290569c19e5accdf0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 12:17:10 +0400
+Subject: net: hisilicon: hix5hd2_gmac: remove redundant NAPI delete
+
+From: Jiawen Liu <1298662399@qq.com>
+
+[ Upstream commit f307a7dc32097c11413178fca437a10d20890bc2 ]
+
+hix5hd2_dev_remove() calls netif_napi_del() before unregister_netdev().
+This is not needed because free_netdev() deletes all NAPI instances
+attached to the net_device.
+
+Remove the redundant call and let the networking core tear down the NAPI
+instance during unregister_netdev(). The probe error path still keeps its
+explicit netif_napi_del(), because the device has not been registered
+there.
+
+Fixes: 57c5bc9ad7d7 ("net: hisilicon: add hix5hd2 mac driver")
+Signed-off-by: Jiawen Liu <1298662399@qq.com>
+Link: https://patch.msgid.link/tencent_5FFD37A252B4FEA6A80AD25B17C8E904F005@qq.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hix5hd2_gmac.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+index e3e7f2270560c..02282dc86faf4 100644
+--- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
++++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+@@ -1282,7 +1282,6 @@ static void hix5hd2_dev_remove(struct platform_device *pdev)
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct hix5hd2_priv *priv = netdev_priv(ndev);
+
+- netif_napi_del(&priv->napi);
+ unregister_netdev(ndev);
+ mdiobus_unregister(priv->bus);
+ mdiobus_free(priv->bus);
+--
+2.53.0
+
--- /dev/null
+From 13138e0e7ccc96a785d45716599e0baabf7ea920 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jul 2026 17:30:36 +0800
+Subject: net: hns3: fix speed configuration residue after driver reload
+
+From: Jijie Shao <shaojijie@huawei.com>
+
+[ Upstream commit 3860d8748af315bfee6fe669fddc1fc17d3214db ]
+
+After setting a 100G optical port to 40G via ethtool and reloading
+the driver, the port remains at 40G instead of reverting to the
+firmware default speed of 100G.
+
+The commit referenced in Fixes: added two overwrites in
+hclge_init_ae_dev() for non-copper media, so that optical ports
+connected to forced-mode remotes inherit the firmware-preset
+autoneg and speed instead of the hardcoded defaults:
+
+ req_autoneg = mac.autoneg
+ req_speed = mac.speed (when autoneg disabled)
+
+The autoneg overwrite keeps existing behavior:
+hclge_set_autoneg_speed_dup() already uses mac.autoneg (not
+req_autoneg) since it was introduced, so autoneg inheritance from
+firmware was already in place. This part is kept.
+
+The speed overwrite, however, introduces the residue: mac.speed
+reflects whatever was last programmed into the MAC, and after unload
+firmware does not restore the MAC speed to the flash default. So if
+the user changed speed via ethtool in a prior load, mac.speed still
+carries that value on reload and req_speed inherits it.
+
+Fix by dropping the req_speed overwrite only. req_speed keeps the
+firmware default value set in hclge_configure() (cfg.default_speed),
+so a reload reverts the speed to default, matching the expectation
+that a driver reload resets link configuration.
+
+Trade-off: on optical ports whose firmware default speed does not
+match a forced-mode remote, reload now drops the link and the user
+must re-apply ethtool configuration. This is acceptable: a driver
+reload is expected to reset link configuration, not to inherit
+runtime state from before unload. The autoneg inheritance is left
+in place as established behavior; changing it is out of scope for
+this patch and would itself be a user-perceivable behavior change.
+
+Fixes: d9d349c4e8a0 ("net: hns3: differentiate autoneg default values between copper and fiber")
+Signed-off-by: Jijie Shao <shaojijie@huawei.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260724093036.426631-1-shaojijie@huawei.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+index 2a6e4d17452c4..13c20a8ca3b0f 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+@@ -11926,12 +11926,8 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
+ if (ret)
+ goto err_ptp_uninit;
+
+- if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_COPPER) {
++ if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_COPPER)
+ hdev->hw.mac.req_autoneg = hdev->hw.mac.autoneg;
+- if (hdev->hw.mac.autoneg == AUTONEG_DISABLE &&
+- hdev->hw.mac.speed != SPEED_UNKNOWN)
+- hdev->hw.mac.req_speed = hdev->hw.mac.speed;
+- }
+
+ ret = hclge_set_autoneg_speed_dup(hdev);
+ if (ret) {
+--
+2.53.0
+
--- /dev/null
+From 30e50e8a071d0e7283008fafb6f87a9b841fdbc4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 11:04:02 +0300
+Subject: net/mlx5: fw_tracer, return NULL on create error
+
+From: Michael Guralnik <michaelgur@nvidia.com>
+
+[ Upstream commit af39eb111ce6b5eba9c08513b62c4868eb7e7fd5 ]
+
+Tracer creation can fail by returning either NULL or ERR_PTR.
+The return value is stored without a check on the device, and users
+treat ERR_PTR and NULL the same way.
+This also causes a crash in the core dump logic, which is missing the
+ERR_PTR check and ends up dereferencing it, as shown in the trace below.
+
+Switch tracer creation to return NULL on failure only, so callers only
+need a single NULL check.
+
+ Internal error: Oops: 0000000096000006 [#1] SMP
+ Modules linked in: mlx5_ib ib_uverbs ib_core ipv6 mlx5_core
+ CPU: 1 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted 6.19.7 #1 PREEMPT(none)
+ Workqueue: mlx5_health0001:01:00.0 mlx5_fw_reporter_err_work [mlx5_core]
+ pstate: a3400009 (NzCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
+ pc : mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core]
+ lr : mlx5_fw_tracer_trigger_core_dump_general+0x40/0xe0 [mlx5_core]
+ sp : ffff800081cf3c40
+ x29: ffff800081cf3c90 x28: 0000000000000000 x27: 0000000000000000
+ x26: ffff000080018828 x25: 0000000000000000 x24: ffff000080304a05
+ x23: ffff800081cf3d80 x22: ffff0000847e01a0 x21: 0000000000000000
+ x20: ffff0000847e01a0 x19: ffffffffffffffa1 x18: ffff80008310bbf0
+ x17: ffff800080119650 x16: ffff80008010df54 x15: ffff80008010d4ac
+ x14: ffff800079c202e4 x13: ffff80008002fe60 x12: ffff800080119650
+ x11: ffff80008010df54 x10: ffff80008010d4ac x9 : ffff800079c203d8
+ x8 : ffff800081cf3c88 x7 : 0000000000000000 x6 : 0000000000000000
+ x5 : 0000000000000000 x4 : 0000000000000008 x3 : 0000000000000030
+ x2 : 0000000000000008 x1 : 0000000000000000 x0 : 00000000c5c4000e
+ Call trace:
+ mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core] (P)
+ mlx5_fw_reporter_dump+0x30/0x2e0 [mlx5_core]
+ devlink_health_do_dump+0x9c/0x160
+ devlink_health_report+0x1c0/0x288
+ mlx5_fw_reporter_err_work+0xac/0xc0 [mlx5_core]
+ process_one_work+0x15c/0x3d8
+ worker_thread+0x18c/0x320
+ kthread+0x148/0x228
+ ret_from_fork+0x10/0x20
+ Code: b9400000 5ac00800 7a401800 540003ca (3940a260)
+ ---[ end trace 0000000000000000 ]---
+ Kernel panic - not syncing: Oops: Fatal exception
+ SMP: stopping secondary CPUs
+ Kernel Offset: disabled
+ CPU features: 0x000000,00078031,75fce5a1,35fffe67
+ Memory Limit: none
+ ---[ end Kernel panic - not syncing: Oops: Fatal exception ]---
+
+Fixes: fd1483fe1f9f ("net/mlx5: Add support for FW reporter dump")
+Signed-off-by: Michael Guralnik <michaelgur@nvidia.com>
+Reviewed-by: Shay Drori <shayd@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260729080402.2427184-1-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ethernet/mellanox/mlx5/core/diag/fw_tracer.c | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+index adcc73e2a5b38..1493d8106c1a4 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+@@ -1025,13 +1025,11 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
+
+ tracer = kvzalloc_obj(*tracer);
+ if (!tracer)
+- return ERR_PTR(-ENOMEM);
++ return NULL;
+
+ tracer->work_queue = create_singlethread_workqueue("mlx5_fw_tracer");
+- if (!tracer->work_queue) {
+- err = -ENOMEM;
++ if (!tracer->work_queue)
+ goto free_tracer;
+- }
+
+ tracer->dev = dev;
+
+@@ -1073,7 +1071,7 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
+ destroy_workqueue(tracer->work_queue);
+ free_tracer:
+ kvfree(tracer);
+- return ERR_PTR(err);
++ return NULL;
+ }
+
+ static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data);
+@@ -1084,7 +1082,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
+ struct mlx5_core_dev *dev;
+ int err;
+
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return 0;
+
+ if (!tracer->str_db.loaded)
+@@ -1134,7 +1132,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
+ /* Stop tracer + Cleanup HW resources */
+ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
+ {
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return;
+
+ mutex_lock(&tracer->state_lock);
+@@ -1163,7 +1161,7 @@ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
+ /* Free software resources (Buffers, etc ..) */
+ void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer)
+ {
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return;
+
+ mlx5_core_dbg(tracer->dev, "FWTracer: Destroy\n");
+@@ -1215,7 +1213,7 @@ int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer)
+ struct mlx5_core_dev *dev;
+ int err;
+
+- if (IS_ERR_OR_NULL(tracer))
++ if (!tracer)
+ return 0;
+
+ dev = tracer->dev;
+--
+2.53.0
+
--- /dev/null
+From ecccff705f2c3e7808414aefe779e6b5b20db02b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 16:47:29 -0700
+Subject: net/mlx5e: fix BQL reset on SQ re-activation
+
+From: Bobby Eshleman <bobbyeshleman@meta.com>
+
+[ Upstream commit e7386770be1bf810bcd6af39d1e4bfeab3408430 ]
+
+mlx5e_queue_start() deactivates and re-activates all channels but closes
+only the queue being restarted. mlx5e_activate_txqsq() then
+unconditionally calls netdev_tx_reset_queue(), zeroing the BQL counters
+of channels that kept their in-flight TX WQEs. The next completion then
+over-charges and trips the BUG_ON() in dql_completed():
+
+ kernel BUG at lib/dynamic_queue_limits.c:99!
+ RIP: 0010:dql_completed+0x23d/0x280
+ Call Trace:
+ <IRQ>
+ mlx5e_poll_tx_cq+0x668/0xa60
+ mlx5e_napi_poll+0x5b/0x7b0
+ net_rx_action+0x15a/0x580
+
+Reset BQL only when the SQ has no bytes in flight (sq->cc == sq->pc).
+
+In the case that reset is skipped, the outstanding WQEs will eventually
+complete and rebalance the dql. The dql->limit is carried across the
+reset.
+
+Fixes: b2588ea40ec9 ("net/mlx5e: Implement queue mgmt ops and single channel swap")
+Signed-off-by: Bobby Eshleman <bobbyeshleman@meta.com>
+Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260803-mlx5-bql-v3-1-a30d4c66fe1d@meta.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index 7d1063c7bf649..22ae49af38cd7 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -1939,8 +1939,10 @@ int mlx5e_open_txqsq(struct mlx5e_channel *c, u32 tisn, int txq_ix,
+ void mlx5e_activate_txqsq(struct mlx5e_txqsq *sq)
+ {
+ sq->txq = netdev_get_tx_queue(sq->netdev, sq->txq_ix);
++ /* Reset BQL only when the SQ has no bytes in flight. */
++ if (sq->cc == sq->pc)
++ netdev_tx_reset_queue(sq->txq);
+ set_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
+- netdev_tx_reset_queue(sq->txq);
+ netif_tx_start_queue(sq->txq);
+ netif_queue_set_napi(sq->netdev, sq->txq_ix, NETDEV_QUEUE_TYPE_TX, sq->cq.napi);
+ }
+--
+2.53.0
+
--- /dev/null
+From 169d11155baa196ab37a3cf65cd959be90365c7e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 07:43:38 +0300
+Subject: net/mlx5e: TC, Check if flow is PEER before acquiring devcom lock
+
+From: Shay Drory <shayd@nvidia.com>
+
+[ Upstream commit 6ddfba2ea98db21b001e0e5c472499156224650c ]
+
+In case __mlx5e_add_fdb_flow() fails in lower levels, the flow is
+deleted via mlx5e_tc_del_flow(), and mlx5e_tc_del_flow() is acquiring
+ESW devcom lock without condition. In addition, in case of peer_flow,
+__mlx5e_add_fdb_flow() is called while holding ESW devcom comp lock.
+This results in an AA deadlock.
+
+To fix this, introduce a new PEER flag that is set on flows created as
+peer flows (the duplicate flows on peer devices), and check it in
+mlx5e_tc_del_flow() before acquiring ESW devcom lock.
+
+Lockdep splat:
+============================================
+WARNING: possible recursive locking detected
+============================================
+ Possible unsafe locking scenario:
+ CPU0
+ ----
+ lock(&comp->lock_key#2);
+ lock(&comp->lock_key#2);
+ *** DEADLOCK ***
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0x69/0xa0
+ print_deadlock_bug.cold+0xbd/0xca
+ __lock_acquire+0x1671/0x2ec0
+ lock_acquire+0x10e/0x2e0
+ down_read+0x95/0x430
+ mlx5_devcom_for_each_peer_begin+0x4e/0xe0 [mlx5_core]
+ mlx5e_tc_del_flow+0x11d/0xa70 [mlx5_core]
+ mlx5e_flow_put+0x99/0x100 [mlx5_core]
+ __mlx5e_add_fdb_flow+0x409/0xf00 [mlx5_core]
+ mlx5e_configure_flower+0x2a86/0x4100 [mlx5_core]
+ mlx5e_rep_setup_tc_cls_flower+0x12f/0x1b0 [mlx5_core]
+ mlx5e_rep_setup_tc_cb+0x153/0x750 [mlx5_core]
+ tc_setup_cb_add+0x1dc/0x470
+ fl_change+0x2f4d/0x626d [cls_flower]
+ tc_new_tfilter+0x79b/0x2310
+ rtnetlink_rcv_msg+0x778/0xad0
+ do_syscall_64+0x70/0x960
+ entry_SYSCALL_64_after_hwframe+0x4b/0x53
+ </TASK>
+
+Fixes: 04de7dda7394 ("net/mlx5e: Infrastructure for duplicated offloading of TC flows")
+Signed-off-by: Shay Drory <shayd@nvidia.com>
+Reviewed-by: Cosmin Ratiu <cratiu@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260728044338.2271143-1-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h | 1 +
+ drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 4 +++-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
+index efb34de4cb7ad..692ac2f21d94e 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
+@@ -30,6 +30,7 @@ enum {
+ MLX5E_TC_FLOW_FLAG_FAILED = MLX5E_TC_FLOW_BASE + 9,
+ MLX5E_TC_FLOW_FLAG_SAMPLE = MLX5E_TC_FLOW_BASE + 10,
+ MLX5E_TC_FLOW_FLAG_USE_ACT_STATS = MLX5E_TC_FLOW_BASE + 11,
++ MLX5E_TC_FLOW_FLAG_PEER = MLX5E_TC_FLOW_BASE + 12,
+ };
+
+ struct mlx5e_tc_flow_parse_attr {
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+index 8b5a421a22a37..f3d4586e09e37 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+@@ -2165,7 +2165,8 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
+ if (mlx5e_is_eswitch_flow(flow)) {
+ struct mlx5_devcom_comp_dev *devcom = flow->priv->mdev->priv.eswitch->devcom;
+
+- if (!mlx5_devcom_for_each_peer_begin(devcom)) {
++ if (flow_flag_test(flow, PEER) ||
++ !mlx5_devcom_for_each_peer_begin(devcom)) {
+ mlx5e_tc_del_fdb_flow(priv, flow);
+ return;
+ }
+@@ -4605,6 +4606,7 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f,
+ else
+ in_mdev = priv->mdev;
+
++ flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_PEER);
+ parse_attr = flow->attr->parse_attr;
+ peer_flow = __mlx5e_add_fdb_flow(peer_priv, f, flow_flags,
+ parse_attr->filter_dev,
+--
+2.53.0
+
--- /dev/null
+From 9749bd46332b48554dead722d8c087cff5d127c9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 12:36:18 +0800
+Subject: net/ncsi: fix heap OOB read in NCSI_CMD_SEND_CMD payload length
+
+From: Henry Martin <bsdhenrymartin@gmail.com>
+
+[ Upstream commit afa58b7384913c8773d837acdb07b035690ec5d2 ]
+
+ncsi_send_cmd_nl() takes the number of bytes to copy from the
+attacker-controlled ncsi_pkt_hdr.length field of the in-band packet
+header, while the source buffer is the NCSI_ATTR_DATA netlink
+attribute whose readable size is nla_len() - sizeof(ncsi_pkt_hdr).
+The two length sources are never cross-checked: only
+nla_len() >= sizeof(struct ncsi_pkt_hdr) is enforced.
+
+With hdr->length set larger than the attribute payload (up to 65535
+against at most 2032 readable bytes), ncsi_cmd_handler_oem() copies
+past the end of the netlink attribute buffer with unsafe_memcpy(),
+leaking up to ~64KB of kernel heap memory into the transmitted NCSI
+command packet. The destination skb is sized by the declared payload,
+so the write side does not overflow - this is a pure OOB read /
+information leak, reachable with CAP_NET_ADMIN on systems with a
+registered NCSI device (e.g. OpenBMC on Aspeed BMC SoCs, where
+NET_NCSI=y is standard).
+
+Reject commands whose declared payload extends past the end of the
+data attribute.
+
+The issue was found by the autokbug dynamic kernel fuzzer at Tencent
+Yunding Lab.
+
+Fixes: 9771b8ccdfa6 ("net/ncsi: Extend NC-SI Netlink interface to allow user space to send NC-SI command")
+Reported-by: Henry Martin <bsdhenrymartin@gmail.com>
+Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>
+Link: https://patch.msgid.link/20260803043618.3210301-1-bsdhenrymartin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ncsi/ncsi-netlink.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/net/ncsi/ncsi-netlink.c b/net/ncsi/ncsi-netlink.c
+index 2f872d064396d..8cc538358f6a3 100644
+--- a/net/ncsi/ncsi-netlink.c
++++ b/net/ncsi/ncsi-netlink.c
+@@ -461,6 +461,10 @@ static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info)
+ nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN;
+ nca.info = info;
+ nca.payload = ntohs(hdr->length);
++ if (nca.payload > len - sizeof(*hdr)) {
++ ret = -EINVAL;
++ goto out_netlink;
++ }
+ nca.data = data + sizeof(*hdr);
+
+ ret = ncsi_xmit_cmd(&nca);
+--
+2.53.0
+
--- /dev/null
+From ec5380945f2ebfe6b5877cd547217640449a3228 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 18:20:06 -0400
+Subject: net/openvswitch: check Ethernet header length in key_extract()
+
+From: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+
+[ Upstream commit cf6f8b29befb92173659bcef6a441d274947bfae ]
+
+When a packet arrives on an ARPHRD_NONE device (e.g. TUN),
+ovs_flow_key_extract() trusts the user-provided skb->protocol field: if
+it is ETH_P_TEB, the packet is classified as MAC_PROTO_ETHERNET and
+key_extract() is called without ensuring the skb has ETH_HLEN (14) bytes
+of linear data. key_extract() unconditionally pulls 2 * ETH_ALEN bytes
+for MAC addresses and parse_ethertype() pulls 2 more, either of which
+triggers a kernel BUG in __skb_pull() when the linear area is too small.
+
+ kernel BUG at include/linux/skbuff.h:2848!
+ RIP: 0010:key_extract+0xa7e/0xd90 net/openvswitch/flow.c:933
+ ovs_flow_key_extract+0x419/0xa70
+ ovs_vport_receive+0x222/0x390
+ netdev_frame_hook+0x3e0/0x630
+ tun_get_user+0x2d0c/0x38e0
+
+Fixed by calling check_header() in key_extract() before accessing the
+Ethernet header.
+
+Fixes: 217ac77a3c25 ("openvswitch: allow L3 netdev ports")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Reviewed-by: Eelco Chaudron <echaudro@redhat.com>
+Signed-off-by: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Reviewed-by: Ilya Maximets <i.maximets@ovn.org>
+Link: https://patch.msgid.link/20260730222006.118652-1-blbllhy@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/flow.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
+index 66366982f6044..46c1d66aad8c3 100644
+--- a/net/openvswitch/flow.c
++++ b/net/openvswitch/flow.c
+@@ -889,8 +889,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ * Ethernet header
+ * @key: output flow key
+ *
+- * The caller must ensure that skb->len >= ETH_HLEN.
+- *
+ * Initializes @skb header fields as follows:
+ *
+ * - skb->mac_header: the L2 header.
+@@ -910,8 +908,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+ */
+ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+ {
+- struct ethhdr *eth;
+-
+ /* Flags are always used as part of stats */
+ key->tp.flags = 0;
+
+@@ -926,6 +922,13 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+ skb_reset_network_header(skb);
+ key->eth.type = skb->protocol;
+ } else {
++ struct ethhdr *eth;
++ int err;
++
++ err = check_header(skb, ETH_HLEN);
++ if (unlikely(err))
++ return err;
++
+ eth = eth_hdr(skb);
+ ether_addr_copy(key->eth.src, eth->h_source);
+ ether_addr_copy(key->eth.dst, eth->h_dest);
+--
+2.53.0
+
--- /dev/null
+From 4960ebb48afafc02410597756b261d6526305133 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 22:19:06 +0800
+Subject: net: prestera: validate firmware header length
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 8ae344eb540af3f457179b52bc6061416752485c ]
+
+prestera_fw_hdr_parse() reads the firmware header before checking
+that the firmware image contains that header.
+
+Reject images shorter than struct prestera_fw_header before decoding the
+magic and version fields.
+
+Fixes: 4c2703dfd7fabb ("net: marvell: prestera: Add PCI interface support")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Acked-by: Elad Nachman <enachman@marvell.com>
+Link: https://patch.msgid.link/20260731141500.1-prestera-v2-pengpeng@iscas.ac.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/marvell/prestera/prestera_pci.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/marvell/prestera/prestera_pci.c b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+index 2989a77e3b422..1ad0e62a8433b 100644
+--- a/drivers/net/ethernet/marvell/prestera/prestera_pci.c
++++ b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+@@ -684,6 +684,9 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw)
+ struct prestera_fw_header *hdr;
+ u32 magic;
+
++ if (fw->bin->size < sizeof(*hdr))
++ return -EINVAL;
++
+ hdr = (struct prestera_fw_header *)fw->bin->data;
+
+ magic = be32_to_cpu(hdr->magic_number);
+--
+2.53.0
+
--- /dev/null
+From 1eded2c917d84ec894633ae4e06fe12542acfa6b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 22:18:30 +0200
+Subject: net: qrtr: ns: Raise lookup limit to 128
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Łukasz Patron <priv.luk@gmail.com>
+
+[ Upstream commit 7fc1c937b6b37c77df4ba374c37435ab06a2e945 ]
+
+Current limit of 64 is not enough for Sony Xperia 10 VII (SM6475).
+
+After merging v6.6.142 into a downstream AOSP device, it's stuck on
+boot animation and following log spam can be observed in dmesg:
+
+E qrtr : ctrl_cmd_new_lookup(): QRTR client node exceeds max lookup limit!
+E qrtr : qrtr_ns_worker(): failed while handling packet from 1:16600
+
+No idea why it needs more than 64 client lookups, but it appears to
+work fine with 128 as it did when there were no limits.
+
+I don't really have a good way to investigate what it needs all
+these lookups for as most of the userspace is closed source.
+
+Fixes: 5640227d9a21 ("net: qrtr: ns: Limit the maximum number of lookups")
+Signed-off-by: Łukasz Patron <priv.luk@gmail.com>
+Link: https://patch.msgid.link/20260804201919.1148015-1-priv.luk@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/ns.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c
+index e5b2adb161d92..c5e7e01db2498 100644
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -78,7 +78,7 @@ struct qrtr_node {
+ */
+ #define QRTR_NS_MAX_NODES 512
+ #define QRTR_NS_MAX_SERVERS 256
+-#define QRTR_NS_MAX_LOOKUPS 64
++#define QRTR_NS_MAX_LOOKUPS 128
+
+ static u16 node_count;
+
+--
+2.53.0
+
--- /dev/null
+From 8d03a9d59e6587f199494059edf3527c1ecb4281 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 15:20:48 +0000
+Subject: net: remove WARN_ON_ONCE() from sk_mc_loop()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit b8a39a09ae4eaae04309e1e38ed6a1101d967496 ]
+
+sk_mc_loop() can be called for sockets that are neither AF_INET
+nor AF_INET6 (e.g. AF_PACKET sockets when sending packets via raw/packet
+socket over virtual devices such as VRF or ipvlan).
+
+In such cases, sk_family is not AF_INET/AF_INET6 and sk_mc_loop() falls
+through the switch statement and triggers WARN_ON_ONCE(1).
+
+Non-INET sockets do not support IP_MULTICAST_LOOP or IPV6_MULTICAST_LOOP
+options, so loopback should default to true without generating a warning.
+
+Fixes: f60e5990d9c1 ("ipv6: protect skb->sk accesses from recursive dereference inside the stack")
+Reported-by: syzbot+22c3218a6fa219e47321@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/6a72024c.13623e66.bdc14.0019.GAE@google.com/T/#u
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260804152048.2134341-1-edumazet@google.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/sock.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/net/core/sock.c b/net/core/sock.c
+index 5714436b08710..aaa3bb214eff9 100644
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -779,7 +779,6 @@ bool sk_mc_loop(const struct sock *sk)
+ return inet6_test_bit(MC6_LOOP, sk);
+ #endif
+ }
+- WARN_ON_ONCE(1);
+ return true;
+ }
+ EXPORT_SYMBOL(sk_mc_loop);
+--
+2.53.0
+
--- /dev/null
+From ee943a757bb754d3eec26d4d2ebe32773b706415 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 1 Aug 2026 08:56:32 -0400
+Subject: net/sched: cls_api: Always acquire rtnl_lock when destroying locked
+ classifiers
+
+From: Jamal Hadi Salim <jhs@mojatatu.com>
+
+[ Upstream commit a347304b2ca1a5377d5bd2d8a72e4b4f12afe648 ]
+
+Another challenge with unlocked filters.
+There is a short window in tc_new_tfilter where a tcf_proto can be found
+and briefly referenced by a totally unrelated, unlocked classifier's request
+and cause a race.
+
+Feng created a poc which created this race with two threads, one creating a
+u32 filter and other a flower filter in the same chain/prio:
+
+1. Both threads enter tc_new_tfilter, both find the chain empty, both
+ drop filter_chain_lock
+2. u32 finishes tcf_proto_create("u32") first, calls
+ tcf_chain_tp_insert_unique() -> inserts u32_tp into the chain
+3. flower finishes tcf_proto_create("flower") later, calls
+ tcf_chain_tp_insert_unique() -> tcf_chain_tp_find() now sees u32_tp
+ already there, takes a reference on it, destroys flower's own tp_new
+ and returns u32_tp to the caller.
+
+Flower then hits the kind mismatch check (because it requested for kind
+"flower" but tp->ops->kind is "u32") and goes through the errout path
+which calls tcf_proto_put() on u32_tp. If the u32 thread has already
+gone through its own errout (its change() call failed on the PoC's empty
+options) and dropped its create and insert refs, flower's put is the
+last one and drops u32_tp's refcnt to zero.
+
+At this point tp->ops->destroy() runs in a context that never took
+rtnl_lock. When that happens, it might cause a UAF like the following
+(illustrated by the PoC):
+
+[ +0.000710] BUG: KASAN: slab-use-after-free in u32_init (net/sched/cls_u32.c:393)
+[ +0.000281] Read of size 8 at addr ffff888120022f00 by task poc_feng_xue/524
+
+ Call Trace:
+ u32_init (net/sched/cls_u32.c:393)
+ tc_new_tfilter (net/sched/cls_api.c:2378)
+
+ Allocated by task 526:
+ u32_init (net/sched/cls_u32.c:378)
+ tc_new_tfilter (net/sched/cls_api.c:2378)
+
+ Freed by task 522:
+ kfree
+ u32_destroy (net/sched/cls_u32.c:662)
+ tcf_proto_destroy (net/sched/cls_api.c:446)
+ tcf_proto_put (net/sched/cls_api.c:459)
+ tc_new_tfilter (net/sched/cls_api.c:2459)
+
+Fix this by having tcf_proto_destroy() take rtnl_lock around
+tp->ops->destroy() for locked classifiers whenever rtnl is not held.
+
+To explain why I used a temp variable "not_lockless" I'd like to point to a
+semi-related note on rtnl_held vs TCF_PROTO_OPS_DOIT_UNLOCKED (adding here
+for future cleanup if deemed necessary):
+The rtnl_held parameter and the TCF_PROTO_OPS_DOIT_UNLOCKED flag are
+redundant sources of truth for whether rtnl_lock is held. Among the nine
+classifier destroy(..rtnl_held..) callbacks, only flower consults the
+rtnl_held parameter which it propagates to tc_setup_cb_destroy()
+and tc_setup_cb_call(). The other eight (u32, flow, bpf, cgroup, route, basic,
+fw, mall) ignore it entirely;-> those that call tc_setup_cb_destroy()
+(u32, bpf, mall) hardcode true always instead of forwarding the parameter.
+
+A future cleanup should remove the rtnl_held parameter from the destroy callback
+signature entirely and have callers rely solely on their knowledge whether
+they are running in an unlocked context.
+
+Fixes: 12db03b65c2b ("net: sched: extend proto ops to support unlocked classifiers")
+Reported-by: Feng Xue <feng.xue@outlook.com>
+Tested-by: Victor Nogueira <victor@mojatatu.com>
+Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260801125632.360365-1-jhs@mojatatu.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_api.c | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index fee4524adc98e..4e6a2812a4f32 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -443,7 +443,22 @@ static void tcf_chain_put(struct tcf_chain *chain);
+ static void tcf_proto_destroy(struct tcf_proto *tp, bool rtnl_held,
+ bool sig_destroy, struct netlink_ext_ack *extack)
+ {
+- tp->ops->destroy(tp, rtnl_held, extack);
++ /* A locked classifier's destroy callback (e.g. u32_destroy) uses
++ * rtnl_dereference() and mutates shared structures (e.g. the
++ * tc_u_common hash list) that are only safe under rtnl_lock. When an
++ * unlocked classifier's request (e.g. flower on ingress) loses the
++ * tcf_chain_tp_insert_unique() race and ends up dropping the last
++ * reference on a locked classifier's proto, destroy() would run
++ * without rtnl held. Take it here in that case.
++ */
++ bool not_lockless = !rtnl_held &&
++ !(tp->ops->flags & TCF_PROTO_OPS_DOIT_UNLOCKED);
++
++ if (not_lockless)
++ rtnl_lock();
++ tp->ops->destroy(tp, rtnl_held || not_lockless, extack);
++ if (not_lockless)
++ rtnl_unlock();
+ tcf_proto_count_usesw(tp, false);
+ if (sig_destroy)
+ tcf_proto_signal_destroyed(tp->chain, tp);
+--
+2.53.0
+
--- /dev/null
+From 2259bde902cae4fac469ed19b559baf2e6509bf4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 05:44:11 -0400
+Subject: net/sched: cls_route: fix fastmap use-after-free on filter
+
+From: Jamal Hadi Salim <jhs@mojatatu.com>
+
+[ Upstream commit 47d7f7051253bdc02b1d245d87e38f16d31a74df ]
+
+The route4 classifier maintains a 16-slot fastmap cache that stores raw
+struct route4_filter pointers indexed by (id, iif). The reader
+(route4_classify) populates this cache via route4_set_fastmap() for every
+classified packet that hits a filter. The writer (route4_delete,
+route4_change) clears the cache via route4_reset_fastmap() before
+RCU-deferred kfree of the filter.
+
+This creates a UAF race:
+ 1. Reader walks the RCU-protected bucket chain, finds filter f
+ 2. Writer unlinks f, calls route4_reset_fastmap(), then tcf_queue_work()
+ 3. Reader calls route4_set_fastmap() and writes f into the cache
+ *after* the writer's reset, caching a pointer about to be freed
+ 4. After the RCU grace period, kfree(f) executes
+ 5. Next classified packet on the same (id, iif) tuple hits the stale
+ fastmap entry and reads f->res from freed memory
+
+Reproduced with an mdelay(100) accelerator in route4_set_fastmap() and a
+concurrent add/delete stress test (provided by both zdi and Santosh).
+Both triggered KASAN slab-use-after-free reports in the route4 fastmap
+paths.
+
+Fix:
+Introduce a per-filter boolean dying flag to suppress stale fastmap
+republishing by in-flight readers.
+
+Fixes: 1109c00547fc ("net: sched: RCU cls_route")
+Reported-by: zdi-disclosures@trendmicro.com
+Reported-by: Santosh Kalluri <santosh.kalluri129@gmail.com>
+Suggested-by: Paolo Abeni <pabeni@redhat.com>
+Tested-by: Victor Nogueira <victor@mojatatu.com>
+Tested-by: Santosh Kalluri <santosh.kalluri129@gmail.com>
+Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260729094411.46257-1-jhs@mojatatu.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_route.c | 35 ++++++++++++++++++++++++++---------
+ 1 file changed, 26 insertions(+), 9 deletions(-)
+
+diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
+index bd6f945bd3883..eded7aacd3f70 100644
+--- a/net/sched/cls_route.c
++++ b/net/sched/cls_route.c
+@@ -52,6 +52,7 @@ struct route4_filter {
+ struct tcf_result res;
+ struct tcf_exts exts;
+ u32 handle;
++ bool dying;
+ struct route4_bucket *bkt;
+ struct tcf_proto *tp;
+ struct rcu_work rwork;
+@@ -66,9 +67,11 @@ static inline int route4_fastmap_hash(u32 id, int iif)
+
+ static DEFINE_SPINLOCK(fastmap_lock);
+ static void
+-route4_reset_fastmap(struct route4_head *head)
++route4_reset_fastmap(struct route4_head *head, struct route4_filter *f)
+ {
+ spin_lock_bh(&fastmap_lock);
++ if (f)
++ f->dying = true;
+ memset(head->fastmap, 0, sizeof(head->fastmap));
+ spin_unlock_bh(&fastmap_lock);
+ }
+@@ -81,9 +84,11 @@ route4_set_fastmap(struct route4_head *head, u32 id, int iif,
+
+ /* fastmap updates must look atomic to aling id, iff, filter */
+ spin_lock_bh(&fastmap_lock);
+- head->fastmap[h].id = id;
+- head->fastmap[h].iif = iif;
+- head->fastmap[h].filter = f;
++ if (f == ROUTE4_FAILURE || !f->dying) {
++ head->fastmap[h].id = id;
++ head->fastmap[h].iif = iif;
++ head->fastmap[h].filter = f;
++ }
+ spin_unlock_bh(&fastmap_lock);
+ }
+
+@@ -297,6 +302,13 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
+ next = rtnl_dereference(f->next);
+ RCU_INIT_POINTER(b->ht[h2], next);
+ tcf_unbind_filter(tp, &f->res);
++ /* Mark the filter dying under fastmap_lock so
++ * any in-flight reader that still holds it
++ * will skip the republish in route4_set_fastmap().
++ */
++ spin_lock_bh(&fastmap_lock);
++ f->dying = true;
++ spin_unlock_bh(&fastmap_lock);
+ if (tcf_exts_get_net(&f->exts))
+ route4_queue_work(f);
+ else
+@@ -307,6 +319,11 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
+ kfree_rcu(b, rcu);
+ }
+ }
++
++ /* All filters are unlinked and marked dying, so no in-flight
++ * reader can republish a stale entry after this reset.
++ */
++ route4_reset_fastmap(head, NULL);
+ kfree_rcu(head, rcu);
+ }
+
+@@ -334,11 +351,11 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,
+ /* unlink it */
+ RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
+
+- /* Remove any fastmap lookups that might ref filter
+- * notice we unlink'd the filter so we can't get it
+- * back in the fastmap.
++ /* Clear any fastmap entries that may ref this filter and
++ * mark it dying so in-flight readers can't republish it
++ * after the reset.
+ */
+- route4_reset_fastmap(head);
++ route4_reset_fastmap(head, f);
+
+ /* Delete it */
+ tcf_unbind_filter(tp, &f->res);
+@@ -558,7 +575,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
+ }
+ }
+
+- route4_reset_fastmap(head);
++ route4_reset_fastmap(head, fold);
+ *arg = f;
+ if (fold) {
+ tcf_unbind_filter(tp, &fold->res);
+--
+2.53.0
+
--- /dev/null
+From aef9fc0afb86114783e6f60c76c7330ea59b6ec3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 21:14:16 +0200
+Subject: net/sched: sch_cake: drop WARN_ON(1) for malformed packets in ACK
+ filter
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Toke Høiland-Jørgensen <toke@toke.dk>
+
+[ Upstream commit 2a33516f9ef59ad11844d4fc152f889449b5daf3 ]
+
+The sch_cake ACK filter parses packets to find the TCP header and filter
+duplicated ACKs if the flow is backlogged. The parsing code contains a
+WARN_ON(1) which can be triggered by a malformed IP header in certain
+cases. Depending on the system configuration, this leads either to
+either spamming dmesg with warnings, or a panic if panic_on_warn is set.
+
+The code already correctly skips the offending packet in the branch that
+triggers the warning, so the WARN_ON itself doesn't really serve any
+purpose. So just drop it altogether to avoid the inconvenient side
+effects.
+
+Fixes: 8b7138814f29 ("sch_cake: Add optional ACK filter")
+Reported-by: Zhiling Zou <zhilinz@nebusec.ai>
+Reported-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
+Link: https://patch.msgid.link/20260729191417.45665-1-toke@toke.dk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_cake.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c
+index 8965fe252471c..755c42c32bcf3 100644
+--- a/net/sched/sch_cake.c
++++ b/net/sched/sch_cake.c
+@@ -1287,7 +1287,6 @@ static struct sk_buff *cake_ack_filter(struct cake_sched_data *q,
+
+ seglen = ipv6_payload_len(skb, ipv6h_check);
+ } else {
+- WARN_ON(1); /* shouldn't happen */
+ continue;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From a24c997bfac0ab87cf2fb25c57c2a6a350619482 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:01:53 +0200
+Subject: net/smc: fix qentry overwrite for CONFIRM_LINK and ADD_LINK_CONT in
+ smc_llc_event_handler()
+
+From: Mahanta Jambigi <mjambigi@linux.ibm.com>
+
+[ Upstream commit 976245094925bab9bc39366b2e9ab44ffcde61d0 ]
+
+The SMC_LLC_CONFIRM_LINK / SMC_LLC_ADD_LINK_CONT branch in
+smc_llc_event_handler() stores an incoming qentry into the local LLC flow
+without first checking whether a qentry is already pending. If a malicious or
+buggy peer sends a second CONFIRM_LINK or ADD_LINK_CONT request while a flow is
+active and flow->qentry is already set, smc_llc_flow_qentry_set() overwrites the
+pointer without freeing the previous allocation, leaking one kmalloc-96 object
+per spurious message.
+
+The sibling SMC_LLC_DELETE_LINK branch already has the correct !flow->qentry
+guard. Apply the same guard to the CONFIRM_LINK/ADD_LINK_CONT branch so that a
+duplicate message when qentry is already occupied falls through to break and is
+freed by the kfree(qentry) at the out: label, rather than silently leaking the
+existing allocation.
+
+The response direction (smc_llc_rx_response()) is unaffected: it already guards
+with flow->qentry at the equivalent site and drops duplicate responses
+correctly.
+
+Fixes: 0fb0b02bd6fd ("net/smc: adapt SMC client code to use the LLC flow")
+Signed-off-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
+Reviewed-by: Hidayath Khan <hidayath@linux.ibm.com>
+Reviewed-by: Sidraya Jayagond <sidraya@linux.ibm.com>
+Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
+Link: https://patch.msgid.link/20260729130153.970800-1-mjambigi@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/smc_llc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c
+index 954b2ff1815c2..aa6d83af55eda 100644
+--- a/net/smc/smc_llc.c
++++ b/net/smc/smc_llc.c
+@@ -1927,7 +1927,8 @@ static void smc_llc_event_handler(struct smc_llc_qentry *qentry)
+ return;
+ case SMC_LLC_CONFIRM_LINK:
+ case SMC_LLC_ADD_LINK_CONT:
+- if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) {
++ if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE &&
++ !lgr->llc_flow_lcl.qentry) {
+ /* a flow is waiting for this message */
+ smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry);
+ wake_up(&lgr->llc_msg_waiter);
+--
+2.53.0
+
--- /dev/null
+From 9b5b62d248d46973973c30491047e09b4e2c4e44 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 09:07:01 +0200
+Subject: net/smc: fix TOCTOU race between smc_listen_out() and listener close
+
+From: Sidraya Jayagond <sidraya@linux.ibm.com>
+
+[ Upstream commit 185a4caeecabc150106deda1da170b09f2ad803f ]
+
+smc_listen_out() reads lsmc->sk.sk_state without the listener lock,
+then acquires lock_sock_nested() only after the check passes. This
+opens a window where smc_close_active() can transition the listener
+to SMC_CLOSED, call smc_close_cleanup_listen() to drain the accept
+queue, and release the lock, all between the lockless read and the
+delayed lock acquisition:
+
+ smc_listen_work (smc_hs_wq) smc_close_active()
+ ------------------------------- -------------------------
+ release_sock(child)
+ if (sk_state == SMC_LISTEN) TRUE
+ lock_sock(listener)
+ sk_state = SMC_CLOSED
+ smc_close_cleanup_listen()
+ release_sock(listener)
+ flush_work(tcp_listen_work)
+ lock_sock_nested(listener)
+ smc_accept_enqueue(listener, child) /* child enqueued on dead listener */
+
+smc_close_active() flushes only tcp_listen_work. Work items already
+dispatched onto smc_hs_wq for the CLC handshake continue running
+unguarded. smc_accept_enqueue() takes a sock_hold() on the child that
+is never released, so the child smc_sock, its clcsock, and the
+reference all leak. A remote peer that opens TCP connections while the
+server calls close() can exhaust kernel memory.
+
+Move lock_sock_nested() to before the sk_state check so that the test
+and the enqueue are atomic under the listener lock.
+
+Fixes: fd57770dd198 ("net/smc: wait for pending work before clcsock release_sock")
+Reviewed-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
+Signed-off-by: Sidraya Jayagond <sidraya@linux.ibm.com>
+Reviewed-by: Breno Leitao <leitao@debian.org>
+Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
+Link: https://patch.msgid.link/20260803070701.126339-1-sidraya@linux.ibm.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/af_smc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
+index b5db69073e20f..00403175b7406 100644
+--- a/net/smc/af_smc.c
++++ b/net/smc/af_smc.c
+@@ -1931,11 +1931,12 @@ static void smc_listen_out(struct smc_sock *new_smc)
+ atomic_dec(&lsmc->queued_smc_hs);
+
+ release_sock(newsmcsk); /* lock in smc_listen_work() */
++ lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
+ if (lsmc->sk.sk_state == SMC_LISTEN) {
+- lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
+ smc_accept_enqueue(&lsmc->sk, newsmcsk);
+ release_sock(&lsmc->sk);
+ } else { /* no longer listening */
++ release_sock(&lsmc->sk);
+ smc_close_non_accepted(newsmcsk);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 864caafd74b5177920c7d255f952d787166475b1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 11:51:56 +0200
+Subject: net: stmmac: resume PHY before hardware setup when opening the
+ interface
+
+From: Stefan Agner <stefan@agner.ch>
+
+[ Upstream commit 06232cb44bc8e81adc2f1d40a01bed830b607ea2 ]
+
+Since the referenced commit, changing the MTU on a running interface no
+longer disconnects and reconnects the PHY; __stmmac_release() merely
+stops phylink, which also suspends the PHY (BMCR power-down) when WoL
+is not enabled. __stmmac_open() then performs the DMA software reset in
+stmmac_hw_setup() before phylink_start() resumes the PHY again.
+
+IEEE 802.3 22.2.4.1.5 allows a PHY to stop its receive clock while
+powered down, and stmmac requires a running receive clock for the DMA
+software reset to complete (the phylink config sets mac_requires_rxc).
+On such setups, e.g. the RK3566-based Home Assistant Green with an
+RTL8211F-VD PHY in RGMII mode, any runtime MTU change now times out and
+leaves the interface dead:
+
+ rk_gmac-dwmac fe010000.ethernet end0: Failed to reset the dma
+ rk_gmac-dwmac fe010000.ethernet end0: stmmac_hw_setup: DMA engine initialization failed
+ rk_gmac-dwmac fe010000.ethernet end0: __stmmac_open: Hw setup failed
+ rk_gmac-dwmac fe010000.ethernet end0: failed reopening the interface after MTU change
+
+In the field this is triggered by NetworkManager applying an MTU while
+activating the connection, breaking networking entirely. The same
+regression has also been reported on i.MX8MP and reproduced on SoCFPGA
+based systems.
+
+Resume the PHY in __stmmac_open() before the hardware setup, making it
+the counterpart of the phylink_stop() in __stmmac_release(), like
+stmmac_resume() already does for the same reason. phylink_start() also
+resumes the PHY, but only after stmmac_hw_setup(), and it cannot be
+moved before the hardware setup since it may bring the link up
+immediately from a workqueue, racing with the initialization (see the
+comment in stmmac_resume()). For the regular ndo_open path the PHY has
+just been attached and is not suspended, in which case
+phylink_prepare_resume() does nothing.
+
+Fixes: db299a0c09e9 ("net: stmmac: move PHY handling out of __stmmac_open()/release()")
+Link: https://github.com/home-assistant/operating-system/issues/4858
+Tested-by: Alexander Stein <alexander.stein@ew.tq-group.com>
+Signed-off-by: Stefan Agner <stefan@agner.ch>
+Tested-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Link: https://patch.msgid.link/20260803095156.132827-1-stefan@agner.ch
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index b7e3f652501e4..84e783f87b3d0 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -4132,6 +4132,15 @@ static int __stmmac_open(struct net_device *dev,
+ dma_conf->tx_queue[i].tbs = priv->dma_conf.tx_queue[i].tbs;
+ memcpy(&priv->dma_conf, dma_conf, sizeof(*dma_conf));
+
++ /* The PHY is suspended when the interface is reopened without
++ * disconnecting the PHY, e.g. on MTU change. IEEE 802.3 allows PHYs
++ * to stop their receive clock while powered down, but the DMA
++ * software reset in stmmac_hw_setup() requires a running receive
++ * clock, and phylink_start() below resumes the PHY only after the
++ * hardware setup. Resume a suspended PHY here first.
++ */
++ phylink_prepare_resume(priv->phylink);
++
+ stmmac_reset_queues_param(priv);
+
+ ret = stmmac_hw_setup(dev);
+--
+2.53.0
+
--- /dev/null
+From f6cef5121c15efac07e50e2bc3bcdd99740bb8e8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 14:38:50 +0000
+Subject: net: thunderbolt: Tear down DMA paths before stopping the rings
+
+From: Fan XinRan <shinjiangjiang@gmail.com>
+
+[ Upstream commit 68bf02b6b4ad3f748c6db71fd77b6c0402d252f4 ]
+
+tbnet_tear_down() stops both rings and frees their frame buffers before
+calling tb_xdomain_disable_paths(). tb_ring_stop() zeroes the ring's
+descriptor base and tbnet_free_buffers() unmaps and frees the pages the
+frames sit in, so by the time __tb_path_deactivate_hop() polls the hop's
+'pending' bit, anything still in flight has nowhere to drain to.
+
+The teardown sequence has been in this order since the driver was added.
+The setup path has not: commit ff7cd07f3064 ("net: thunderbolt: Enable
+DMA paths only after rings are enabled") moved the path enable to the end
+of tbnet_connected_work() and documented why:
+
+ /* Both logins successful so enable the rings, high-speed DMA
+ * paths and start the network device queue.
+ *
+ * Note we enable the DMA paths last to make sure we have primed
+ * the Rx ring before any incoming packets are allowed to
+ * arrive.
+ */
+
+Teardown was never updated to match, so the rings and the paths now come
+down in the same order they go up instead of in reverse.
+
+On an ASMedia ASM4242 host router the 'pending' bit then never clears:
+every teardown burns the full 500 ms timeout and
+__tb_path_deactivate_hop() returns -ETIMEDOUT. Raising the timeout to
+5 s does not help, so the hop is not slow to drain, it never drains
+at all.
+
+The failure is invisible above the thunderbolt core.
+__tb_path_deactivate_hops() is void and only calls tb_port_warn();
+tb_path_deactivate(), tb_tunnel_deactivate() and
+__tb_disconnect_xdomain_paths() are void as well, and
+tb_disconnect_xdomain_paths() ends in an unconditional "return 0". So
+tb_xdomain_disable_paths() reports success and the netdev_warn() below
+it never fires. Repeated teardowns eventually take the XDomain control
+channel down, after which the peer node is gone and only a power cycle
+brings the controller back.
+
+Deactivating the paths first fixes it. Measured with kretprobes on a
+stock v6.17 tree with no other patches applied, on a link that was up
+and had just carried traffic:
+
+ before: __tb_path_deactivate_hop() returns 0 for the first hop, then
+ -ETIMEDOUT for the second 500335 us later
+ after: 0 for both, 525 us apart
+
+Alternating the two orderings ABBA over three load levels, four
+teardowns per arm: every teardown failed before the change (21 of 21
+that ran), none failed after (0 of 24). The before arms ran short
+because the link died partway through. The same split shows up when
+the interface is enslaved to a bond instead of just brought down, which
+is how I ran into this in the first place. Throughput and latency after
+the change are unchanged.
+
+Hosts whose routers drain the hop despite the stale descriptor base see
+no functional difference, since the paths end up deactivated either way.
+
+Fixes: e69b6c02b4c3 ("net: Add support for networking over Thunderbolt cable")
+Signed-off-by: Fan XinRan <shinjiangjiang@gmail.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Link: https://patch.msgid.link/20260803-b4-tbnet-teardown-v2-1-27de6a13ca2d@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/thunderbolt/main.c | 20 +++++++++++++++-----
+ 1 file changed, 15 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c
+index 0cd98496d135d..fb569c0abf8e6 100644
+--- a/drivers/net/thunderbolt/main.c
++++ b/drivers/net/thunderbolt/main.c
+@@ -390,11 +390,16 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)
+ break;
+ }
+
+- tb_ring_stop(net->rx_ring.ring);
+- tb_ring_stop(net->tx_ring.ring);
+- tbnet_free_buffers(&net->rx_ring);
+- tbnet_free_buffers(&net->tx_ring);
+-
++ /* Tear the paths down before stopping the rings. This mirrors
++ * tbnet_connected_work(), which enables the paths last so the
++ * Rx ring is primed before packets can arrive. Stopping a
++ * ring zeroes its descriptor base and tbnet_free_buffers()
++ * unmaps and frees the frame buffers, leaving anything still
++ * in flight with nowhere to drain to;
++ * __tb_path_deactivate_hop() then waits for the hop's
++ * 'pending' bit, which on some host routers never clears in
++ * that state.
++ */
+ ret = tb_xdomain_disable_paths(net->xd,
+ net->local_transmit_path,
+ net->tx_ring.ring->hop,
+@@ -403,6 +408,11 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout)
+ if (ret)
+ netdev_warn(net->dev, "failed to disable DMA paths\n");
+
++ tb_ring_stop(net->rx_ring.ring);
++ tb_ring_stop(net->tx_ring.ring);
++ tbnet_free_buffers(&net->rx_ring);
++ tbnet_free_buffers(&net->tx_ring);
++
+ tb_xdomain_release_in_hopid(net->xd, net->remote_transmit_path);
+ net->remote_transmit_path = 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From 2ab0a5f88709cd8032896e9952f0b3ee7b223f17 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 20:38:50 +0200
+Subject: netfilter: ipset: switch ext_size to atomic64_t
+
+From: Jozsef Kadlecsik <kadlec@netfilter.org>
+
+[ Upstream commit 712a6f545c359b427daa9a5a782e30d2f8331e25 ]
+
+The hash types do not acquire set->lock, they use 'region locking' where
+only part of the hash table is locked. Parallel inserts and deletes are
+possible and CPUs can race on ->ext_size update. Switch to atomic64_t.
+
+This leaves another bug unresolved: there still can be a race on
+comment extension re-init. This will be handled in a later commit
+when converting to rhashtable backend.
+
+Fixes: f66ee0410b1c ("netfilter: ipset: Fix "INFO: rcu detected stall in hash_xxx" reports")
+Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/netfilter/ipset/ip_set.h | 2 +-
+ net/netfilter/ipset/ip_set_bitmap_gen.h | 4 ++--
+ net/netfilter/ipset/ip_set_core.c | 6 +++---
+ net/netfilter/ipset/ip_set_hash_gen.h | 2 +-
+ net/netfilter/ipset/ip_set_list_set.c | 4 ++--
+ 5 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
+index b98331572ad29..cadae9b2578f1 100644
+--- a/include/linux/netfilter/ipset/ip_set.h
++++ b/include/linux/netfilter/ipset/ip_set.h
+@@ -273,7 +273,7 @@ struct ip_set {
+ /* Number of elements (vs timeout) */
+ u32 elements;
+ /* Size of the dynamic extensions (vs timeout) */
+- size_t ext_size;
++ atomic64_t ext_size;
+ /* Element data size */
+ size_t dsize;
+ /* Offsets to extensions in elements */
+diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h
+index bb9b5bed10e19..226fdf17b6832 100644
+--- a/net/netfilter/ipset/ip_set_bitmap_gen.h
++++ b/net/netfilter/ipset/ip_set_bitmap_gen.h
+@@ -77,7 +77,7 @@ mtype_flush(struct ip_set *set)
+ mtype_ext_cleanup(set);
+ bitmap_zero(map->members, map->elements);
+ set->elements = 0;
+- set->ext_size = 0;
++ atomic64_set(&set->ext_size, 0);
+ }
+
+ /* Calculate the actual memory size of the set data */
+@@ -93,7 +93,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
+ {
+ const struct mtype *map = set->data;
+ struct nlattr *nested;
+- size_t memsize = mtype_memsize(map, set->dsize) + set->ext_size;
++ size_t memsize = mtype_memsize(map, set->dsize) + atomic64_read(&set->ext_size);
+
+ nested = nla_nest_start(skb, IPSET_ATTR_DATA);
+ if (!nested)
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index 6cfad152d7d1b..822a53a7f502a 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -350,7 +350,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
+ size_t len = ext->comment ? strlen(ext->comment) : 0;
+
+ if (unlikely(c)) {
+- set->ext_size -= sizeof(*c) + strlen(c->str) + 1;
++ atomic64_sub(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
+ rcu_assign_pointer(comment->c, NULL);
+ kfree_rcu(c, rcu);
+ }
+@@ -362,7 +362,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
+ if (unlikely(!c))
+ return;
+ strscpy(c->str, ext->comment, len + 1);
+- set->ext_size += sizeof(*c) + strlen(c->str) + 1;
++ atomic64_add(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
+ rcu_assign_pointer(comment->c, c);
+ }
+ EXPORT_SYMBOL_GPL(ip_set_init_comment);
+@@ -392,7 +392,7 @@ ip_set_comment_free(struct ip_set *set, void *ptr)
+ c = rcu_dereference_protected(comment->c, 1);
+ if (unlikely(!c))
+ return;
+- set->ext_size -= sizeof(*c) + strlen(c->str) + 1;
++ atomic64_sub(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
+ rcu_assign_pointer(comment->c, NULL);
+ kfree_rcu(c, rcu);
+ }
+diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
+index a3ed683cc47e7..3072b4e288537 100644
+--- a/net/netfilter/ipset/ip_set_hash_gen.h
++++ b/net/netfilter/ipset/ip_set_hash_gen.h
+@@ -1288,7 +1288,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
+ rcu_read_lock_bh();
+ t = rcu_dereference_bh(h->table);
+ mtype_ext_size(set, &elements, &ext_size);
+- memsize = mtype_ahash_memsize(h, t) + ext_size + set->ext_size;
++ memsize = mtype_ahash_memsize(h, t) + ext_size + atomic64_read(&set->ext_size);
+ htable_bits = t->htable_bits;
+ rcu_read_unlock_bh();
+
+diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
+index 1cef84f15e8c7..ca3ef9479e838 100644
+--- a/net/netfilter/ipset/ip_set_list_set.c
++++ b/net/netfilter/ipset/ip_set_list_set.c
+@@ -421,7 +421,7 @@ list_set_flush(struct ip_set *set)
+ list_for_each_entry_safe(e, n, &map->members, list)
+ list_set_del(set, e);
+ set->elements = 0;
+- set->ext_size = 0;
++ atomic64_set(&set->ext_size, 0);
+ }
+
+ static void
+@@ -455,7 +455,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
+ {
+ const struct list_set *map = set->data;
+ struct nlattr *nested;
+- size_t memsize = list_set_memsize(map, set->dsize) + set->ext_size;
++ size_t memsize = list_set_memsize(map, set->dsize) + atomic64_read(&set->ext_size);
+
+ nested = nla_nest_start(skb, IPSET_ATTR_DATA);
+ if (!nested)
+--
+2.53.0
+
--- /dev/null
+From b5ebd4fc676c67f1e80fe03cfcf0836179695c00 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 09:33:28 +0000
+Subject: netfilter: nf_flow_table: drop existing skb dst before
+ skb_dst_set_noref()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 8aecf0bbcc72605592134c917c222207d8f63ab0 ]
+
+Incoming skbs passing through netfilter flowtable offload hooks (or XFRM
+offload path) might already carry a ref-counted dst_entry assigned during
+earlier RX or routing steps.
+
+Calling skb_dst_set_noref() when skb already holds a ref-counted dst
+overwrites skb->_skb_refdst, leaking the previous dst_entry reference
+count and triggering a DEBUG_NET_WARN_ON_ONCE assertion in
+skb_dst_check_unset():
+
+ WARNING: at skb_dst_check_unset include/linux/skbuff.h:1170
+ WARNING: at skb_dst_set_noref include/linux/skbuff.h:1234
+ WARNING: at nf_flow_offload_ip_hook+0xf6c/0x2b60 net/netfilter/nf_flow_table_ip.c:864
+
+Drop any existing dst_entry reference with skb_dst_drop(skb) before
+setting the non-referenced flowtable destination.
+
+Fixes: 2a79fd3908ac ("netfilter: nf_flow_table: attach dst to skbs")
+Reported-by: syzbot+76d4e3a055aec3b007ec@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/6a71b141.9511d2ce.1fc5b9.033b.GAE@google.com/T/#u
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Link: https://patch.msgid.link/20260804093328.1831847-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_flow_table_ip.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
+index 0b78decce8a9b..c9e332fafcb5c 100644
+--- a/net/netfilter/nf_flow_table_ip.c
++++ b/net/netfilter/nf_flow_table_ip.c
+@@ -310,6 +310,7 @@ static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb,
+ struct dst_entry *dst)
+ {
+ skb_orphan(skb);
++ skb_dst_drop(skb);
+ skb_dst_set_noref(skb, dst);
+ dst_output(state->net, state->sk, skb);
+ return NF_STOLEN;
+@@ -861,6 +862,7 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
+ return NF_DROP;
+ }
+ xmit.dest = neigh->ha;
++ skb_dst_drop(skb);
+ skb_dst_set_noref(skb, &rt->dst);
+ break;
+ case FLOW_OFFLOAD_XMIT_DIRECT:
+@@ -1178,6 +1180,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
+ return NF_DROP;
+ }
+ xmit.dest = neigh->ha;
++ skb_dst_drop(skb);
+ skb_dst_set_noref(skb, &rt->dst);
+ break;
+ case FLOW_OFFLOAD_XMIT_DIRECT:
+--
+2.53.0
+
--- /dev/null
+From 557122a1aabb258ed59ba1081371c35506308d86 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 30 Jun 2026 15:39:45 -0400
+Subject: NFS: Decrement refcounts if allocating nfs_free_stateid_data fails
+
+From: Anna Schumaker <anna.schumaker@hammerspace.com>
+
+[ Upstream commit 4aeb63d5ac2dba2a474e7b64d60776d9dd1c6cd2 ]
+
+I noticed that we were immediately exiting this function if the
+allocation fails, leaving the client and server object refcounts bumped.
+Fix this by creating a common exit point to clean up dangling
+references.
+
+Fixes: 576acc259146 ("nfs4: take a reference on the nfs_client when running FREE_STATEID")
+Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/nfs4proc.c | 20 +++++++++++++-------
+ 1 file changed, 13 insertions(+), 7 deletions(-)
+
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index bea00343f09b1..6142a7daf983d 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -10369,21 +10369,22 @@ static int nfs41_free_stateid(struct nfs_server *server,
+ struct nfs_free_stateid_data *data;
+ struct rpc_task *task;
+ struct nfs_client *clp = server->nfs_client;
++ int ret = -EIO;
+
+ if (!refcount_inc_not_zero(&clp->cl_count))
+- return -EIO;
+- if (!nfs_sb_active(server->super)) {
+- nfs_put_client(clp);
+- return -EIO;
+- }
++ return ret;
++ if (!nfs_sb_active(server->super))
++ goto out_put_clp;
+
+ nfs4_state_protect(clp, NFS_SP4_MACH_CRED_STATEID,
+ &task_setup.rpc_client, &msg);
+
+ dprintk("NFS call free_stateid %p\n", stateid);
+ data = kmalloc_obj(*data);
+- if (!data)
+- return -ENOMEM;
++ if (!data) {
++ ret = -ENOMEM;
++ goto out_put_server;
++ }
+ data->server = server;
+ nfs4_stateid_copy(&data->args.stateid, stateid);
+
+@@ -10399,6 +10400,11 @@ static int nfs41_free_stateid(struct nfs_server *server,
+ rpc_put_task(task);
+ stateid->type = NFS4_FREED_STATEID_TYPE;
+ return 0;
++out_put_server:
++ nfs_sb_deactive(server->super);
++out_put_clp:
++ nfs_put_client(clp);
++ return ret;
+ }
+
+ static void
+--
+2.53.0
+
--- /dev/null
+From f85aa6110cf116d3a602a9a605740ba8a021c012 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 30 Jun 2026 14:31:00 -0400
+Subject: NFS: Pin the 'struct nfs_server' during a FREE_STATEID call
+
+From: Anna Schumaker <anna.schumaker@hammerspace.com>
+
+[ Upstream commit cf616096a0f3a2b60f7d68b6b39674a6867ded9c ]
+
+Dan Aloni reports that he was able to hit a use-after-free bug if a
+FREE_STATEID operation gets delayed for whatever reason. Fix this by
+bumping the refcount of the 'struct nfs_server' object for the duration
+of the FREE_STATEID so it doesn't get cleaned up from underneath us
+while operations are still in flight.
+
+Reported-by: Dan Aloni <dan.aloni@vastdata.com>
+Fixes: 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call")
+Tested-by: Dan Aloni <dan.aloni@vastdata.com>
+Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/nfs4proc.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index 4db27f4eb01e9..bea00343f09b1 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -10330,6 +10330,7 @@ static void nfs41_free_stateid_release(void *calldata)
+ struct nfs_free_stateid_data *data = calldata;
+ struct nfs_client *clp = data->server->nfs_client;
+
++ nfs_sb_deactive(data->server->super);
+ nfs_put_client(clp);
+ kfree(calldata);
+ }
+@@ -10371,6 +10372,10 @@ static int nfs41_free_stateid(struct nfs_server *server,
+
+ if (!refcount_inc_not_zero(&clp->cl_count))
+ return -EIO;
++ if (!nfs_sb_active(server->super)) {
++ nfs_put_client(clp);
++ return -EIO;
++ }
+
+ nfs4_state_protect(clp, NFS_SP4_MACH_CRED_STATEID,
+ &task_setup.rpc_client, &msg);
+--
+2.53.0
+
--- /dev/null
+From 0c7b865a1c9176fd8aa9f6d2379cc48b28cbaf5a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jul 2026 15:41:30 +0200
+Subject: ovpn: add missing rtnl_link_ops->get_size callback
+
+From: Ralf Lici <ralf@mandelbit.com>
+
+[ Upstream commit 6e9f539e4f01153651dd77609b5ccadd44b74df8 ]
+
+ovpn_fill_info emits IFLA_OVPN_MODE inside IFLA_INFO_DATA, but
+ovpn_link_ops does not provide a get_size callback. Consequently,
+rtnetlink's size estimate for ovpn link messages does not include the
+nested mode attribute.
+
+Available skb tailroom may hide this mismatch. When the remaining space
+is insufficient, however, ovpn_fill_info returns -EMSGSIZE and message
+construction fails.
+
+Add the callback and account for IFLA_OVPN_MODE.
+
+Fixes: c2d950c4672a ("ovpn: add basic interface creation/destruction/management routines")
+Signed-off-by: Ralf Lici <ralf@mandelbit.com>
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/main.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
+index 9993c1dfe471d..9d9a0ff690d66 100644
+--- a/drivers/net/ovpn/main.c
++++ b/drivers/net/ovpn/main.c
+@@ -210,6 +210,12 @@ static int ovpn_newlink(struct net_device *dev,
+ return register_netdevice(dev);
+ }
+
++static size_t ovpn_get_size(const struct net_device *dev)
++{
++ /* IFLA_OVPN_MODE */
++ return nla_total_size(sizeof(u8));
++}
++
+ static int ovpn_fill_info(struct sk_buff *skb, const struct net_device *dev)
+ {
+ struct ovpn_priv *ovpn = netdev_priv(dev);
+@@ -228,6 +234,7 @@ static struct rtnl_link_ops ovpn_link_ops = {
+ .policy = ovpn_policy,
+ .maxtype = IFLA_OVPN_MAX,
+ .newlink = ovpn_newlink,
++ .get_size = ovpn_get_size,
+ .fill_info = ovpn_fill_info,
+ };
+
+--
+2.53.0
+
--- /dev/null
+From 82be98162c3adc0e61c050372f13cd9ac88f819a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 13:48:53 +0200
+Subject: ovpn: disable IPv4 redirects on MP interfaces
+
+From: Antonio Quartulli <antonio@openvpn.net>
+
+[ Upstream commit 0301aa324941698bec3dd455df1c5abc7afb10db ]
+
+ovpn_mp_alloc() tried to disable SEND_REDIRECTS on a multipeer
+interface, but it runs from ovpn_net_init() (->ndo_init), which
+register_netdevice() invokes before the NETDEV_REGISTER notifier
+chain. The IPv4 in_device is only created when that notifier reaches
+inetdev_event() -> inetdev_init(), so __in_dev_get_rtnl() always
+returned NULL at ndo_init time and the whole redirect-disabling block
+(both the per-device and the per-netns IPV4_DEVCONF_ALL write) was
+dead. MP interfaces therefore kept emitting ICMP redirects.
+
+Disabling redirects only once is not enough either: the IPv4
+in_device is destroyed and recreated when the interface is moved to a
+different network namespace (NETDEV_UNREGISTER/NETDEV_REGISTER), and
+the newly created in_device inherits the destination namespace
+defaults, silently re-enabling SEND_REDIRECTS.
+
+Disable redirects from ovpn_net_open() (->ndo_open) instead: it runs
+every time the interface is brought up, including after the in_device
+has been recreated, so the setting is always re-applied. This mirrors
+what wireguard does in wg_open(). RTNL is held on the ndo_open() path,
+so __in_dev_get_rtnl() is safe.
+
+Fixes: 05003b408c20 ("ovpn: implement multi-peer support")
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/main.c | 50 ++++++++++++++++++++++++++++-------------
+ 1 file changed, 35 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
+index 9d9a0ff690d66..3a04757d5c31e 100644
+--- a/drivers/net/ovpn/main.c
++++ b/drivers/net/ovpn/main.c
+@@ -35,25 +35,11 @@ static void ovpn_priv_free(struct net_device *net)
+
+ static int ovpn_mp_alloc(struct ovpn_priv *ovpn)
+ {
+- struct in_device *dev_v4;
+ int i;
+
+ if (ovpn->mode != OVPN_MODE_MP)
+ return 0;
+
+- dev_v4 = __in_dev_get_rtnl(ovpn->dev);
+- if (dev_v4) {
+- /* disable redirects as Linux gets confused by ovpn
+- * handling same-LAN routing.
+- * This happens because a multipeer interface is used as
+- * relay point between hosts in the same subnet, while
+- * in a classic LAN this would not be needed because the
+- * two hosts would be able to talk directly.
+- */
+- IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false);
+- IPV4_DEVCONF_ALL(dev_net(ovpn->dev), SEND_REDIRECTS) = false;
+- }
+-
+ /* the peer container is fairly large, therefore we allocate it only in
+ * MP mode
+ */
+@@ -97,9 +83,38 @@ static void ovpn_net_uninit(struct net_device *dev)
+ gro_cells_destroy(&ovpn->gro_cells);
+ }
+
++static int ovpn_net_open(struct net_device *dev)
++{
++ struct ovpn_priv *ovpn = netdev_priv(dev);
++ struct in_device *dev_v4;
++
++ /* the IPv4 in_device (and thus its config) is recreated whenever the
++ * interface is moved to a new netns, so redirects must be disabled on
++ * every bring-up rather than once at creation time, otherwise the
++ * setting is silently lost after such a move
++ */
++ if (ovpn->mode == OVPN_MODE_MP) {
++ dev_v4 = __in_dev_get_rtnl(dev);
++ if (dev_v4) {
++ /* disable redirects as Linux gets confused by ovpn
++ * handling same-LAN routing.
++ * This happens because a multipeer interface is used as
++ * relay point between hosts in the same subnet, while
++ * in a classic LAN this would not be needed because the
++ * two hosts would be able to talk directly.
++ */
++ IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false);
++ IPV4_DEVCONF_ALL(dev_net(dev), SEND_REDIRECTS) = false;
++ }
++ }
++
++ return 0;
++}
++
+ static const struct net_device_ops ovpn_netdev_ops = {
+ .ndo_init = ovpn_net_init,
+ .ndo_uninit = ovpn_net_uninit,
++ .ndo_open = ovpn_net_open,
+ .ndo_start_xmit = ovpn_net_xmit,
+ };
+
+@@ -183,6 +198,7 @@ static int ovpn_newlink(struct net_device *dev,
+ struct ovpn_priv *ovpn = netdev_priv(dev);
+ struct nlattr **data = params->data;
+ enum ovpn_mode mode = OVPN_MODE_P2P;
++ int ret;
+
+ if (data && data[IFLA_OVPN_MODE]) {
+ mode = nla_get_u8(data[IFLA_OVPN_MODE]);
+@@ -207,7 +223,11 @@ static int ovpn_newlink(struct net_device *dev,
+ else
+ netif_carrier_off(dev);
+
+- return register_netdevice(dev);
++ ret = register_netdevice(dev);
++ if (ret < 0)
++ return ret;
++
++ return 0;
+ }
+
+ static size_t ovpn_get_size(const struct net_device *dev)
+--
+2.53.0
+
--- /dev/null
+From 2bc6639f6aedc0298d99cee731f177e9d59c4842 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 13:48:50 +0200
+Subject: ovpn: ensure socket is owned by ovpn before deref sk_user_data
+
+From: Antonio Quartulli <antonio@openvpn.net>
+
+[ Upstream commit 59aed1eb60d70678a53acccb0cb337a26ce6680e ]
+
+Some subsystems, like BPF SOCKMAP, set sk_user_data without
+actually setting the encap_type.
+
+For this reason, we must make sure that the type is the
+one ovpn expects before dereferencing sk_user_data.
+
+Failing to do so may lead to out-of-bounds reads.
+
+Fixes: f6226ae7a0cd ("ovpn: introduce the ovpn_socket object")
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/socket.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/net/ovpn/socket.c b/drivers/net/ovpn/socket.c
+index 517caa64a4fef..6cbeb2caaeeca 100644
+--- a/drivers/net/ovpn/socket.c
++++ b/drivers/net/ovpn/socket.c
+@@ -162,6 +162,15 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
+ rcu_read_lock();
+ ovpn_sock = rcu_dereference_sk_user_data(sk);
+ if (ovpn_sock) {
++ /* something else filled the sk_user_data without
++ * setting the encap_type. Reject the socket.
++ */
++ if (!type) {
++ ovpn_sock = ERR_PTR(-EBUSY);
++ rcu_read_unlock();
++ goto sock_release;
++ }
++
+ /* socket owned by another ovpn instance, we can't use it */
+ if (ovpn_sock->ovpn != peer->ovpn) {
+ ovpn_sock = ERR_PTR(-EBUSY);
+--
+2.53.0
+
--- /dev/null
+From efa66673615423e554e6863afc30577aedeef384 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 13:48:54 +0200
+Subject: ovpn: ensure TCP vars are initialized first
+
+From: Antonio Quartulli <antonio@openvpn.net>
+
+[ Upstream commit 4680c0ebd958fc18e53c8b91d80436b236a8fc09 ]
+
+Netlink calls may access TCP global vars (i.e. when attaching
+a TCP socket), therefore we need to make sure the
+latters are initialized beforehand.
+
+For this reason move the global TCP initialization at the top
+of the module init function.
+
+Fixes: 11851cbd60ea ("ovpn: implement TCP transport")
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/main.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
+index 3a04757d5c31e..168cfe9b59a98 100644
+--- a/drivers/net/ovpn/main.c
++++ b/drivers/net/ovpn/main.c
+@@ -260,8 +260,11 @@ static struct rtnl_link_ops ovpn_link_ops = {
+
+ static int __init ovpn_init(void)
+ {
+- int err = rtnl_link_register(&ovpn_link_ops);
++ int err;
+
++ ovpn_tcp_init();
++
++ err = rtnl_link_register(&ovpn_link_ops);
+ if (err) {
+ pr_err("ovpn: can't register rtnl link ops: %d\n", err);
+ return err;
+@@ -273,8 +276,6 @@ static int __init ovpn_init(void)
+ goto unreg_rtnl;
+ }
+
+- ovpn_tcp_init();
+-
+ return 0;
+
+ unreg_rtnl:
+--
+2.53.0
+
--- /dev/null
+From fe27bda44071c62e5cc36dceccd4924bda6029c2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jul 2026 09:49:26 +0800
+Subject: ovpn: fix incorrect use of rcu_access_pointer()
+
+From: Qingfang Deng <qingfang.deng@linux.dev>
+
+[ Upstream commit 26ba17d845193dac4921ae1ab280d28d1938052e ]
+
+rcu_access_pointer() should only be used to test the value of a pointer,
+not to dereference it. As it's in a spin_lock_bh() critical section, use
+rcu_dereference_bh() instead, avoiding an extra rcu_read_lock().
+
+Fixes: f6226ae7a0cd ("ovpn: introduce the ovpn_socket object")
+Signed-off-by: Qingfang Deng <qingfang.deng@linux.dev>
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/peer.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
+index eada414a9d922..b0519f9840d83 100644
+--- a/drivers/net/ovpn/peer.c
++++ b/drivers/net/ovpn/peer.c
+@@ -1249,7 +1249,7 @@ static void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, struct sock *sk,
+ }
+
+ if (sk) {
+- ovpn_sock = rcu_access_pointer(peer->sock);
++ ovpn_sock = rcu_dereference_bh(peer->sock);
+ if (!ovpn_sock || ovpn_sock->sk != sk) {
+ spin_unlock_bh(&ovpn->lock);
+ return;
+--
+2.53.0
+
--- /dev/null
+From f00e6d56b80aa65b348f37f53a4d7f2f600cc304 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 13:48:52 +0200
+Subject: ovpn: hash floated peer by transport identity only
+
+From: Antonio Quartulli <antonio@openvpn.net>
+
+[ Upstream commit b47a52dcd598a50207a33df304acdf45348a690f ]
+
+The by_transp_addr table is keyed on the peer's remote transport
+address, but the float rehash hashed bind->remote directly, while the
+two other sites that touch the table build a clean key first:
+ovpn_peer_add_mp() and the lookup in ovpn_peer_get_by_transp_addr()
+both hash a sockaddr holding only family/address/port.
+
+For a link-local IPv6 peer, bind->remote carries sin6_scope_id (set
+from ipv6_iface_scope_id() when the endpoint is learned), and that
+field is folded into the jhash() over sizeof(struct sockaddr_in6).
+The lookup never sets sin6_scope_id, so after such a peer floats it is
+rehashed into a scope_id-dependent bucket that lookups (scope_id 0)
+never visit, making the peer unreachable through the by_transp_addr
+fallback. ovpn_peer_transp_match() only compares address and port, so
+the hash was keying on a field the match ignores.
+
+sin6_scope_id must stay in bind->remote because the TX path uses it as
+flowi6_oif, so it cannot just be cleared there. Instead build the hash
+key from family/address/port only, exactly like ovpn_peer_add_mp() and
+the lookup, so all three sites agree on the bucket.
+
+Fixes: f0281c1d3732 ("ovpn: add support for updating local or remote UDP endpoint")
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/peer.c | 25 +++++++++++++++++++++----
+ 1 file changed, 21 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
+index 33fb0a75e6006..eada414a9d922 100644
+--- a/drivers/net/ovpn/peer.c
++++ b/drivers/net/ovpn/peer.c
+@@ -904,7 +904,10 @@ bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
+ static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
+ const struct ovpn_bind *bind)
+ {
++ struct sockaddr_storage sa = {};
+ struct hlist_nulls_head *nhead;
++ struct sockaddr_in6 *sa6;
++ struct sockaddr_in *sa4;
+ size_t salen;
+
+ lockdep_assert_held(&peer->ovpn->lock);
+@@ -920,12 +923,26 @@ static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
+ if (unlikely(hlist_unhashed(&peer->hash_entry_id)))
+ return;
+
++ /* Build the hash key from the transport identity only
++ * (family/address/port), matching ovpn_peer_add_mp() and the lookup
++ * in ovpn_peer_get_by_transp_addr(). Hashing bind->remote directly
++ * would fold in sin6_scope_id (set on the float path but never by the
++ * lookup), scattering the peer into a bucket lookups cannot reach.
++ */
+ switch (bind->remote.in4.sin_family) {
+ case AF_INET:
+- salen = sizeof(struct sockaddr_in);
++ sa4 = (struct sockaddr_in *)&sa;
++ sa4->sin_family = AF_INET;
++ sa4->sin_addr.s_addr = bind->remote.in4.sin_addr.s_addr;
++ sa4->sin_port = bind->remote.in4.sin_port;
++ salen = sizeof(*sa4);
+ break;
+ case AF_INET6:
+- salen = sizeof(struct sockaddr_in6);
++ sa6 = (struct sockaddr_in6 *)&sa;
++ sa6->sin6_family = AF_INET6;
++ sa6->sin6_addr = bind->remote.in6.sin6_addr;
++ sa6->sin6_port = bind->remote.in6.sin6_port;
++ salen = sizeof(*sa6);
+ break;
+ default:
+ return;
+@@ -934,8 +951,8 @@ static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
+ /* remove old hashing (no-op if entry is not currently linked) */
+ hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
+ /* re-add with current transport address */
+- nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
+- &bind->remote, salen);
++ nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr, &sa,
++ salen);
+ hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 85fef0824e3cabf31500f5a1f066ab99b08c366e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 13:48:48 +0200
+Subject: ovpn: rehash peer in by_transp_addr table on CMD_PEER_SET
+
+From: Antonio Quartulli <antonio@openvpn.net>
+
+[ Upstream commit cc12f7240c8c4dee557749d33237542613992f14 ]
+
+When userspace updates a peer's remote endpoint via OVPN_CMD_PEER_SET,
+ovpn_nl_peer_modify() installs a new ovpn_bind through
+ovpn_peer_reset_sockaddr(), but ovpn_nl_peer_set_doit() only calls
+ovpn_peer_hash_vpn_ip() to refresh the VPN-IP hashtables. The peer is
+left in the bucket of peers->by_transp_addr corresponding to its old
+remote address.
+
+As a consequence, datagrams arriving at the UDP RX path from the newly
+configured remote hash to a different slot and the lockless lookup in
+ovpn_peer_get_by_transp_addr() (called from ovpn_udp_encap_recv()) does
+not find the peer, until either a float event or a peer re-add fixes
+the bucket.
+
+Introduce ovpn_peer_hash_transp_addr() (modeled after
+ovpn_peer_hash_vpn_ip()) and invoke it from ovpn_nl_peer_set_doit()
+whenever the request carried a new remote address. The helper bails
+out in P2P mode and on peers without a bind (TCP), and relies on
+hlist_nulls_del_init_rcu()'s pprev==NULL short-circuit to handle the
+case of an entry not currently linked in the table.
+
+Fixes: 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/netlink.c | 6 +++
+ drivers/net/ovpn/peer.c | 105 +++++++++++++++++++++++++------------
+ drivers/net/ovpn/peer.h | 1 +
+ 3 files changed, 79 insertions(+), 33 deletions(-)
+
+diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c
+index 4c66c1ec497ec..4dad852941982 100644
+--- a/drivers/net/ovpn/netlink.c
++++ b/drivers/net/ovpn/netlink.c
+@@ -534,6 +534,12 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
+ */
+ if (ret > 0)
+ ovpn_peer_hash_vpn_ip(peer);
++ /* if the remote endpoint was updated, the by_transp_addr hash bucket
++ * also needs to be refreshed, otherwise incoming packets from the new
++ * remote address would fail the lockless lookup
++ */
++ if (attrs[OVPN_A_PEER_REMOTE_IPV4] || attrs[OVPN_A_PEER_REMOTE_IPV6])
++ ovpn_peer_hash_transp_addr(peer);
+ spin_unlock_bh(&ovpn->lock);
+ ovpn_peer_put(peer);
+
+diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
+index 68021c0c17830..a330892e82bf7 100644
+--- a/drivers/net/ovpn/peer.c
++++ b/drivers/net/ovpn/peer.c
+@@ -189,6 +189,9 @@ int ovpn_peer_reset_sockaddr(struct ovpn_peer *peer,
+ &(*__tbl1)[ovpn_get_hash_slot(*__tbl1, _key, _key_len)];\
+ })
+
++static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
++ const struct ovpn_bind *bind);
++
+ /**
+ * ovpn_peer_endpoints_update - update remote or local endpoint for peer
+ * @peer: peer to update the remote endpoint for
+@@ -196,7 +199,6 @@ int ovpn_peer_reset_sockaddr(struct ovpn_peer *peer,
+ */
+ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
+ {
+- struct hlist_nulls_head *nhead;
+ struct sockaddr_storage ss;
+ struct sockaddr_in6 *sa6;
+ bool reset_cache = false;
+@@ -295,46 +297,23 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
+ ovpn_nl_peer_float_notify(peer, &ss);
+
+ /* rehashing is required only in MP mode as P2P has one peer
+- * only and thus there is no hashtable
++ * only and thus there is no hashtable.
++ *
++ * This function may be invoked concurrently, so re-read peer->bind
++ * under the proper locks and rehash against its current value.
+ */
+ if (peer->ovpn->mode != OVPN_MODE_MP)
+ return;
+
++ /* This function may be invoked concurrently, therefore another
++ * float may have happened in parallel: re-acquire the locks and
++ * rehash using the peer->bind->remote directly as key
++ */
+ spin_lock_bh(&peer->ovpn->lock);
+ spin_lock_bh(&peer->lock);
+ bind = rcu_dereference_protected(peer->bind,
+ lockdep_is_held(&peer->lock));
+- if (unlikely(!bind))
+- goto unlock2;
+-
+- /* peer may have been concurrently removed between the caller's
+- * initial lookup and our acquisition of ovpn->lock; skip the
+- * rehash so we don't re-insert a removed peer
+- */
+- if (unlikely(hlist_unhashed(&peer->hash_entry_id)))
+- goto unlock2;
+-
+- /* This function may be invoked concurrently, therefore another
+- * float may have happened in parallel: perform rehashing
+- * using the peer->bind->remote directly as key
+- */
+-
+- switch (bind->remote.in4.sin_family) {
+- case AF_INET:
+- salen = sizeof(*sa);
+- break;
+- case AF_INET6:
+- salen = sizeof(*sa6);
+- break;
+- }
+-
+- /* remove old hashing */
+- hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
+- /* re-add with new transport address */
+- nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
+- &bind->remote, salen);
+- hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
+-unlock2:
++ __ovpn_peer_hash_transp_addr(peer, bind);
+ spin_unlock_bh(&peer->lock);
+ spin_unlock_bh(&peer->ovpn->lock);
+ return;
+@@ -902,6 +881,66 @@ bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
+ return match;
+ }
+
++/* Move @peer to the by_transp_addr bucket matching its current bind.
++ *
++ * Caller must hold both peer->ovpn->lock and peer->lock, and must have
++ * already dereferenced a valid (non-NULL) peer->bind, passed in as @bind.
++ */
++static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer,
++ const struct ovpn_bind *bind)
++{
++ struct hlist_nulls_head *nhead;
++ size_t salen;
++
++ lockdep_assert_held(&peer->ovpn->lock);
++ lockdep_assert_held(&peer->lock);
++
++ if (WARN_ON_ONCE(!bind))
++ return;
++
++ /* peer may have been concurrently removed between the caller's
++ * initial lookup and our acquisition of ovpn->lock; skip the
++ * rehash so we don't re-insert a removed peer
++ */
++ if (unlikely(hlist_unhashed(&peer->hash_entry_id)))
++ return;
++
++ switch (bind->remote.in4.sin_family) {
++ case AF_INET:
++ salen = sizeof(struct sockaddr_in);
++ break;
++ case AF_INET6:
++ salen = sizeof(struct sockaddr_in6);
++ break;
++ default:
++ return;
++ }
++
++ /* remove old hashing (no-op if entry is not currently linked) */
++ hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
++ /* re-add with current transport address */
++ nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
++ &bind->remote, salen);
++ hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
++}
++
++void ovpn_peer_hash_transp_addr(struct ovpn_peer *peer)
++{
++ struct ovpn_bind *bind;
++
++ lockdep_assert_held(&peer->ovpn->lock);
++
++ /* rehashing makes sense only in multipeer mode */
++ if (peer->ovpn->mode != OVPN_MODE_MP)
++ return;
++
++ spin_lock_bh(&peer->lock);
++ bind = rcu_dereference_protected(peer->bind,
++ lockdep_is_held(&peer->lock));
++ __ovpn_peer_hash_transp_addr(peer, bind);
++ spin_unlock_bh(&peer->lock);
++}
++
+ void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer)
+ {
+ struct hlist_nulls_head *nhead;
+diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h
+index 86c8cffada6d4..dfa5c0037e02b 100644
+--- a/drivers/net/ovpn/peer.h
++++ b/drivers/net/ovpn/peer.h
+@@ -150,6 +150,7 @@ struct ovpn_peer *ovpn_peer_get_by_id(struct ovpn_priv *ovpn, u32 peer_id);
+ struct ovpn_peer *ovpn_peer_get_by_dst(struct ovpn_priv *ovpn,
+ struct sk_buff *skb);
+ void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer);
++void ovpn_peer_hash_transp_addr(struct ovpn_peer *peer);
+ bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
+ struct ovpn_peer *peer);
+
+--
+2.53.0
+
--- /dev/null
+From aeeed7a742d1a79b21e9ac45083e673c27ab54a1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 13:48:47 +0200
+Subject: ovpn: skip rehash for peers already removed from by_id
+
+From: Antonio Quartulli <antonio@openvpn.net>
+
+[ Upstream commit 33ec10567fe14456063daf549fdf1a4f53448e4c ]
+
+ovpn_nl_peer_set_doit() resolves the target peer via
+ovpn_peer_get_by_id() before taking ovpn->lock. In the window between
+the lookup (which only takes a refcount) and the subsequent
+spin_lock_bh(&ovpn->lock), a concurrent OVPN_CMD_PEER_DEL, keepalive
+expiry, or socket teardown can take ovpn->lock first, run
+ovpn_peer_remove() to unhash the peer from all four tables (by_id,
+by_vpn_addr4/6, by_transp_addr) and release the lock. set_doit then
+acquires ovpn->lock and calls ovpn_peer_hash_vpn_ip(), which
+re-inserts the now-removed peer back into the rehashing tables.
+
+The same race affects the float path: ovpn_peer_endpoints_update()
+holds only a refcount and acquires ovpn->lock very late (after async
+AEAD decrypt and a netlink notification), then rehashes the peer
+in the by_transp_addr table.
+
+The resurrected peer becomes reachable again from the RX lookup
+(ovpn_peer_get_by_transp_addr) and the TX VPN-IP lookup, even though
+userspace believes it is gone. Once the data-path refcount drops the
+peer is freed via call_rcu while the hash entries embedded in it
+remain linked, opening a UAF window.
+
+Bail out of the rehash when hash_entry_id is unhashed, mirroring
+the sentinel already used by ovpn_peer_remove() to detect the
+already-removed state. The check is safe under ovpn->lock, which
+serializes every mutation of hash_entry_id, and is a no-op for the
+add path because ovpn_peer_add_mp() inserts hash_entry_id before
+calling ovpn_peer_hash_vpn_ip().
+
+Fixes: 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/peer.c | 73 ++++++++++++++++++++++++-----------------
+ 1 file changed, 43 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
+index a21d02ac715e0..68021c0c17830 100644
+--- a/drivers/net/ovpn/peer.c
++++ b/drivers/net/ovpn/peer.c
+@@ -297,40 +297,46 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
+ /* rehashing is required only in MP mode as P2P has one peer
+ * only and thus there is no hashtable
+ */
+- if (peer->ovpn->mode == OVPN_MODE_MP) {
+- spin_lock_bh(&peer->ovpn->lock);
+- spin_lock_bh(&peer->lock);
+- bind = rcu_dereference_protected(peer->bind,
+- lockdep_is_held(&peer->lock));
+- if (unlikely(!bind)) {
+- spin_unlock_bh(&peer->lock);
+- spin_unlock_bh(&peer->ovpn->lock);
+- return;
+- }
++ if (peer->ovpn->mode != OVPN_MODE_MP)
++ return;
+
+- /* This function may be invoked concurrently, therefore another
+- * float may have happened in parallel: perform rehashing
+- * using the peer->bind->remote directly as key
+- */
++ spin_lock_bh(&peer->ovpn->lock);
++ spin_lock_bh(&peer->lock);
++ bind = rcu_dereference_protected(peer->bind,
++ lockdep_is_held(&peer->lock));
++ if (unlikely(!bind))
++ goto unlock2;
+
+- switch (bind->remote.in4.sin_family) {
+- case AF_INET:
+- salen = sizeof(*sa);
+- break;
+- case AF_INET6:
+- salen = sizeof(*sa6);
+- break;
+- }
++ /* peer may have been concurrently removed between the caller's
++ * initial lookup and our acquisition of ovpn->lock; skip the
++ * rehash so we don't re-insert a removed peer
++ */
++ if (unlikely(hlist_unhashed(&peer->hash_entry_id)))
++ goto unlock2;
+
+- /* remove old hashing */
+- hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
+- /* re-add with new transport address */
+- nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
+- &bind->remote, salen);
+- hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
+- spin_unlock_bh(&peer->lock);
+- spin_unlock_bh(&peer->ovpn->lock);
++ /* This function may be invoked concurrently, therefore another
++ * float may have happened in parallel: perform rehashing
++ * using the peer->bind->remote directly as key
++ */
++
++ switch (bind->remote.in4.sin_family) {
++ case AF_INET:
++ salen = sizeof(*sa);
++ break;
++ case AF_INET6:
++ salen = sizeof(*sa6);
++ break;
+ }
++
++ /* remove old hashing */
++ hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr);
++ /* re-add with new transport address */
++ nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr,
++ &bind->remote, salen);
++ hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead);
++unlock2:
++ spin_unlock_bh(&peer->lock);
++ spin_unlock_bh(&peer->ovpn->lock);
+ return;
+ unlock:
+ spin_unlock_bh(&peer->lock);
+@@ -906,6 +912,13 @@ void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer)
+ if (peer->ovpn->mode != OVPN_MODE_MP)
+ return;
+
++ /* peer may have been concurrently removed between the caller's
++ * initial lookup and our acquisition of ovpn->lock; skip the
++ * rehash so we don't re-insert a removed peer
++ */
++ if (hlist_unhashed(&peer->hash_entry_id))
++ return;
++
+ if (peer->vpn_addrs.ipv4.s_addr != htonl(INADDR_ANY)) {
+ /* remove potential old hashing */
+ hlist_nulls_del_init_rcu(&peer->hash_entry_addr4);
+--
+2.53.0
+
--- /dev/null
+From 80a4f313e8aa5bfcef0f12c1e142086e8836360a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Jul 2026 13:48:51 +0200
+Subject: ovpn: zero-initialize sockaddr before learning a floated endpoint
+
+From: Antonio Quartulli <antonio@openvpn.net>
+
+[ Upstream commit 3f012bdbabe211ccbc0c50ea5a1dbc60f8af1532 ]
+
+ovpn_peer_endpoints_update() builds the new remote endpoint in an
+on-stack struct sockaddr_storage that is left uninitialized. For IPv4
+only sin_family/sin_addr/sin_port are written, leaving the 8-byte
+sin_zero padding as stack garbage (for IPv6, sin6_flowinfo is left
+uninitialized likewise).
+
+ovpn_peer_reset_sockaddr() -> ovpn_bind_from_sockaddr() then memcpy()s
+sizeof(struct sockaddr_in)/sizeof(struct sockaddr_in6) bytes - padding
+included - into bind->remote. That buffer is later hashed with jhash()
+over the same length to place the peer in the by_transp_addr table, so
+the garbage padding lands the floated peer in an essentially random
+bucket. Lockless lookups in ovpn_peer_get_by_transp_addr() build their
+key from a zero-initialized sockaddr_storage, compute a different bucket
+and fail to find the peer.
+
+This is also a plain use of uninitialized stack memory in jhash().
+
+Build the floated endpoint with a designated initializer so the
+padding (sin_zero for IPv4, sin6_flowinfo for IPv6) is zeroed as part
+of the assignment. This keeps the padding out of the by_transp_addr
+hash key without memset-ing the whole sockaddr_storage on every
+received packet.
+
+Fixes: f0281c1d3732 ("ovpn: add support for updating local or remote UDP endpoint")
+Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ovpn/peer.c | 31 +++++++++++++++++++++++--------
+ 1 file changed, 23 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
+index a330892e82bf7..33fb0a75e6006 100644
+--- a/drivers/net/ovpn/peer.c
++++ b/drivers/net/ovpn/peer.c
+@@ -222,9 +222,16 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
+ */
+ local_ip = &ip_hdr(skb)->daddr;
+ sa = (struct sockaddr_in *)&ss;
+- sa->sin_family = AF_INET;
+- sa->sin_addr.s_addr = ip_hdr(skb)->saddr;
+- sa->sin_port = udp_hdr(skb)->source;
++ /* use a designated initializer so the sin_zero padding
++ * is zeroed (it ends up in the by_transp_addr hash key)
++ * without memset-ing the whole sockaddr_storage on the
++ * RX fast path
++ */
++ *sa = (struct sockaddr_in) {
++ .sin_family = AF_INET,
++ .sin_addr.s_addr = ip_hdr(skb)->saddr,
++ .sin_port = udp_hdr(skb)->source,
++ };
+ salen = sizeof(*sa);
+ reset_cache = true;
+ break;
+@@ -250,11 +257,19 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
+ */
+ local_ip = &ipv6_hdr(skb)->daddr;
+ sa6 = (struct sockaddr_in6 *)&ss;
+- sa6->sin6_family = AF_INET6;
+- sa6->sin6_addr = ipv6_hdr(skb)->saddr;
+- sa6->sin6_port = udp_hdr(skb)->source;
+- sa6->sin6_scope_id = ipv6_iface_scope_id(&ipv6_hdr(skb)->saddr,
+- skb->skb_iif);
++ /* use a designated initializer so the sin6_flowinfo
++ * padding is zeroed (it ends up in the by_transp_addr
++ * hash key) without memset-ing the whole
++ * sockaddr_storage on the RX fast path
++ */
++ *sa6 = (struct sockaddr_in6) {
++ .sin6_family = AF_INET6,
++ .sin6_addr = ipv6_hdr(skb)->saddr,
++ .sin6_port = udp_hdr(skb)->source,
++ .sin6_scope_id =
++ ipv6_iface_scope_id(&ipv6_hdr(skb)->saddr,
++ skb->skb_iif),
++ };
+ salen = sizeof(*sa6);
+ reset_cache = true;
+ break;
+--
+2.53.0
+
--- /dev/null
+From b462af1aa7f44fc725c572081a16bb20dee6fea8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 17:00:30 +0000
+Subject: pds_core: cancel pending PCI reset work on AER recovery
+
+From: Nikhil P. Rao <nikhil.rao@amd.com>
+
+[ Upstream commit 57d635329d799b79096155cdf47ee0013d6780d1 ]
+
+pdsc_check_pci_health() queues pci_reset_work when it sees a broken PCI
+connection, and nothing cancels it. When the PCI core starts AER
+recovery, pdsc_pci_error_detected() runs pdsc_reset_prepare() and
+recovers the device, but a pci_reset_work queued just before is left
+pending. If it runs after recovery released the device lock, it resets a
+device the driver now considers healthy, bouncing the link for no reason.
+
+Cancel pci_reset_work in pdsc_pci_error_detected() after
+pdsc_reset_prepare(), which has already stopped the health thread so it
+cannot requeue the work. cancel_work_sync() is safe under the device
+lock here because pdsc_pci_reset_thread() uses pci_try_reset_function(),
+which returns instead of blocking on the lock. Only PFs initialize
+pci_reset_work, so guard the cancel with !is_virtfn.
+
+Fixes: 81665adf25d2 ("pds_core: Fix pdsc_check_pci_health function to use work thread")
+Reported-by: sashiko-bot <sashiko-bot@kernel.org>
+Closes: https://sashiko.dev/#/patchset/20260714180223.1642792-2-nikhil.rao%40amd.com?part=1
+Signed-off-by: Nikhil P. Rao <nikhil.rao@amd.com>
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Link: https://patch.msgid.link/20260727170030.361116-1-nikhil.rao@amd.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/amd/pds_core/main.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c
+index 71a1d4b001c22..9a2c64198d03b 100644
+--- a/drivers/net/ethernet/amd/pds_core/main.c
++++ b/drivers/net/ethernet/amd/pds_core/main.c
+@@ -561,7 +561,11 @@ static pci_ers_result_t pdsc_pci_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t error)
+ {
+ if (error == pci_channel_io_frozen) {
++ struct pdsc *pdsc = pci_get_drvdata(pdev);
++
+ pdsc_reset_prepare(pdev);
++ if (!pdev->is_virtfn)
++ cancel_work_sync(&pdsc->pci_reset_work);
+ return PCI_ERS_RESULT_NEED_RESET;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From b0f915f0818741151987d71cf761bebb6e8c0239 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 16:45:48 +0000
+Subject: pds_core: keep the health thread stopped during reset
+
+From: Nikhil P. Rao <nikhil.rao@amd.com>
+
+[ Upstream commit cd09971dcc1c499ae0879010a00e9dba87abdc4f ]
+
+Commit d9407ff11809 ("pds_core: Prevent health thread from running
+during reset/remove") stops the health thread with cancel_work_sync()
+before a reset, but a devcmd timeout during pdsc_fw_down() re-queues
+health_work, so pdsc_health_thread() runs again mid-reset and double
+allocates the core DMA queues via pdsc_fw_up().
+
+Only the reset path is affected: on remove PDSC_S_STOPPING_DRIVER gates
+the health thread and the workqueue is destroyed.
+
+Use disable_work_sync() to cancel health_work and block further
+queue_work() on it, and enable_work() in pdsc_restart_health_thread() to
+re-allow it after the reset.
+
+disable_work_sync() keeps a disable depth, so every disable must be
+matched by one enable. pdsc_reset_prepare() stops the health thread and
+pdsc_reset_done() restarts it. On the AER path pdsc_pci_error_detected()
+calls pdsc_reset_prepare(), then pdsc_pci_error_resume() re-inits via
+pci_reset_function_locked() (pds_core has no .slot_reset handler), which
+runs the pair again - stopping the thread twice but restarting it once.
+Gate the disable and enable on a health_stopped flag so each fires at
+most once per stopped/running transition.
+
+Fixes: d9407ff11809 ("pds_core: Prevent health thread from running during reset/remove")
+Reported-by: sashiko-bot <sashiko-bot@kernel.org>
+Closes: https://sashiko.dev/#/patchset/20260629200358.2626129-1-nikhil.rao%40amd.com?part=2
+Signed-off-by: Nikhil P. Rao <nikhil.rao@amd.com>
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Link: https://patch.msgid.link/20260727164548.359562-1-nikhil.rao@amd.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/amd/pds_core/core.h | 1 +
+ drivers/net/ethernet/amd/pds_core/main.c | 10 ++++++++--
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h
+index 4a6b35c84dabe..2449e19321f7f 100644
+--- a/drivers/net/ethernet/amd/pds_core/core.h
++++ b/drivers/net/ethernet/amd/pds_core/core.h
+@@ -171,6 +171,7 @@ struct pdsc {
+ struct timer_list wdtimer;
+ unsigned int wdtimer_period;
+ struct work_struct health_work;
++ bool health_stopped;
+ struct devlink_health_reporter *fw_reporter;
+ u32 fw_recoveries;
+
+diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c
+index 8d94a4d70395e..71a1d4b001c22 100644
+--- a/drivers/net/ethernet/amd/pds_core/main.c
++++ b/drivers/net/ethernet/amd/pds_core/main.c
+@@ -470,8 +470,10 @@ static void pdsc_stop_health_thread(struct pdsc *pdsc)
+ return;
+
+ timer_shutdown_sync(&pdsc->wdtimer);
+- if (pdsc->health_work.func)
+- cancel_work_sync(&pdsc->health_work);
++ if (pdsc->health_work.func && !pdsc->health_stopped) {
++ disable_work_sync(&pdsc->health_work);
++ pdsc->health_stopped = true;
++ }
+ }
+
+ static void pdsc_restart_health_thread(struct pdsc *pdsc)
+@@ -479,6 +481,10 @@ static void pdsc_restart_health_thread(struct pdsc *pdsc)
+ if (pdsc->pdev->is_virtfn)
+ return;
+
++ if (pdsc->health_stopped) {
++ enable_work(&pdsc->health_work);
++ pdsc->health_stopped = false;
++ }
+ timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0);
+ mod_timer(&pdsc->wdtimer, jiffies + 1);
+ }
+--
+2.53.0
+
--- /dev/null
+From b4d17a8ada124c01cd0617551f2dd4282f78b0a9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 19 Jul 2026 15:35:59 +0200
+Subject: pinctrl: qcom: ipq806x: mark gpio as a GPIO pin function
+
+From: Hans Ulli Kroll <linux@ulli-kroll.de>
+
+[ Upstream commit 687f39faccba29ab26de965411db37e849af8ec2 ]
+
+The qcom pinctrl core supports marking functions that represent GPIO mode
+via PINCTRL_GPIO_PINFUNCTION(), so that strict pinmuxing does not reject
+GPIO requests for pins that are muxed to the GPIO function.
+
+Add a IPQ_GPIO_PIN_FUNCTION() helper and use it for the ipq806x gpio
+function, matching how the msm-based qcom drivers handle this.
+
+This allows ipq806x to keep the GPIO-related configuration in DTS
+without tripping over strict pinmux ownership
+checks.
+
+Fixes: cc85cb96e2e4 ("pinctrl: qcom: make the pinmuxing strict")
+Signed-off-by: Hans Ulli Kroll <linux@ulli-kroll.de>
+Acked-by: Linus Walleij <linusw@kernel.org>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260719134548.8830-2-linux@ulli-kroll.de
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pinctrl/qcom/pinctrl-ipq8064.c | 2 +-
+ drivers/pinctrl/qcom/pinctrl-msm.h | 5 +++++
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/pinctrl/qcom/pinctrl-ipq8064.c b/drivers/pinctrl/qcom/pinctrl-ipq8064.c
+index 0a9e357e64c60..c1651f112950e 100644
+--- a/drivers/pinctrl/qcom/pinctrl-ipq8064.c
++++ b/drivers/pinctrl/qcom/pinctrl-ipq8064.c
+@@ -480,7 +480,7 @@ static const char * const ps_hold_groups[] = {
+ };
+
+ static const struct pinfunction ipq8064_functions[] = {
+- IPQ_PIN_FUNCTION(gpio),
++ IPQ_GPIO_PIN_FUNCTION(gpio),
+ IPQ_PIN_FUNCTION(mdio),
+ IPQ_PIN_FUNCTION(ssbi),
+ IPQ_PIN_FUNCTION(spmi),
+diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h
+index 4fbff61de6bb3..b94ba1a4177ed 100644
+--- a/drivers/pinctrl/qcom/pinctrl-msm.h
++++ b/drivers/pinctrl/qcom/pinctrl-msm.h
+@@ -24,6 +24,11 @@ struct pinctrl_pin_desc;
+ fname##_groups, \
+ ARRAY_SIZE(fname##_groups))
+
++#define IPQ_GPIO_PIN_FUNCTION(fname) \
++ [IPQ_MUX_##fname] = PINCTRL_GPIO_PINFUNCTION(#fname, \
++ fname##_groups, \
++ ARRAY_SIZE(fname##_groups))
++
+ #define MSM_PIN_FUNCTION(fname) \
+ [msm_mux_##fname] = PINCTRL_PINFUNCTION(#fname, \
+ fname##_groups, \
+--
+2.53.0
+
--- /dev/null
+From 73e15c389e891e5018de4fb0f49fdfc27e0973d2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 19 Jul 2026 15:36:00 +0200
+Subject: pinctrl: qcom: ipq806x: mark pci reset as a GPIO pin function
+
+From: Hans Ulli Kroll <linux@ulli-kroll.de>
+
+[ Upstream commit fd46760956509f580f7d3d25db4de10e7c6f949b ]
+
+The qcom pinctrl core supports marking functions that represent GPIO mode
+via PINCTRL_GPIO_PINFUNCTION(), so that strict pinmuxing does not reject
+GPIO requests for pins that are muxed to the GPIO function.
+
+Mark PCIe reset as GPIO pin function
+
+This allows ipq806x to keep the PCIe-reset related configuration in DTS
+without tripping over strict pinmux ownership checks.
+
+Fixes: cc85cb96e2e4 ("pinctrl: qcom: make the pinmuxing strict")
+Signed-off-by: Hans Ulli Kroll <linux@ulli-kroll.de>
+Acked-by: Linus Walleij <linusw@kernel.org>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260719134548.8830-3-linux@ulli-kroll.de
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pinctrl/qcom/pinctrl-ipq8064.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/pinctrl/qcom/pinctrl-ipq8064.c b/drivers/pinctrl/qcom/pinctrl-ipq8064.c
+index c1651f112950e..f35dbe07ab6fe 100644
+--- a/drivers/pinctrl/qcom/pinctrl-ipq8064.c
++++ b/drivers/pinctrl/qcom/pinctrl-ipq8064.c
+@@ -507,19 +507,19 @@ static const struct pinfunction ipq8064_functions[] = {
+ IPQ_PIN_FUNCTION(usb2_hsic),
+ IPQ_PIN_FUNCTION(rgmii2),
+ IPQ_PIN_FUNCTION(sata),
+- IPQ_PIN_FUNCTION(pcie1_rst),
++ IPQ_GPIO_PIN_FUNCTION(pcie1_rst),
+ IPQ_PIN_FUNCTION(pcie1_prsnt),
+ IPQ_PIN_FUNCTION(pcie1_pwren_n),
+ IPQ_PIN_FUNCTION(pcie1_pwren),
+ IPQ_PIN_FUNCTION(pcie1_pwrflt),
+ IPQ_PIN_FUNCTION(pcie1_clk_req),
+- IPQ_PIN_FUNCTION(pcie2_rst),
++ IPQ_GPIO_PIN_FUNCTION(pcie2_rst),
+ IPQ_PIN_FUNCTION(pcie2_prsnt),
+ IPQ_PIN_FUNCTION(pcie2_pwren_n),
+ IPQ_PIN_FUNCTION(pcie2_pwren),
+ IPQ_PIN_FUNCTION(pcie2_pwrflt),
+ IPQ_PIN_FUNCTION(pcie2_clk_req),
+- IPQ_PIN_FUNCTION(pcie3_rst),
++ IPQ_GPIO_PIN_FUNCTION(pcie3_rst),
+ IPQ_PIN_FUNCTION(pcie3_prsnt),
+ IPQ_PIN_FUNCTION(pcie3_pwren_n),
+ IPQ_PIN_FUNCTION(pcie3_pwren),
+--
+2.53.0
+
--- /dev/null
+From 5b1f3dadd797ec074509336fe303b885d9ce408b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 12:29:48 +0000
+Subject: Revert "net: thunderbolt: Enable end-to-end flow control also in
+ transmit"
+
+From: Fan Ye <fy15309206903@gmail.com>
+
+[ Upstream commit 1881f2efbf7f78dc0a79a387b29fde6ff56d3731 ]
+
+This reverts commit a8065af3346ebd7c76ebc113451fb3ba94cf7769.
+
+Per the USB4 spec, a Transmit Descriptor Ring with E2E flow control
+disabled does not require any credits to be available before the Host
+Interface Adapter Layer transmits a tunneled packet from it. Once E2E is
+enabled on that ring the controller must first obtain end-to-end
+credits.
+
+The ASMedia ASM4242 USB4 host router (PCI 1b21:2425) never delivers
+those credits. The controller does accept the configuration: reading the
+ring OPTIONS register back right after tb_ring_start() returns exactly
+what was written, including RING_FLAG_E2E_FLOW_CONTROL (bit 28) and the
+E2E HopID field. No credit ever arrives though, so the Tx ring's
+hardware consumer index never advances and the link carries no traffic
+at all.
+
+Measured on two hosts connected point to point, onboard ASM4242 on MSI
+X870E and X870, v6.17, stock drivers/net/thunderbolt/main.c with only
+this revert applied on top:
+
+ before: 100% packet loss to the peer; thunderbolt0 is up and the
+ XDomain handshake completes ("new host found"), but iperf3
+ fails with "No route to host" once the neighbour entry
+ expires
+ after: 0% packet loss, 0.28 ms RTT; iperf3 4.21 Gb/s one way and
+ 5.17 Gb/s the other (5 runs each, stddev <= 0.02), 1
+ retransmit in 10 s
+
+An instrumented build additionally showed a frozen-Tx-consumer watchdog
+firing ~30k times in a 10 s window before this change.
+
+Rx-side E2E is not touched by this revert, so peers that do return
+credits keep receive-side flow control.
+
+ASMedia does not look like an isolated case. The out-of-tree
+thunderbolt-ibverbs project disables native E2E on AMD NHI by default,
+noting that "Strix Halo has reproduced TX completion wedges with
+multiple native E2E rings active" -- the same failure mode, on a
+different vendor. Since the driver has no way to tell in advance which
+host router returns the credits, going back to the previous behaviour
+looks safer than adding a quirk per affected part; Tx-side E2E can be
+reintroduced as an opt-in for controllers that are known to implement
+the credit return.
+
+Note that the reverted commit was not fixing a reported problem, it was
+derived from the spec wording alone, so this revert is not expected to
+regress a known workload. Cc'ing the original author in case there was
+one.
+
+Fixes: a8065af3346e ("net: thunderbolt: Enable end-to-end flow control also in transmit")
+Cc: zhangjianrong <zhangjianrong5@huawei.com>
+Signed-off-by: Fan Ye <fy15309206903@gmail.com>
+Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Link: https://patch.msgid.link/20260727123002.25225-1-fy15309206903@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/thunderbolt/main.c | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c
+index ac016890646cf..0cd98496d135d 100644
+--- a/drivers/net/thunderbolt/main.c
++++ b/drivers/net/thunderbolt/main.c
+@@ -929,12 +929,8 @@ static int tbnet_open(struct net_device *dev)
+
+ netif_carrier_off(dev);
+
+- flags = RING_FLAG_FRAME;
+- /* Only enable full E2E if the other end supports it too */
+- if (tbnet_e2e && net->svc->prtcstns & TBNET_E2E)
+- flags |= RING_FLAG_E2E;
+-
+- ring = tb_ring_alloc_tx(xd->tb->nhi, -1, TBNET_RING_SIZE, flags);
++ ring = tb_ring_alloc_tx(xd->tb->nhi, -1, TBNET_RING_SIZE,
++ RING_FLAG_FRAME);
+ if (!ring) {
+ netdev_err(dev, "failed to allocate Tx ring\n");
+ return -ENOMEM;
+@@ -953,6 +949,11 @@ static int tbnet_open(struct net_device *dev)
+ sof_mask = BIT(TBIP_PDF_FRAME_START);
+ eof_mask = BIT(TBIP_PDF_FRAME_END);
+
++ flags = RING_FLAG_FRAME;
++ /* Only enable full E2E if the other end supports it too */
++ if (tbnet_e2e && net->svc->prtcstns & TBNET_E2E)
++ flags |= RING_FLAG_E2E;
++
+ ring = tb_ring_alloc_rx(xd->tb->nhi, -1, TBNET_RING_SIZE, flags,
+ net->tx_ring.ring->hop, sof_mask,
+ eof_mask, tbnet_start_poll, net);
+--
+2.53.0
+
--- /dev/null
+From 53d5e5122b58473e86d6f82e7025453716b89416 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 2 Aug 2026 04:17:59 +0200
+Subject: rqspinlock: Reset tail when preserving queue on deadlock
+
+From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+
+[ Upstream commit 7a3c0289c3c8eb4607dff448ae9ff9f902c813af ]
+
+Currently, the destruction of the waiter queue is suppressed for
+rqspinlock in cases where a deadlock is detected. Deadlock checks happen
+relatively frequently (on entry for AA, within 1ms for ABBA), and waiter
+threads may not be involved in locking scenarios involving deadlocks.
+Thus, it is useful to not flush the queue and let other waiters take a
+stab at acquiring the lock after we detect a deadlock and exit.
+
+However, we need to follow the same logic as what we did previously for
+the waitq_timeout label: reset the tail, and if we cannot, signal the
+next waiter appropriately. In case of deadlocks, this signal would just
+mark the MCS node as unlocked, and in case of timeouts, it would signal
+RES_TIMEOUT_VAL. The difference thus is in the value propagated, which
+decides whether the queue remains active or gets flushed.
+
+Not doing the tail reset, and waiting for the next waiter can lead to
+cases where we are the final waiter, and thus no next waiter arrives,
+leading to intermittent stalls in this path. Once the next waiter does
+join, we will be unblocked. In the theoretical case when the next waiter
+never joins, we risk stalling indefinitely.
+
+This can only happen for ABBA deadlocks, since entry into the wait queue
+is guarded with AA checks. A precise sequence of executions leading up
+to this scenario can be:
+
+CPU 0 holds lock A.
+CPU 1 holds lock B.
+CPU 2 attempts lock B, becomes the pending waiter for B.
+CPU 0 attempts lock B. B has locked+pending bits set, thus CPU 0 queues.
+CPU 1 attempts lock A.
+CPU 0 detects an ABBA deadlock.
+
+Once deadlock detection happens for CPU 0, it will sit waiting for the
+next waiter in the queue to populate node->next, which will experience
+delays until such a waiter arrives.
+
+Fix this by adjusting the logic for the check for deadlocks preceding
+the waitq_timeout label. It would make sense to consolidate code for
+both cases and use 'ret' to distinguish the value being propagated, but
+that is left as an exercise for a future refactoring task to avoid diff
+noise in this patch.
+
+Fixes: 7bd6e5ce5be6 ("rqspinlock: Disable queue destruction for deadlocks")
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Link: https://patch.msgid.link/20260802021759.1139457-1-memxor@gmail.com
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/rqspinlock.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/bpf/rqspinlock.c b/kernel/bpf/rqspinlock.c
+index e4e338cdb437c..2129defc4a9a7 100644
+--- a/kernel/bpf/rqspinlock.c
++++ b/kernel/bpf/rqspinlock.c
+@@ -572,9 +572,10 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val)
+
+ /* Disable queue destruction when we detect deadlocks. */
+ if (ret == -EDEADLK) {
+- if (!next)
++ if (!try_cmpxchg_tail(lock, tail, 0)) {
+ next = smp_cond_load_relaxed(&node->next, (VAL));
+- arch_mcs_spin_unlock_contended(&next->locked);
++ arch_mcs_spin_unlock_contended(&next->locked);
++ }
+ goto err_release_node;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 23a6b7cee9620038e6028c2d6405e7551c61dfc6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 15:10:43 +0200
+Subject: s390/ism: Fix UAF of sba and ieq during ism_dev_exit()
+
+From: Alexandra Winter <wintera@linux.ibm.com>
+
+[ Upstream commit b1896543ce59c4258625a35cf41e23a9a1f80ea2 ]
+
+A ism interrupt handler can be active in parallel with ism_dev_exit(),
+accessing freed data structures.
+
+No new interrupts will be generated after unregister_ieq(). Drain ongoing
+interrupt handlers by free_irq(), before freeing ism data structures.
+
+Fixes: 684b89bc39ce ("s390/ism: add device driver for internal shared memory")
+Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
+Link: https://patch.msgid.link/20260805131043.954639-1-wintera@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/s390/net/ism_drv.c | 19 +++++++++++++++----
+ 1 file changed, 15 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
+index 7d0479e4e0956..369aa21b1ff7c 100644
+--- a/drivers/s390/net/ism_drv.c
++++ b/drivers/s390/net/ism_drv.c
+@@ -148,13 +148,16 @@ static int unregister_sba(struct ism_dev *ism)
+ if (ret && ret != ISM_ERROR)
+ return -EIO;
+
++ return 0;
++}
++
++static void ism_free_sba(struct ism_dev *ism)
++{
+ dma_free_coherent(&ism->pdev->dev, PAGE_SIZE,
+ ism->sba, ism->sba_dma_addr);
+
+ ism->sba = NULL;
+ ism->sba_dma_addr = 0;
+-
+- return 0;
+ }
+
+ static int unregister_ieq(struct ism_dev *ism)
+@@ -168,13 +171,16 @@ static int unregister_ieq(struct ism_dev *ism)
+ if (ret && ret != ISM_ERROR)
+ return -EIO;
+
++ return 0;
++}
++
++static void ism_free_ieq(struct ism_dev *ism)
++{
+ dma_free_coherent(&ism->pdev->dev, PAGE_SIZE,
+ ism->ieq, ism->ieq_dma_addr);
+
+ ism->ieq = NULL;
+ ism->ieq_dma_addr = 0;
+-
+- return 0;
+ }
+
+ static int ism_read_local_gid(struct dibs_dev *dibs)
+@@ -573,6 +579,7 @@ static int ism_dev_init(struct ism_dev *ism)
+
+ unreg_sba:
+ unregister_sba(ism);
++ ism_free_sba(ism);
+ free_irq:
+ free_irq(pci_irq_vector(pdev, 0), ism);
+ free_vectors:
+@@ -585,9 +592,13 @@ static void ism_dev_exit(struct ism_dev *ism)
+ {
+ struct pci_dev *pdev = ism->pdev;
+
++ /* ism will only generate new IRQs while ieq & sba are registered */
+ unregister_ieq(ism);
+ unregister_sba(ism);
++ /* drain ongoing irpt handlers */
+ free_irq(pci_irq_vector(pdev, 0), ism);
++ ism_free_ieq(ism);
++ ism_free_sba(ism);
+ pci_free_irq_vectors(pdev);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From f99376625f6f292c30273fc82ce962304a0a98bb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 10:46:04 -1000
+Subject: sched_ext: Don't enable non-ext tasks in the sub-sched task loops
+
+From: Tejun Heo <tj@kernel.org>
+
+[ Upstream commit 5cdc928598095b2c7d5f265e5f21eadd1634bfbe ]
+
+Root enable and scx_post_fork() enable a task only if it's on the ext class.
+Tasks on other classes, possible under an SCX_OPS_SWITCH_PARTIAL root, are
+left READY and enabled by switching_to_scx() when they switch over. The sub
+enable-commit pass and the sub-disable re-home loop enable unconditionally,
+so a fair-class READY task in the subtree becomes ENABLED while not on
+sched_ext. A later switch to SCHED_EXT then trips the task state validation
+WARN (ENABLED with the previous state not READY) and calls ops.enable() a
+second time.
+
+Gate scx_enable_task() on the task's class in both loops.
+
+Fixes: 337ec00b1d9c ("sched_ext: Implement cgroup sub-sched enabling and disabling")
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Reviewed-by: Andrea Righi <arighi@nvidia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/sched/ext.c | 21 ++++++++++++++++-----
+ 1 file changed, 16 insertions(+), 5 deletions(-)
+
+diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
+index a8c4f665d173c..40df1be44a6d5 100644
+--- a/kernel/sched/ext.c
++++ b/kernel/sched/ext.c
+@@ -5874,15 +5874,22 @@ static void scx_sub_disable(struct scx_sched *sch)
+ /*
+ * $p is initialized for $parent and still attached to
+ * @sch. Disable and exit for @sch, switch over to
+- * $parent, override the state to READY to account for
+- * $p having already been initialized, and then enable.
++ * $parent and override the state to READY to account
++ * for $p having already been initialized.
+ */
+ scx_disable_and_exit_task(sch, p);
+ scx_set_task_state(p, SCX_TASK_INIT_BEGIN);
+ scx_set_task_state(p, SCX_TASK_INIT);
+ scx_set_task_sched(p, parent);
+ scx_set_task_state(p, SCX_TASK_READY);
+- scx_enable_task(parent, p);
++
++ /*
++ * A task on a non-ext class, possible under an
++ * %SCX_OPS_SWITCH_PARTIAL root, stays READY and is
++ * enabled by switching_to_scx() if it switches over.
++ */
++ if (p->sched_class == &ext_sched_class)
++ scx_enable_task(parent, p);
+ }
+
+ task_rq_unlock(rq, p, &rf);
+@@ -7377,10 +7384,14 @@ static void scx_sub_enable_workfn(struct kthread_work *work)
+
+ /*
+ * $p is now only initialized for @sch and READY, which
+- * is what we want. Assign it to @sch and enable.
++ * is what we want. Assign it to @sch and, if it's on
++ * the ext class, enable. A non-ext task, possible under
++ * an %SCX_OPS_SWITCH_PARTIAL root, stays READY and is
++ * enabled by switching_to_scx() if it switches over.
+ */
+ scx_set_task_sched(p, sch);
+- scx_enable_task(sch, p);
++ if (p->sched_class == &ext_sched_class)
++ scx_enable_task(sch, p);
+
+ p->scx.flags &= ~SCX_TASK_SUB_INIT;
+ }
+--
+2.53.0
+
--- /dev/null
+From e2f65dca5fd02e1bbf7843524aacc321c183a79d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 10:43:25 -1000
+Subject: sched_ext: Reject setting disallow from init_task outside the enable
+ path
+
+From: Tejun Heo <tj@kernel.org>
+
+[ Upstream commit 477869bfafea65492d23de62c1b5208147c09dd2 ]
+
+The p->scx.disallow revert assumes the root enable path, where the switching
+loop reads the reverted policy right afterwards and leaves the task off SCX.
+The sub-scheduler disable path also reaches it when re-initializing the
+returned tasks on a root parent. Nothing reads the policy there: the task is
+enabled on root anyway and keeps running on the ext class with a silently
+rewritten policy.
+
+Kill the sched instead, matching the fork and non-root branches, and update
+the disallow documentation, which equated !fork with the load path and
+pointed at a stale debugfs path for nr_rejected.
+
+Fixes: 337ec00b1d9c ("sched_ext: Implement cgroup sub-sched enabling and disabling")
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Reviewed-by: Andrea Righi <arighi@nvidia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/sched/ext.h | 10 +++++-----
+ kernel/sched/ext.c | 3 +++
+ 2 files changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/include/linux/sched/ext.h b/include/linux/sched/ext.h
+index 2129e18ada58b..31c810a3b808b 100644
+--- a/include/linux/sched/ext.h
++++ b/include/linux/sched/ext.h
+@@ -235,11 +235,11 @@ struct sched_ext_entity {
+ * to %SCHED_EXT with -%EACCES.
+ *
+ * Can be set from ops.init_task() while the BPF scheduler is being
+- * loaded (!scx_init_task_args->fork). If set and the task's policy is
+- * already %SCHED_EXT, the task's policy is rejected and forcefully
+- * reverted to %SCHED_NORMAL. The number of such events are reported
+- * through /sys/kernel/debug/sched_ext::nr_rejected. Setting this flag
+- * during fork is not allowed.
++ * loaded. If set and the task's policy is already %SCHED_EXT, the
++ * task's policy is rejected and forcefully reverted to %SCHED_NORMAL.
++ * The number of such events are reported through
++ * /sys/kernel/sched_ext/nr_rejected. Setting this flag from any other
++ * ops.init_task() invocation, such as during fork, fails the scheduler.
+ */
+ bool disallow; /* reject switching into SCX */
+
+diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
+index 5c780756e3623..6904d65d2b852 100644
+--- a/kernel/sched/ext.c
++++ b/kernel/sched/ext.c
+@@ -3581,6 +3581,9 @@ static int __scx_init_task(struct scx_sched *sch, struct task_struct *p, bool fo
+ } else if (unlikely(fork)) {
+ scx_error(sch, "ops.init_task() set task->scx.disallow for %s[%d] during fork",
+ p->comm, p->pid);
++ } else if (unlikely(scx_enable_state() != SCX_ENABLING)) {
++ scx_error(sch, "ops.init_task() set task->scx.disallow for %s[%d] outside the enable path",
++ p->comm, p->pid);
+ } else {
+ struct rq *rq;
+ struct rq_flags rf;
+--
+2.53.0
+
--- /dev/null
+From f73aa863b764f0a96a9ccb1709bb7972990be1ba Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 10:45:23 -1000
+Subject: sched_ext: Skip sub-disable teardown for never-linked sub-schedulers
+
+From: Tejun Heo <tj@kernel.org>
+
+[ Upstream commit 8c13364db9c9a43ed286f3a8d0fb9477b1adc43c ]
+
+A sub-scheduler enable can fail before scx_link_sched() links the sched into
+the hierarchy, e.g. when the parent is already being disabled, and cleanup
+still runs the full scx_sub_disable().
+
+That is racy against root disable: drain_descendants() is the only ordering
+between a sub's disable-time task walk and root disable's all-task teardown,
+and an unlinked sub is invisible to it. Root's teardown can thus run between
+the never-linked sub's drain and its walk, exiting every task to no
+scheduler.
+
+The walk then trips the membership WARN and re-homes the exited tasks onto
+the dying hierarchy, a use-after-free.
+
+Skip the cgroup ownership reset and the task walk if @sch was never linked,
+indicated by the empty ->sibling as unlinking only happens later in the same
+function. The membership WARN remains valid: a linked sub is always waited
+on by an ancestor's drain.
+
+Fixes: 337ec00b1d9c ("sched_ext: Implement cgroup sub-sched enabling and disabling")
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Reviewed-by: Andrea Righi <arighi@nvidia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/sched/ext.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
+index 6904d65d2b852..a8c4f665d173c 100644
+--- a/kernel/sched/ext.c
++++ b/kernel/sched/ext.c
+@@ -5798,6 +5798,15 @@ static void scx_sub_disable(struct scx_sched *sch)
+ percpu_down_write(&scx_fork_rwsem);
+ scx_cgroup_lock();
+
++ /*
++ * An enable that failed before scx_link_sched() never owned a cgroup or
++ * task and won't be waited on by an ancestor's drain_descendants().
++ * Nothing to reparent and walking the tasks can misbehave as the task
++ * ownership invariant (either owned by self or parent) does not hold.
++ */
++ if (list_empty(&sch->sibling))
++ goto dump;
++
+ set_cgroup_sched(sch_cgroup(sch), parent);
+
+ scx_task_iter_start(&sti, sch->cgrp);
+@@ -5810,8 +5819,8 @@ static void scx_sub_disable(struct scx_sched *sch)
+ continue;
+
+ /*
+- * By the time control reaches here, all descendant schedulers
+- * should already have been disabled.
++ * By the time control reaches here, all linked descendant
++ * schedulers should have been disabled.
+ */
+ WARN_ON_ONCE(!scx_task_on_sched(sch, p));
+
+@@ -5881,6 +5890,7 @@ static void scx_sub_disable(struct scx_sched *sch)
+ }
+ scx_task_iter_stop(&sti);
+
++dump:
+ scx_disable_dump(sch);
+
+ scx_cgroup_unlock();
+--
+2.53.0
+
--- /dev/null
+From 27081d1fb3c26192eb545857097e8b348148766d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 11:18:40 -0400
+Subject: sctp: clear control chunk transport if it is being removed
+
+From: Xin Long <lucien.xin@gmail.com>
+
+[ Upstream commit c9158ceaf27780ef64534ad72f44ffde3f8ccc49 ]
+
+sctp_make_heartbeat_ack() caches the destination transport in
+chunk->transport without taking a reference. When src_out_of_asoc_ok is
+enabled, the HEARTBEAT ACK may remain queued on control_chunk_list instead
+of being transmitted immediately.
+
+If the peer transport is removed while the chunk is still queued,
+sctp_assoc_rm_peer() drops the transport and schedules it for RCU freeing,
+but only clears cached transport pointers in out_chunk_list. The queued
+control chunk therefore retains a dangling transport pointer.
+
+Once an ASCONF_ACK clears the suppression and the queued control chunk is
+transmitted, SCTP dereferences the stale transport pointer, leading to a
+use-after-free.
+
+Fix this by also clearing chunk->transport for queued control chunks in
+control_chunk_list when removing the transport.
+
+Fixes: 8a07eb0a50ae ("sctp: Add ASCONF operation on the single-homed host")
+Reported-by: Daniele Linguaglossa <danielelinguaglossa@gmail.com>
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/7e1168cb722132152a29d47e5eafaeac4a3bf6f3.1785943120.git.lucien.xin@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/associola.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/net/sctp/associola.c b/net/sctp/associola.c
+index b6ac0966420a1..5b0ae616e1ff9 100644
+--- a/net/sctp/associola.c
++++ b/net/sctp/associola.c
+@@ -573,6 +573,10 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
+ if (ch->transport == peer)
+ ch->transport = NULL;
+
++ list_for_each_entry(ch, &asoc->outqueue.control_chunk_list, list)
++ if (ch->transport == peer)
++ ch->transport = NULL;
++
+ asoc->peer.transport_count--;
+
+ sctp_ulpevent_notify_peer_addr_change(peer, SCTP_ADDR_REMOVED, 0);
+--
+2.53.0
+
--- /dev/null
+From 25c5edb238d768d240ce7d4f4fb15a63b5b4f4c5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 10:55:14 +0800
+Subject: sctp: fix addip_serial increment on ASCONF_ACK allocation failure
+
+From: Qing Luo <luoqing@kylinos.cn>
+
+[ Upstream commit aa2e13ae8d3cbe2c15ef4f7e971b2de0832794aa ]
+
+In sctp_process_asconf(), when sctp_make_asconf_ack() fails to allocate
+the ASCONF_ACK chunk due to memory pressure, the code jumps to the
+done label where asoc->peer.addip_serial is unconditionally incremented.
+
+This leaves the peer's ASCONF (serial N) unacknowledged while the local
+endpoint now expects serial N+1. When the peer retransmits serial N, it
+falls into the serial < addip_serial + 1 branch ,
+which attempts to look up a cached ACK for serial N. No cached ACK
+exists since the allocation failed, so the retransmission is silently
+discarded. The peer eventually times out and ABORTs the association.
+
+Move the addip_serial increment inside the if (asconf_ack) block so that
+the serial number is only advanced when the ASCONF_ACK is successfully
+created and cached. This way, on allocation failure, the serial number
+is unchanged and the peer's retransmitted ASCONF will be correctly
+re-processed.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Qing Luo <luoqing@kylinos.cn>
+Acked-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/20260804025514.241767-1-l1138897701@163.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/sm_make_chunk.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
+index 0ae30c3c8913a..e25612e9d0821 100644
+--- a/net/sctp/sm_make_chunk.c
++++ b/net/sctp/sm_make_chunk.c
+@@ -3336,12 +3336,11 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
+ goto done;
+ }
+ done:
+- asoc->peer.addip_serial++;
+-
+ /* If we are sending a new ASCONF_ACK hold a reference to it in assoc
+ * after freeing the reference to old asconf ack if any.
+ */
+ if (asconf_ack) {
++ asoc->peer.addip_serial++;
+ sctp_chunk_hold(asconf_ack);
+ list_add_tail(&asconf_ack->transmitted_list,
+ &asoc->asconf_ack_list);
+--
+2.53.0
+
--- /dev/null
+From e7fb5a399860559dfdf9e848b54219e4f3db6ecd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 21:46:35 +0200
+Subject: selftests/ftrace: refactor eprobes test to fix argument checks
+
+From: Martin Kaiser <martin@kaiser.cx>
+
+[ Upstream commit 6e3abef2a27e7402a94111c9eff85d887e64a309 ]
+
+The add/remove eprobe test installs an eprobe for the openat syscall and
+runs ls. It checks the filenames that were opened by ls against a
+whitelist and a blacklist.
+
+Commit 206b25c09080 ("tracing: eprobe: read the complete FILTER_PTR_STRING
+pointer") fixed access to some string fields in eprobes. This triggers
+test failures as the blacklist does not allow relative paths for the
+openat parameters.
+
+What makes this test unstable is the fact that the openat calls vary a
+lot between different systems.
+
+Refactor the test to make it more robust. "cd <directory>" will issue a
+chdir syscall with the target directory as parameter. Set an eprobe on
+the sys_enter_chdir event and filter for the exact directory name. Allow
+(fault) as fallback.
+
+Link: https://lore.kernel.org/all/20260804194705.760893-1-martin@kaiser.cx/
+
+Fixes: 206b25c09080 ("tracing: eprobe: read the complete FILTER_PTR_STRING pointer")
+Reported-by: kernel test robot <oliver.sang@intel.com>
+Closes: https://lore.kernel.org/oe-lkp/202607151010.b68428e1-lkp@intel.com
+Signed-off-by: Martin Kaiser <martin@kaiser.cx>
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ftrace/test.d/dynevent/add_remove_eprobe.tc | 16 +++++-----------
+ 1 file changed, 5 insertions(+), 11 deletions(-)
+
+diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
+index c300eb0202620..e2322693d0c32 100644
+--- a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
++++ b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_eprobe.tc
+@@ -1,16 +1,16 @@
+ #!/bin/sh
+ # SPDX-License-Identifier: GPL-2.0
+ # description: Generic dynamic event - add/remove eprobe events
+-# requires: dynamic_events events/syscalls/sys_enter_openat "<attached-group>.<attached-event> [<args>]":README
++# requires: dynamic_events events/syscalls/sys_enter_chdir "<attached-group>.<attached-event> [<args>]":README
+
+ echo 0 > events/enable
+
+ clear_dynamic_events
+
+ SYSTEM="syscalls"
+-EVENT="sys_enter_openat"
++EVENT="sys_enter_chdir"
+ FIELD="filename"
+-EPROBE="eprobe_open"
++EPROBE="eprobe_chdir"
+ OPTIONS="file=+0(\$filename):ustring"
+ echo "e:$EPROBE $SYSTEM/$EVENT $OPTIONS" >> dynamic_events
+
+@@ -18,20 +18,14 @@ grep -q "$EPROBE" dynamic_events
+ test -d events/eprobes/$EPROBE
+
+ echo 1 > events/eprobes/$EPROBE/enable
+-ls
++cd /sys/kernel/tracing
+ echo 0 > events/eprobes/$EPROBE/enable
+
+-content=`grep '^ *ls-' trace | grep 'file='`
+-nocontent=`grep '^ *ls-' trace | grep 'file=' | grep -v -e '"/' -e '"."' -e '(fault)' ` || true
+-
++content=`grep -e 'file="/sys/kernel/tracing"\|(fault)' trace`
+ if [ -z "$content" ]; then
+ exit_fail
+ fi
+
+-if [ ! -z "$nocontent" ]; then
+- exit_fail
+-fi
+-
+ echo "-:$EPROBE" >> dynamic_events
+
+ ! grep -q "$EPROBE" dynamic_events
+--
+2.53.0
+
--- /dev/null
+From 0ada57190ae36b4a2ed98f85d13d52fbe4c085f3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jul 2026 09:59:55 +0000
+Subject: selftests/sched_ext: Handle sleeping task affinity changes in numa
+ test
+
+From: Kuba Piecuch <jpiecuch@google.com>
+
+[ Upstream commit d4a00d61a5c2c24973175ace5368d1f6acf9bb0a ]
+
+When a sleeping task's affinity is changed, task_cpu(p) can be outside
+of p->cpus_ptr until after select_task_rq() selects a new runqueue for
+the task during wakeup.
+
+Thus, the task's NUMA node determined by numa_select_cpu() can be
+completely outside of the task's cpumask, leading to
+scx_pick_{idle,any}_cpu_node() failing to find an eligible CPU and
+returning -EBUSY. This leads to the numa.bpf.c scheduler abnormally
+exiting with the following message in dmesg:
+
+sched_ext: numa: invalid CPU -16
+ scx_bpf_cpu_node+0x120/0x190
+ bpf_prog_0a34b8e0f515771f_numa_select_cpu+0x108/0x14e
+ bpf__sched_ext_ops_select_cpu+0x4f/0xb4
+ select_task_rq_scx+0xb0/0x210
+ select_task_rq+0xa0/0xd0
+ __try_to_wake_up+0x196/0x650
+ complete_all+0x76/0x100
+ migration_cpu_stop+0x22b/0x300
+ cpu_stopper_thread+0xc1/0x180
+ smpboot_thread_fn+0x16b/0x230
+ kthread+0x2d7/0x350
+ ret_from_fork+0x1c2/0x350
+ ret_from_fork_asm+0x1a/0x30
+
+Make numa_select_cpu() robust against this case by returning @prev_cpu
+if no CPU could be found in the selected NUMA node _and_ we have reason
+to believe that the task's affinity was changed while it was sleeping.
+
+Fixes: 5ae5161820e5 ("selftests/sched_ext: Add NUMA-aware scheduler test")
+Signed-off-by: Kuba Piecuch <jpiecuch@google.com>
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/sched_ext/numa.bpf.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/tools/testing/selftests/sched_ext/numa.bpf.c b/tools/testing/selftests/sched_ext/numa.bpf.c
+index 78cc49a7f9a67..6b4515c28aa0b 100644
+--- a/tools/testing/selftests/sched_ext/numa.bpf.c
++++ b/tools/testing/selftests/sched_ext/numa.bpf.c
+@@ -34,7 +34,8 @@ static bool is_cpu_idle(s32 cpu, int node)
+ s32 BPF_STRUCT_OPS(numa_select_cpu,
+ struct task_struct *p, s32 prev_cpu, u64 wake_flags)
+ {
+- int node = __COMPAT_scx_bpf_cpu_node(scx_bpf_task_cpu(p));
++ s32 task_cpu = scx_bpf_task_cpu(p);
++ int node = __COMPAT_scx_bpf_cpu_node(task_cpu);
+ s32 cpu;
+
+ /*
+@@ -48,6 +49,16 @@ s32 BPF_STRUCT_OPS(numa_select_cpu,
+ cpu = __COMPAT_scx_bpf_pick_any_cpu_node(p->cpus_ptr, node,
+ __COMPAT_SCX_PICK_IDLE_IN_NODE);
+
++ /*
++ * @task_cpu may be outside of p->cpus_ptr if @p's affinity
++ * changed while it was sleeping. This means it's possible for
++ * p->cpus_ptr to not include any CPUs from @node.
++ * If we failed to find a cpu in @node, check if @task_cpu
++ * is outside of p->cpus_ptr and just return @prev_cpu if it is.
++ */
++ if (cpu < 0 && !bpf_cpumask_test_cpu(task_cpu, p->cpus_ptr))
++ return prev_cpu;
++
+ if (is_cpu_idle(cpu, node))
+ scx_bpf_error("CPU %d should be marked as busy", cpu);
+
+--
+2.53.0
+
gpio-pca953x-fix-pca953x_irq_bus_sync_unlock-regmap-.patch
drm-amd-display-add-av-mute-wait-frames-to-dce110_se.patch
drm-amd-display-check-for-tg-ops-in-dce110_set_avmut.patch
+arm64-dts-qcom-glymur-fix-pcie-smmu-interrupts.patch
+arm64-dts-qcom-glymur-fix-qup-serial-engine-irqs.patch
+arm64-dts-qcom-purwa-fix-gpu-iommu-property.patch
+arm64-dts-qcom-monaco-add-default-gic-address-cells.patch
+arm64-dts-qcom-sm8650-fix-ipa-imem-slice.patch
+arm64-dts-qcom-sdm850-lenovo-yoga-c630-lower-psci-cl.patch
+sched_ext-reject-setting-disallow-from-init_task-out.patch
+sched_ext-skip-sub-disable-teardown-for-never-linked.patch
+sched_ext-don-t-enable-non-ext-tasks-in-the-sub-sche.patch
+nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch
+nfs-decrement-refcounts-if-allocating-nfs_free_state.patch
+arm64-dts-broadcom-bcm2712-remove-non-functional-el2.patch
+soc-aspeed-lpc-snoop-fix-usercopy-overflow-in-snoop_.patch
+xfs-handle-null-b_addr-in-xfs_buf_free.patch
+arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch
+selftests-sched_ext-handle-sleeping-task-affinity-ch.patch
+pinctrl-qcom-ipq806x-mark-gpio-as-a-gpio-pin-functio.patch
+pinctrl-qcom-ipq806x-mark-pci-reset-as-a-gpio-pin-fu.patch
+ovpn-add-missing-rtnl_link_ops-get_size-callback.patch
+arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch
+ovpn-skip-rehash-for-peers-already-removed-from-by_i.patch
+ovpn-rehash-peer-in-by_transp_addr-table-on-cmd_peer.patch
+ovpn-ensure-socket-is-owned-by-ovpn-before-deref-sk_.patch
+ovpn-zero-initialize-sockaddr-before-learning-a-floa.patch
+ovpn-hash-floated-peer-by-transport-identity-only.patch
+ovpn-disable-ipv4-redirects-on-mp-interfaces.patch
+ovpn-ensure-tcp-vars-are-initialized-first.patch
+ovpn-fix-incorrect-use-of-rcu_access_pointer.patch
+drm-bridge-ps8640-propagate-aux-transfer-register-er.patch
+net-hns3-fix-speed-configuration-residue-after-drive.patch
+revert-net-thunderbolt-enable-end-to-end-flow-contro.patch
+bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch
+enic-fix-tx_hang_reset-use-after-free-on-device-remo.patch
+net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch
+pds_core-keep-the-health-thread-stopped-during-reset.patch
+pds_core-cancel-pending-pci-reset-work-on-aer-recove.patch
+netfilter-ipset-switch-ext_size-to-atomic64_t.patch
+ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch
+ipvs-return-the-csum-validation-for-forward-hook.patch
+watchdog-bd96801_wdt-fix-timeout-for-enabled-wdg.patch
+btrfs-lzo-add-error-message-for-invalid-headers.patch
+btrfs-lzo-reject-inline-extents-without-valid-header.patch
+btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch
+btrfs-move-large-data-folios-out-of-experimental-fea.patch
+btrfs-disable-bs-ps-support-if-no-transparent-hugepa.patch
+btrfs-initialize-inode-mapping-flags-for-cached-inod.patch
+accel-amxdna-fix-page-insertion-errors-in-amdxdna_in.patch
+bpf-preserve-pointer-state-for-commuted-arithmetic.patch
+bpf-propagate-untrusted-pointer-state-in-commuted-ar.patch
+net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch
+net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch
+net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch
+devlink-fix-net-namespace-reference-leak-in-reload.patch
+net-mlx5-fw_tracer-return-null-on-create-error.patch
+accel-amdxdna-fix-locally-exploitable-bug_on-in-amdx.patch
+bpf-fix-netns-reference-imbalance-in-conntrack-kfunc.patch
+counter-microchip-tcb-capture-fix-dt-channel-validat.patch
+bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch
+alsa-usb-audio-add-quirk_flag_mixer_get_cur_broken.patch
+alsa-usb-audio-add-quirk_flag_mixer_get_cur_broken-f.patch
+vhost_iotlb-bound-map-allocation-in-add_range.patch
+vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch
+vdpa-mlx5-fix-buffer-length-in-create_direct_keys.patch
+hwmon-pmbus-core-avoid-race-condition-during-probe.patch
+hwmon-pmbus-fix-type-confusion-in-notification-logic.patch
+tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch
+bnxt-fix-memory-leak-in-bnxt_queue_mem_alloc-error-c.patch
+xsk-require-at-least-16-bytes-of-tx-metadata.patch
+xsk-pass-tx-metadata-pointer-by-reference.patch
+xsk-clear-metadata-pointer-when-no-timestamp-is-requ.patch
+xsk-validate-launch-time-metadata-size.patch
+xsk-move-xsk_tx_metadata_request-to-xdp_sock_drv.h.patch
+xsk-validate-metadata-when-processing-requests.patch
+bnge-fix-null-pointer-dereference-in-aux-device-rele.patch
+udp-fix-potential-use-after-free-in-tunnel-segmentat.patch
+net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch
+vhost-scsi-validate-t10-pi-scatterlist-counts.patch
+vhost-scsi-reject-feature-changes-after-endpoint.patch
+net-openvswitch-check-ethernet-header-length-in-key_.patch
+net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch
+drm-xe-fix-memory-leak-in-exec_queue_set_hang_replay.patch
+drm-xe-uc-apply-rcs-ccs-yield-policy-to-sr-iov-vfs.patch
+hwmon-nzxt-smart2-check-return-value-of-init_device-.patch
+hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch
+selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch
+net-stmmac-resume-phy-before-hardware-setup-when-ope.patch
+bnge-use-int-for-bnge_fix_rings_count-return-value.patch
+net-mlx5e-fix-bql-reset-on-sq-re-activation.patch
+bnxt_en-move-rss-table-fill-outside-__bnxt_hwrm_vnic.patch
+bnxt_en-determine-and-store-default-rx-ring-in-vnic-.patch
+bnxt_en-refresh-vnic-default-ring-on-queue-restart-i.patch
+bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch
+bnxt_en-fix-ptp-pps-setting-bug.patch
+sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch
+bpf-check-sk_state-before-sk_protocol-in-bpf_tcp_-_s.patch
+tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch
+netfilter-nf_flow_table-drop-existing-skb-dst-before.patch
+net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch
+net-prestera-validate-firmware-header-length.patch
+net-remove-warn_on_once-from-sk_mc_loop.patch
+net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch
+net-qrtr-ns-raise-lookup-limit-to-128.patch
+net-thunderbolt-tear-down-dma-paths-before-stopping-.patch
+ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch
+bnge-fix-resource-leak-in-bnge_init_nic-error-path.patch
+s390-ism-fix-uaf-of-sba-and-ieq-during-ism_dev_exit.patch
+net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch
+sctp-clear-control-chunk-transport-if-it-is-being-re.patch
+tls-don-t-abort-the-connection-on-signal-interrupted.patch
+watchdog-at91sam9_wdt-prevent-timer-rearm-during-tea.patch
+rqspinlock-reset-tail-when-preserving-queue-on-deadl.patch
+hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch
+hwmon-ads7828-fix-external-vref-regulator-handling.patch
+hwmon-ltc4282-avoid-overflow-in-maximum-power-calcul.patch
+hwmon-ltc4282-clamp-negative-current-limits.patch
+hwmon-ltc4282-fix-parsing-adi-current-limit-sense-mi.patch
+hwmon-support-guard-and-scoped_guard-for-subsystem-l.patch
+hwmon-corsair-psu-serialize-debugfs-access-against-h.patch
+alsa-usb-audio-fix-sticky-mixer-regressions-on-m-aud.patch
--- /dev/null
+From 893957595ada0b0557f3cb1fde74cfe8764e6041 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 12 Jun 2026 19:07:43 +0000
+Subject: soc: aspeed: lpc-snoop: Fix usercopy overflow in snoop_file_read
+
+From: Karthikeyan KS <karthiproffesional@gmail.com>
+
+[ Upstream commit 1acef6d85bfd98bd9dfe1f08bffa397a4dda8a6f ]
+
+put_fifo_with_discard() acts as both producer and consumer on the kfifo:
+it calls kfifo_skip() (advances out) and kfifo_put() (advances in) from
+the IRQ handler without synchronizing with snoop_file_read(), which also
+consumes via kfifo_to_user(). On SMP systems this concurrent access can
+leave (in - out) larger than the ring buffer, so __kfifo_to_user()'s clamp
+to (in - out) is ineffective and kfifo_copy_to_user() can attempt a
+copy_to_user() past the kmalloc-2k backing store:
+
+ usercopy: Kernel memory exposure attempt detected from SLUB object
+ 'kmalloc-2k' (offset 0, size 2049)!
+ kernel BUG at mm/usercopy.c!
+ Call trace:
+ usercopy_abort
+ __check_heap_object
+ __check_object_size
+ kfifo_copy_to_user
+ __kfifo_to_user
+ snoop_file_read
+ vfs_read
+
+Serialize kfifo access with a per-channel spinlock shared between the
+IRQ handler (producer) and the file reader (consumer). Annotate @fifo
+with __guarded_by(&lock) and opt the driver into context analysis so the
+compiler enforces that all fifo access holds the lock.
+
+Fixes: 3772e5da4454 ("drivers/misc: Aspeed LPC snoop output using misc chardev")
+Signed-off-by: Karthikeyan KS <karthiproffesional@gmail.com>
+Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/aspeed/Makefile | 1 +
+ drivers/soc/aspeed/aspeed-lpc-snoop.c | 38 ++++++++++++++++++---------
+ 2 files changed, 27 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile
+index b35d745929646..b5188dcde37a7 100644
+--- a/drivers/soc/aspeed/Makefile
++++ b/drivers/soc/aspeed/Makefile
+@@ -4,3 +4,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
+ obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o
+ obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o
+ obj-$(CONFIG_ASPEED_SOCINFO) += aspeed-socinfo.o
++CONTEXT_ANALYSIS_aspeed-lpc-snoop.o := y
+diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c
+index b03310c0830d2..7fa1a345acacc 100644
+--- a/drivers/soc/aspeed/aspeed-lpc-snoop.c
++++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c
+@@ -11,6 +11,7 @@
+ */
+
+ #include <linux/bitops.h>
++#include <linux/cleanup.h>
+ #include <linux/clk.h>
+ #include <linux/dev_printk.h>
+ #include <linux/interrupt.h>
+@@ -74,7 +75,8 @@ struct aspeed_lpc_snoop_channel_cfg {
+ struct aspeed_lpc_snoop_channel {
+ const struct aspeed_lpc_snoop_channel_cfg *cfg;
+ bool enabled;
+- struct kfifo fifo;
++ spinlock_t lock;
++ struct kfifo fifo __guarded_by(&lock);
+ wait_queue_head_t wq;
+ struct miscdevice miscdev;
+ };
+@@ -114,6 +116,7 @@ static ssize_t snoop_file_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+ {
+ struct aspeed_lpc_snoop_channel *chan = snoop_file_to_chan(file);
++ u8 *buf __free(kfree) = NULL;
+ unsigned int copied;
+ int ret = 0;
+
+@@ -125,9 +128,16 @@ static ssize_t snoop_file_read(struct file *file, char __user *buffer,
+ if (ret == -ERESTARTSYS)
+ return -EINTR;
+ }
+- ret = kfifo_to_user(&chan->fifo, buffer, count, &copied);
+- if (ret)
+- return ret;
++
++ count = min_t(size_t, count, SNOOP_FIFO_SIZE);
++
++ buf = kmalloc(count, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ copied = kfifo_out_spinlocked(&chan->fifo, buf, count, &chan->lock);
++ if (copied && copy_to_user(buffer, buf, copied))
++ return -EFAULT;
+
+ return copied;
+ }
+@@ -151,11 +161,13 @@ static const struct file_operations snoop_fops = {
+ /* Save a byte to a FIFO and discard the oldest byte if FIFO is full */
+ static void put_fifo_with_discard(struct aspeed_lpc_snoop_channel *chan, u8 val)
+ {
+- if (!kfifo_initialized(&chan->fifo))
+- return;
+- if (kfifo_is_full(&chan->fifo))
+- kfifo_skip(&chan->fifo);
+- kfifo_put(&chan->fifo, val);
++ scoped_guard(spinlock, &chan->lock) {
++ if (!kfifo_initialized(&chan->fifo))
++ return;
++ if (kfifo_is_full(&chan->fifo))
++ kfifo_skip(&chan->fifo);
++ kfifo_put(&chan->fifo, val);
++ }
+ wake_up_interruptible(&chan->wq);
+ }
+
+@@ -239,9 +251,11 @@ static int aspeed_lpc_enable_snoop(struct device *dev,
+ if (!channel->miscdev.name)
+ return -ENOMEM;
+
+- rc = kfifo_alloc(&channel->fifo, SNOOP_FIFO_SIZE, GFP_KERNEL);
+- if (rc)
+- return rc;
++ scoped_guard(spinlock_init, &channel->lock) {
++ rc = kfifo_alloc(&channel->fifo, SNOOP_FIFO_SIZE, GFP_KERNEL);
++ if (rc)
++ return rc;
++ }
+
+ rc = misc_register(&channel->miscdev);
+ if (rc)
+--
+2.53.0
+
--- /dev/null
+From c0319886e76a9d831c14a9f2b602e99046babf0a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jul 2026 20:08:06 -0700
+Subject: tcp: do not change rcv_ssthresh in tcp_measure_rcv_mss()
+
+From: Nathan Gao <zcgao@amazon.com>
+
+[ Upstream commit 0e125ecfe20c077625cf0be8d750d5c3abc0dce9 ]
+
+Commit f5da7c45188e ("tcp: adjust rcvq_space after updating scaling
+ratio") replaced the direct window_clamp update in tcp_measure_rcv_mss()
+with a call to tcp_set_window_clamp(), a helper that implements the
+TCP_WINDOW_CLAMP setsockopt. As a side effect, the helper also shrinks
+rcv_ssthresh via __tcp_adjust_rcv_ssthresh().
+
+As a result, each scaling_ratio decrease detected by
+tcp_measure_rcv_mss() also cuts rcv_ssthresh. Elsewhere in TCP,
+rcv_ssthresh is usually cut under memory pressure and grows via
+tcp_grow_window().
+
+Flows whose segment sizes vary keep scaling_ratio oscillating, which
+leads to an unstable rcv_ssthresh: a dip of rcv_ssthresh only recovers
+via tcp_grow_window(), keeping the advertised window at a relatively
+low level even after the ratio itself has recovered, and can even stall
+the sender.
+
+Observed on a customer's proxy gateway after upgrading from kernel 6.1
+to 6.12: in the worst case, rcv_ssthresh was cut in half by a
+scaling_ratio dip. P99 latency jumped from <10ms on 6.1 to ~100ms on
+6.12, and almost returned to the 6.1 level with this patch applied.
+
+Restore the plain WRITE_ONCE() update of window_clamp, as introduced
+in commit a2cbb1603943 ("tcp: Update window clamping condition"), and
+keep the rcvq_space.space adjustment. Now rcv_ssthresh is decoupled from
+scaling_ratio changes in tcp_measure_rcv_mss().
+
+Fixes: f5da7c45188e ("tcp: adjust rcvq_space after updating scaling ratio")
+Signed-off-by: Nathan Gao <zcgao@amazon.com>
+Link: https://patch.msgid.link/20260725030806.28135-1-zcgao@amazon.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_input.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
+index eed808c2adbb5..e2c022f02c644 100644
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -252,7 +252,7 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb)
+ struct tcp_sock *tp = tcp_sk(sk);
+
+ val = tcp_win_from_space(sk, sk->sk_rcvbuf);
+- tcp_set_window_clamp(sk, val);
++ WRITE_ONCE(tp->window_clamp, val);
+
+ if (tp->window_clamp < tp->rcvq_space.space)
+ tp->rcvq_space.space = tp->window_clamp;
+--
+2.53.0
+
--- /dev/null
+From f3ba535f5118933506bcc2198a4dc0d2286eb1a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 14:17:38 +0800
+Subject: tcp: fix TFO max_qlen accounting across reuseport migration
+
+From: Jiayuan Chen <jiayuan.chen@linux.dev>
+
+[ Upstream commit a0ab2ba83e35159d81cec830a92e885ecf8139be ]
+
+A listener's TCP_FASTOPEN max_qlen stops being accurate and lets through
+far more pending Fast Open requests than it was configured for.
+
+This only shows up with SO_REUSEPORT listener migration, where closing a
+listener hands its still-pending TFO children over to a surviving one.
+
+fastopenq.qlen is charged in tcp_fastopen_create_child() when the child
+is created and uncharged in reqsk_fastopen_remove() when the handshake
+completes. The uncharge follows rsk_listener of the request the child
+points at, and inet_reqsk_clone() has repointed the child at a new
+request owned by the new listener, so the ++ and the -- land on two
+different sockets. The new listener's qlen drifts negative and its
+limit no longer binds.
+
+Charge the new listener during migration, like reqsk_queue_migrated()
+already does for queue->young and queue->qlen.
+
+Fixes: 54b92e841937 ("tcp: Migrate TCP_ESTABLISHED/TCP_SYN_RECV sockets in accept queues.")
+Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260803061739.134737-1-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/inet_connection_sock.c | 20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
+index 690f7fb3f029e..935b46db61541 100644
+--- a/net/ipv4/inet_connection_sock.c
++++ b/net/ipv4/inet_connection_sock.c
+@@ -946,11 +946,23 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req,
+
+ nreq->rsk_listener = sk;
+
+- /* We need not acquire fastopenq->lock
+- * because the child socket is locked in inet_csk_listen_stop().
+- */
+- if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener)
++ if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener) {
++ struct fastopen_queue *fastopenq;
++
++ /* reqsk_fastopen_remove() will uncharge nreq->rsk_listener,
++ * that is @sk, so charge it here. Unlike the listener
++ * being closed, @sk is live and needs its lock.
++ */
++ fastopenq = &inet_csk(sk)->icsk_accept_queue.fastopenq;
++ spin_lock_bh(&fastopenq->lock);
++ fastopenq->qlen++;
++ spin_unlock_bh(&fastopenq->lock);
++
++ /* We need not acquire fastopenq->lock
++ * because the child socket is locked in inet_csk_listen_stop().
++ */
+ rcu_assign_pointer(tcp_sk(nreq->sk)->fastopen_rsk, nreq);
++ }
+
+ return nreq;
+ }
+--
+2.53.0
+
--- /dev/null
+From 9d0a48e0d834347f3e32ec1af19476bdf8ed47e3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 08:22:48 +0200
+Subject: tls: don't abort the connection on signal-interrupted sends
+
+From: Maximilian Immanuel Brandtner <maxbr@linux.ibm.com>
+
+[ Upstream commit af0e5cdd031f4f4a8f6d4160bfbda4f36872b0ed ]
+
+When a signal interrupts a blocking send, tls_tx_records() treats the
+resulting -ERESTARTSYS as a transmission failure and marks the socket
+errored via tls_err_abort() with the raw error code. Later syscalls
+return the kernel-internal errno 512 (ERESTARTSYS) to userspace, as the
+signal it stems from is no longer pending during syscall exit and thus
+never translated.
+
+An interrupted send is not a connection error: the partially sent record
+stays queued and is resent later. Interrupt error codes are therefore
+excluded from the abort in the same way as -EAGAIN.
+
+Fixes: b341ca51d267 ("tls: Fix tls_sw_sendmsg error handling")
+Signed-off-by: Maximilian Immanuel Brandtner <maxbr@linux.ibm.com>
+Link: https://patch.msgid.link/20260805063109.1772314-1-maxbr@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tls/tls_sw.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
+index ba95f9d927a35..a8c3adc0fad0a 100644
+--- a/net/tls/tls_sw.c
++++ b/net/tls/tls_sw.c
+@@ -458,7 +458,7 @@ int tls_tx_records(struct sock *sk, int flags)
+ }
+
+ tx_err:
+- if (rc < 0 && rc != -EAGAIN)
++ if (rc < 0 && rc != -EAGAIN && rc != -EINTR && rc != -ERESTARTSYS)
+ tls_err_abort(sk, rc);
+
+ return rc;
+--
+2.53.0
+
--- /dev/null
+From 4d887cfb549136a384554092992fa1717cca2bca Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 17:35:54 +0800
+Subject: udp: fix potential use-after-free in tunnel segmentation
+
+From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+
+[ Upstream commit d0f86fb36eb260abd10007b62c9dcc1028e03e61 ]
+
+__skb_udp_tunnel_segment() gets the UDP header before ensuring the
+tunnel header is in the skb head. If the pull reallocates skb->head,
+the saved UDP header pointer is no longer valid.
+
+Get the UDP header after the pull to avoid a potential use-after-free.
+
+Fixes: dbef491ebe7f ("udp: Use uh->len instead of skb->len to compute checksum in segmentation")
+Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+Reviewed-by: Antoine Tenart <atenart@kernel.org>
+Link: https://patch.msgid.link/20260730093554.68127-1-xuanqiang.luo@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/udp_offload.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
+index 29651b1a0bc70..abcd3cc2d9a38 100644
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -178,17 +178,19 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
+ int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
+ bool remcsum, need_csum, offload_csum, gso_partial;
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+- struct udphdr *uh = udp_hdr(skb);
+ u16 mac_offset = skb->mac_header;
+ __be16 protocol = skb->protocol;
+ u16 mac_len = skb->mac_len;
+ int udp_offset, outer_hlen;
++ struct udphdr *uh;
+ __wsum partial;
+ bool need_ipsec;
+
+ if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
+ goto out;
+
++ uh = udp_hdr(skb);
++
+ /* Adjust partial header checksum to negate old length.
+ * We cannot rely on the value contained in uh->len as it is
+ * possible that the actual value exceeds the boundaries of the
+--
+2.53.0
+
--- /dev/null
+From 50bf7bb5aae5e875c8024d78aa49378684d33244 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 6 Jul 2026 16:15:37 +0200
+Subject: vdpa/mlx5: Fix buffer length in create_direct_keys()
+
+From: Christian Borntraeger <borntraeger@linux.ibm.com>
+
+[ Upstream commit 727e1f569855df83579edbd73dcb4a0723543a12 ]
+
+We have seen in our CI the following KASAN message:
+BUG: KASAN: slab-out-of-bounds in cmd_exec+0x550/0xca0 [mlx5_core]
+Read of size 272 at addr 0000000176795020 by task qemu-system-s39/82764
+[...]
+[<000011388ab3a7a0>] cmd_exec+0x550/0xca0 [mlx5_core]
+[<000011388ab3b61c>] mlx5_cmd_exec_cb+0x25c/0x4f0 [mlx5_core]
+[<000011388b21e82e>] mlx5_vdpa_exec_async_cmds+0x22e/0x5e0 [mlx5_vdpa]
+[<000011388b21fd44>] create_direct_keys+0x954/0xef0 [mlx5_vdpa]
+[...]
+The buggy address is located 4128 bytes inside of
+allocated 4384-byte region [0000000176794000, 0000000176795120)
+
+So in essence we read 16 bytes beyond 4384-byte allocation.
+create_direct_keys calculates the pointer and length for in and out
+buffers.
+The size calculation for in includes the entire structure
+size (out + in + mtt[]) but the pointer passed to cmd_exec points only
+to the 'in' field, skipping the 'out' field.
+
+This causes mlx5_copy_to_msg() to read beyond the allocated buffer
+by sizeof(out) bytes when copying command data.
+
+Properly calculate the input size to match the pointer and allocation size.
+
+Fixes: 0071b138d44a ("vdpa/mlx5: Create direct MKEYs in parallel")
+Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
+Tested-by: Dragos Tatulea <dtatulea@nvidia.com>
+Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Message-ID: <20260706141537.3510294-1-borntraeger@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vdpa/mlx5/core/mr.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c
+index deb56e948f785..ce204ae3dfda3 100644
+--- a/drivers/vdpa/mlx5/core/mr.c
++++ b/drivers/vdpa/mlx5/core/mr.c
+@@ -234,7 +234,8 @@ static int create_direct_keys(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *
+ cmds[i].out = cmd_mem->out;
+ cmds[i].outlen = sizeof(cmd_mem->out);
+ cmds[i].in = cmd_mem->in;
+- cmds[i].inlen = struct_size(cmd_mem, mtt, mttcount);
++ cmds[i].inlen = struct_size(cmd_mem, mtt, mttcount) -
++ offsetof(struct mlx5_create_mkey_mem, in);
+
+ fill_create_direct_mr(mvdev, dmr, cmd_mem);
+
+--
+2.53.0
+
--- /dev/null
+From 41015a3d10237e553b63a38eb14decb24534cf9b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 26 Jul 2026 22:43:14 +0800
+Subject: vhost-scsi: reject feature changes after endpoint
+
+From: Jia Jia <physicalmtea@gmail.com>
+
+[ Upstream commit 42bc45df5905e2b7dccb72adaf7730f66cfbe03f ]
+
+vhost_scsi_setup_vq_cmds() runs from VHOST_SCSI_SET_ENDPOINT and allocates
+each command's protection scatterlist array (prot_sgl) according to the
+acknowledged VIRTIO_SCSI_F_T10_PI bit. The command pools are not rebuilt
+when VHOST_SET_FEATURES changes that bit later.
+
+Although virtio feature bits must not change after feature negotiation,
+vhost_scsi_set_features() currently accepts such a request after the
+endpoint is active and updates acked_features. Enabling T10-PI after
+endpoint setup therefore leaves prot_sgl NULL while the I/O path follows
+the new feature bit.
+
+For a 129-page protection payload, vhost_scsi_mapal() passes the missing
+first chunk to sg_alloc_table_chained():
+
+ sg_alloc_table_chained(table, 129, first_chunk=NULL,
+ nents_first_chunk=inline_sg_cnt)
+
+sg_pool_index() then hits:
+
+ BUG_ON(nents > SG_CHUNK_SIZE); /* 129 > 128 */
+
+The kernel reported the following call trace and register state:
+
+ Call Trace:
+ <TASK>
+ ? __sg_alloc_table+0x1d8/0x250
+ ? __pfx_vhost_run_work_list+0x10/0x10 [vhost]
+ sg_alloc_table_chained+0x59/0xf0
+ ? __pfx_sg_pool_alloc+0x10/0x10
+ ? vhost_scsi_calc_sgls.constprop.0+0x43/0x60 [vhost_scsi]
+ vhost_scsi_handle_vq+0xf02/0x1700 [vhost_scsi]
+ ? __pfx_vhost_scsi_handle_vq+0x10/0x10 [vhost_scsi]
+ vhost_scsi_handle_kick+0x37/0x50 [vhost_scsi]
+ vhost_run_work_list+0x8e/0xd0 [vhost]
+ vhost_task_fn+0xe1/0x210
+ ret_from_fork+0x348/0x540
+ </TASK>
+
+ RIP: 0010:0x4
+ CR2 = 0x4
+ RSP: 0018:ffffc90000dbf940 EFLAGS: 00010202
+ RAX: ffffffff82396810 RBX: ffff88811dc28b80 RCX: 0000000000000000
+ RDX: 0000000000000000 RSI: 0000000000000820 RDI: 0000000000000081
+
+VHOST_F_LOG_ALL is a vhost-specific runtime feature and remains the only
+exception.
+
+Reject changes to any feature other than VHOST_F_LOG_ALL while the
+endpoint is active. This preserves the existing runtime log toggle while
+preventing feature-dependent command resources and data-path state from
+becoming inconsistent. Userspace must clear the endpoint before changing
+any other negotiated feature and set the endpoint up again afterward.
+
+Fixes: bf2d650391be ("vhost-scsi: Allocate T10 PI structs only when enabled")
+Signed-off-by: Jia Jia <physicalmtea@gmail.com>
+Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Message-ID: <20260726144314.1652934-1-physicalmtea@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vhost/scsi.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
+index c79197edb1637..904bd842cdd84 100644
+--- a/drivers/vhost/scsi.c
++++ b/drivers/vhost/scsi.c
+@@ -2227,6 +2227,7 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
+ {
+ struct vhost_virtqueue *vq;
+ bool is_log, was_log;
++ u64 old_features;
+ int i;
+
+ if (features & ~VHOST_SCSI_FEATURES)
+@@ -2242,6 +2243,14 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
+ if (!vs->dev.nvqs)
+ goto out;
+
++ old_features = vs->vqs[0].vq.acked_features;
++ if (vs->vs_tpg &&
++ ((features ^ old_features) &
++ ~(1ULL << VHOST_F_LOG_ALL))) {
++ mutex_unlock(&vs->dev.mutex);
++ return -EBUSY;
++ }
++
+ is_log = features & (1 << VHOST_F_LOG_ALL);
+ /*
+ * All VQs should have same feature.
+--
+2.53.0
+
--- /dev/null
+From cbac41a9e7cc85a5510128b6215d867dbe6460b5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 16:18:41 +0800
+Subject: vhost-scsi: Validate T10 PI scatterlist counts
+
+From: Linfeng Sun <slf@hdu.edu.cn>
+
+[ Upstream commit d876c493fc4b811941bfeb4c80beb2dfc4bf025e ]
+
+When T10 PI is negotiated, vhost-scsi splits protection bytes from
+the data iterator before mapping the request scatterlists. A malformed
+request can claim protection bytes that cover or exceed the full payload
+length. The former leaves no data bytes to map, while the latter
+underflows exp_data_len before advancing the iterator. Both cases can let
+a zero data SGL count reach sg_alloc_table_chained(), which triggers
+BUG_ON(!nents).
+
+Reject protection lengths that cover or exceed the payload before
+subtracting prot_bytes and advancing the iterator. Also propagate
+negative errors from the protection SGL calculation before calling the
+allocator, matching the data SGL path.
+
+Fixes: bca939d5bcd0 ("vhost-scsi: Dynamically allocate scatterlists")
+Suggested-by: Jia Jia <physicalmtea@gmail.com>
+Signed-off-by: Jia Jia <physicalmtea@gmail.com>
+Assisted-by: OpenAI-Codex:GPT-5
+Signed-off-by: Linfeng Sun <linfeng.sun.dev@gmail.com>
+Message-ID: <20260727081841.923151-1-slf@hdu.edu.cn>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vhost/scsi.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
+index 9a1253b9d8c50..c79197edb1637 100644
+--- a/drivers/vhost/scsi.c
++++ b/drivers/vhost/scsi.c
+@@ -972,6 +972,9 @@ vhost_scsi_mapal(struct vhost_scsi *vs, struct vhost_scsi_cmd *cmd,
+ if (prot_bytes) {
+ sgl_count = vhost_scsi_calc_sgls(prot_iter, prot_bytes,
+ VHOST_SCSI_PREALLOC_PROT_SGLS);
++ if (sgl_count < 0)
++ return sgl_count;
++
+ cmd->prot_table.sgl = cmd->prot_sgl;
+ ret = sg_alloc_table_chained(&cmd->prot_table, sgl_count,
+ cmd->prot_table.sgl,
+@@ -1416,6 +1419,11 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
+ * actual data payload length.
+ */
+ if (prot_bytes) {
++ if (prot_bytes >= exp_data_len) {
++ vq_err(vq, "Protection data exceeds payload length\n");
++ goto err;
++ }
++
+ exp_data_len -= prot_bytes;
+ prot_iter = data_iter;
+ iov_iter_truncate(&prot_iter, prot_bytes);
+--
+2.53.0
+
--- /dev/null
+From e7db3f64447716fe57d50db75a68cca25e533410 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Jun 2026 15:02:02 -0700
+Subject: vhost/vdpa: reject overflowing PA map page counts on 32-bit
+
+From: Yousef Alhouseen <alhouseenyousef@gmail.com>
+
+[ Upstream commit 0619aaa34c0c2a2dcb07f0e9c8a34e7efb8c4cdf ]
+
+vhost_vdpa_pa_map() adds the IOVA page offset to the user-controlled map
+size before computing the number of pages to pin. On 32-bit systems,
+where unsigned long is narrower than u64, that addition can overflow and
+the code can pin and map fewer pages than the requested IOTLB range.
+
+Reject sizes that overflow the unsigned long page-count calculation.
+
+Fixes: 22af48cf91aa ("vdpa: factor out vhost_vdpa_pa_map() and vhost_vdpa_pa_unmap()")
+Acked-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Message-ID: <CAMuQ4bX-iDvcUOPPY+NLz95tkRJYwWqvzAr=U48uNaub_HZLGw@mail.gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vhost/vdpa.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
+index ef642bc9f97e1..c3d913bd7cac7 100644
+--- a/drivers/vhost/vdpa.c
++++ b/drivers/vhost/vdpa.c
+@@ -1109,6 +1109,7 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
+ unsigned int gup_flags = FOLL_LONGTERM;
+ unsigned long npages, cur_base, map_pfn, last_pfn = 0;
+ unsigned long lock_limit, sz2pin, nchunks, i;
++ unsigned long page_offset;
+ u64 start = iova;
+ long pinned;
+ int ret = 0;
+@@ -1121,7 +1122,13 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
+ if (perm & VHOST_ACCESS_WO)
+ gup_flags |= FOLL_WRITE;
+
+- npages = PFN_UP(size + (iova & ~PAGE_MASK));
++ page_offset = iova & ~PAGE_MASK;
++ if (size > ULONG_MAX - page_offset) {
++ ret = -EINVAL;
++ goto free;
++ }
++
++ npages = PFN_UP(size + page_offset);
+ if (!npages) {
+ ret = -EINVAL;
+ goto free;
+--
+2.53.0
+
--- /dev/null
+From 9cf7692bd15012285dfa28e3de0a11cb858a16b1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 20 Jun 2026 21:00:05 +0800
+Subject: vhost_iotlb: bound map allocation in add_range
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Linfeng Sun <linfeng.sun.dev@gamil.com>
+
+[ Upstream commit 1ed35ac7f3fe2b4396bdd29ac3a7f0ebc0829e94 ]
+
+vhost_iotlb_add_range_ctx() only retires an old entry when the table
+has a non-zero limit, has exactly reached that limit and has
+VHOST_IOTLB_FLAG_RETIRE set. Non-retiring tables can keep allocating
+entries after reaching their configured limit.
+
+Existing vhost devices allocate their IOTLB with max_iotlb_entries from
+vhost.c, which defaults to 2048 and is tunable by module parameter. Use
+the caller-provided limit at the allocation point instead of adding a
+separate default in the common IOTLB helper, and reject non-positive
+values in vhost paths that can report an error.
+
+Other vhost IOTLB users should not create zero-limit tables when entries
+can be populated from userspace or guest-controlled requests. Add
+caller-side max_iotlb_entries parameters for mlx5 vDPA, VDUSE and
+vhost-vDPA. Reject non-positive VDUSE and vhost-vDPA values, and require
+at least two entries for vdpa_sim and mlx5 vDPA paths that install
+full-range mappings, since those mappings are split into two IOTLB
+entries.
+
+Handle full-range mappings in the common helper by checking that the
+IOTLB can hold both split entries before inserting the first half. This
+avoids returning an error after leaving a half mapping behind.
+
+When the table is full, keep the existing retire behavior for retiring
+tables and return -ENOSPC for non-retiring tables. Reuse the retired map
+node instead of freeing it and allocating a replacement, so a stream of
+IOTLB updates cannot keep forcing GFP_ATOMIC allocations after the table
+has reached its limit. If a zero-limit IOTLB still reaches the common
+helper, treat it as a configuration error and return -EINVAL.
+
+I found this bug myself, though the patch was written with AI assistance.
+
+Fixes: 0bbe30668d89 ("vhost: factor out IOTLB")
+Assisted-by: OpenAI-Codex:GPT-5
+Signed-off-by: Linfeng Sun <linfeng.sun.dev@gamil.com>
+Message-ID: <AMYAtgAiKmgYcSQT5ukl-4qq.3.1781960405943.Hmail.241270009@hdu.edu.cn>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vdpa/mlx5/core/mlx5_vdpa.h | 2 ++
+ drivers/vdpa/mlx5/core/mr.c | 5 ++-
+ drivers/vdpa/mlx5/core/resources.c | 11 ++++++-
+ drivers/vdpa/vdpa_sim/vdpa_sim.c | 10 ++++--
+ drivers/vdpa/vdpa_user/iova_domain.c | 11 ++++++-
+ drivers/vhost/iotlb.c | 47 +++++++++++++++++++---------
+ drivers/vhost/vdpa.c | 9 +++++-
+ drivers/vhost/vhost.c | 8 +++++
+ 8 files changed, 82 insertions(+), 21 deletions(-)
+
+diff --git a/drivers/vdpa/mlx5/core/mlx5_vdpa.h b/drivers/vdpa/mlx5/core/mlx5_vdpa.h
+index 2cedf7e2dbc49..42f2f44b383c7 100644
+--- a/drivers/vdpa/mlx5/core/mlx5_vdpa.h
++++ b/drivers/vdpa/mlx5/core/mlx5_vdpa.h
+@@ -11,6 +11,8 @@
+
+ #define MLX5V_ETH_HARD_MTU (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)
+
++extern int mlx5_vdpa_max_iotlb_entries;
++
+ struct mlx5_vdpa_direct_mr {
+ u64 start;
+ u64 end;
+diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c
+index 42c2705077a6d..deb56e948f785 100644
+--- a/drivers/vdpa/mlx5/core/mr.c
++++ b/drivers/vdpa/mlx5/core/mr.c
+@@ -777,6 +777,9 @@ static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
+ {
+ int err;
+
++ if (mlx5_vdpa_max_iotlb_entries < 2)
++ return -EINVAL;
++
+ if (iotlb)
+ err = create_user_mr(mvdev, mr, iotlb);
+ else
+@@ -785,7 +788,7 @@ static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
+ if (err)
+ return err;
+
+- mr->iotlb = vhost_iotlb_alloc(0, 0);
++ mr->iotlb = vhost_iotlb_alloc(mlx5_vdpa_max_iotlb_entries, 0);
+ if (!mr->iotlb) {
+ err = -ENOMEM;
+ goto err_mr;
+diff --git a/drivers/vdpa/mlx5/core/resources.c b/drivers/vdpa/mlx5/core/resources.c
+index aeae31d0cefae..28a4d7a35bf4e 100644
+--- a/drivers/vdpa/mlx5/core/resources.c
++++ b/drivers/vdpa/mlx5/core/resources.c
+@@ -3,8 +3,14 @@
+
+ #include <linux/iova.h>
+ #include <linux/mlx5/driver.h>
++#include <linux/moduleparam.h>
+ #include "mlx5_vdpa.h"
+
++int mlx5_vdpa_max_iotlb_entries = 2048;
++module_param_named(max_iotlb_entries, mlx5_vdpa_max_iotlb_entries, int, 0444);
++MODULE_PARM_DESC(max_iotlb_entries,
++ "Maximum number of iotlb entries. (default: 2048)");
++
+ static int alloc_pd(struct mlx5_vdpa_dev *dev, u32 *pdn, u16 uid)
+ {
+ struct mlx5_core_dev *mdev = dev->mdev;
+@@ -229,7 +235,10 @@ int mlx5_vdpa_destroy_mkey(struct mlx5_vdpa_dev *mvdev, u32 mkey)
+
+ static int init_ctrl_vq(struct mlx5_vdpa_dev *mvdev)
+ {
+- mvdev->cvq.iotlb = vhost_iotlb_alloc(0, 0);
++ if (mlx5_vdpa_max_iotlb_entries < 2)
++ return -EINVAL;
++
++ mvdev->cvq.iotlb = vhost_iotlb_alloc(mlx5_vdpa_max_iotlb_entries, 0);
+ if (!mvdev->cvq.iotlb)
+ return -ENOMEM;
+
+diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c
+index 8cb1cc2ea1391..4d116644851d9 100644
+--- a/drivers/vdpa/vdpa_sim/vdpa_sim.c
++++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c
+@@ -34,7 +34,7 @@ MODULE_PARM_DESC(batch_mapping, "Batched mapping 1 -Enable; 0 - Disable");
+ static int max_iotlb_entries = 2048;
+ module_param(max_iotlb_entries, int, 0444);
+ MODULE_PARM_DESC(max_iotlb_entries,
+- "Maximum number of iotlb entries for each address space. 0 means unlimited. (default: 2048)");
++ "Maximum number of iotlb entries for each address space. (default: 2048)");
+
+ static bool use_va = true;
+ module_param(use_va, bool, 0444);
+@@ -201,6 +201,8 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,
+
+ if (!dev_attr->alloc_size)
+ return ERR_PTR(-EINVAL);
++ if (max_iotlb_entries < 2)
++ return ERR_PTR(-EINVAL);
+
+ if (config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) {
+ if (config->device_features &
+@@ -261,8 +263,10 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,
+
+ for (i = 0; i < vdpasim->dev_attr.nas; i++) {
+ vhost_iotlb_init(&vdpasim->iommu[i], max_iotlb_entries, 0);
+- vhost_iotlb_add_range(&vdpasim->iommu[i], 0, ULONG_MAX, 0,
+- VHOST_MAP_RW);
++ ret = vhost_iotlb_add_range(&vdpasim->iommu[i], 0, ULONG_MAX,
++ 0, VHOST_MAP_RW);
++ if (ret)
++ goto err_iommu;
+ vdpasim->iommu_pt[i] = true;
+ }
+
+diff --git a/drivers/vdpa/vdpa_user/iova_domain.c b/drivers/vdpa/vdpa_user/iova_domain.c
+index 4dc76c0d0d13d..b6c958224b7ce 100644
+--- a/drivers/vdpa/vdpa_user/iova_domain.c
++++ b/drivers/vdpa/vdpa_user/iova_domain.c
+@@ -12,11 +12,17 @@
+ #include <linux/file.h>
+ #include <linux/anon_inodes.h>
+ #include <linux/highmem.h>
++#include <linux/moduleparam.h>
+ #include <linux/vmalloc.h>
+ #include <linux/vdpa.h>
+
+ #include "iova_domain.h"
+
++static int max_iotlb_entries = 2048;
++module_param(max_iotlb_entries, int, 0444);
++MODULE_PARM_DESC(max_iotlb_entries,
++ "Maximum number of iotlb entries. (default: 2048)");
++
+ static int vduse_iotlb_add_range(struct vduse_iova_domain *domain,
+ u64 start, u64 last,
+ u64 addr, unsigned int perm,
+@@ -622,11 +628,14 @@ vduse_domain_create(unsigned long iova_limit, size_t bounce_size)
+ if (iova_limit <= bounce_size)
+ return NULL;
+
++ if (max_iotlb_entries <= 0)
++ return NULL;
++
+ domain = kzalloc_obj(*domain);
+ if (!domain)
+ return NULL;
+
+- domain->iotlb = vhost_iotlb_alloc(0, 0);
++ domain->iotlb = vhost_iotlb_alloc(max_iotlb_entries, 0);
+ if (!domain->iotlb)
+ goto err_iotlb;
+
+diff --git a/drivers/vhost/iotlb.c b/drivers/vhost/iotlb.c
+index e1414c774c344..a1d4376a5b872 100644
+--- a/drivers/vhost/iotlb.c
++++ b/drivers/vhost/iotlb.c
+@@ -20,6 +20,14 @@ INTERVAL_TREE_DEFINE(struct vhost_iotlb_map,
+ rb, __u64, __subtree_last,
+ START, LAST, static inline, vhost_iotlb_itree);
+
++static void vhost_iotlb_map_unlink(struct vhost_iotlb *iotlb,
++ struct vhost_iotlb_map *map)
++{
++ vhost_iotlb_itree_remove(map, &iotlb->root);
++ list_del(&map->link);
++ iotlb->nmaps--;
++}
++
+ /**
+ * vhost_iotlb_map_free - remove a map node and free it
+ * @iotlb: the IOTLB
+@@ -28,10 +36,8 @@ INTERVAL_TREE_DEFINE(struct vhost_iotlb_map,
+ void vhost_iotlb_map_free(struct vhost_iotlb *iotlb,
+ struct vhost_iotlb_map *map)
+ {
+- vhost_iotlb_itree_remove(map, &iotlb->root);
+- list_del(&map->link);
++ vhost_iotlb_map_unlink(iotlb, map);
+ kfree(map);
+- iotlb->nmaps--;
+ }
+ EXPORT_SYMBOL_GPL(vhost_iotlb_map_free);
+
+@@ -57,14 +63,25 @@ int vhost_iotlb_add_range_ctx(struct vhost_iotlb *iotlb,
+ if (last < start)
+ return -EFAULT;
+
++ if (!iotlb->limit)
++ return -EINVAL;
++
+ /* If the range being mapped is [0, ULONG_MAX], split it into two entries
+ * otherwise its size would overflow u64.
+ */
+ if (start == 0 && last == ULONG_MAX) {
+ u64 mid = last / 2;
+- int err = vhost_iotlb_add_range_ctx(iotlb, start, mid, addr,
+- perm, opaque);
++ int err;
++
++ if (iotlb->limit < 2)
++ return -ENOSPC;
+
++ if (!(iotlb->flags & VHOST_IOTLB_FLAG_RETIRE) &&
++ iotlb->nmaps > iotlb->limit - 2)
++ return -ENOSPC;
++
++ err = vhost_iotlb_add_range_ctx(iotlb, start, mid, addr,
++ perm, opaque);
+ if (err)
+ return err;
+
+@@ -72,17 +89,19 @@ int vhost_iotlb_add_range_ctx(struct vhost_iotlb *iotlb,
+ start = mid + 1;
+ }
+
+- if (iotlb->limit &&
+- iotlb->nmaps == iotlb->limit &&
+- iotlb->flags & VHOST_IOTLB_FLAG_RETIRE) {
+- map = list_first_entry(&iotlb->list, typeof(*map), link);
+- vhost_iotlb_map_free(iotlb, map);
++ if (iotlb->nmaps >= iotlb->limit) {
++ if (iotlb->flags & VHOST_IOTLB_FLAG_RETIRE) {
++ map = list_first_entry(&iotlb->list, typeof(*map), link);
++ vhost_iotlb_map_unlink(iotlb, map);
++ } else {
++ return -ENOSPC;
++ }
++ } else {
++ map = kmalloc_obj(*map, GFP_ATOMIC);
++ if (!map)
++ return -ENOMEM;
+ }
+
+- map = kmalloc_obj(*map, GFP_ATOMIC);
+- if (!map)
+- return -ENOMEM;
+-
+ map->start = start;
+ map->size = last - start + 1;
+ map->last = last;
+diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
+index ac55275fa0d0a..ef642bc9f97e1 100644
+--- a/drivers/vhost/vdpa.c
++++ b/drivers/vhost/vdpa.c
+@@ -34,6 +34,11 @@ enum {
+
+ #define VHOST_VDPA_DEV_MAX (1U << MINORBITS)
+
++static int max_iotlb_entries = 2048;
++module_param(max_iotlb_entries, int, 0444);
++MODULE_PARM_DESC(max_iotlb_entries,
++ "Maximum number of iotlb entries. (default: 2048)");
++
+ #define VHOST_VDPA_IOTLB_BUCKETS 16
+
+ struct vhost_vdpa_as {
+@@ -109,12 +114,14 @@ static struct vhost_vdpa_as *vhost_vdpa_alloc_as(struct vhost_vdpa *v, u32 asid)
+
+ if (asid >= v->vdpa->nas)
+ return NULL;
++ if (max_iotlb_entries <= 0)
++ return NULL;
+
+ as = kmalloc_obj(*as);
+ if (!as)
+ return NULL;
+
+- vhost_iotlb_init(&as->iotlb, 0, 0);
++ vhost_iotlb_init(&as->iotlb, max_iotlb_entries, 0);
+ as->id = asid;
+ hlist_add_head(&as->hash_link, head);
+
+diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
+index db329a6f61458..6ec0616932382 100644
+--- a/drivers/vhost/vhost.c
++++ b/drivers/vhost/vhost.c
+@@ -1137,6 +1137,9 @@ EXPORT_SYMBOL_GPL(vhost_dev_set_owner);
+
+ static struct vhost_iotlb *iotlb_alloc(void)
+ {
++ if (max_iotlb_entries <= 0)
++ return NULL;
++
+ return vhost_iotlb_alloc(max_iotlb_entries,
+ VHOST_IOTLB_FLAG_RETIRE);
+ }
+@@ -1981,6 +1984,8 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
+ return -EOPNOTSUPP;
+ if (mem.nregions > max_mem_regions)
+ return -E2BIG;
++ if (max_iotlb_entries <= 0)
++ return -EINVAL;
+ newmem = kvzalloc_flex(*newmem, regions, mem.nregions);
+ if (!newmem)
+ return -ENOMEM;
+@@ -2275,6 +2280,9 @@ int vhost_init_device_iotlb(struct vhost_dev *d)
+ struct vhost_iotlb *niotlb, *oiotlb;
+ int i;
+
++ if (max_iotlb_entries <= 0)
++ return -EINVAL;
++
+ niotlb = iotlb_alloc();
+ if (!niotlb)
+ return -ENOMEM;
+--
+2.53.0
+
--- /dev/null
+From 24a2cf6f22ea340bd70f5c98847b2c8070fe8cce Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 14:06:13 +0800
+Subject: watchdog: at91sam9_wdt: prevent timer rearm during teardown
+
+From: Hongyan Xu <getshell@seu.edu.cn>
+
+[ Upstream commit 8444d66aa6b6e7fe0a26fa1a00a11cb4d0523783 ]
+
+at91_ping() rearms the watchdog timer from its callback. timer_delete()
+neither waits for a running callback nor prevents it from rearming the
+timer, so probe failure or driver removal can leave the timer accessing the
+devm-allocated at91wdt after it has been freed.
+
+Use timer_shutdown_sync() on both teardown paths. It waits for a running
+callback and rejects any attempt by the callback to rearm the timer.
+
+Fixes: 5161b31dc39a ("watchdog: at91sam9_wdt: better watchdog support")
+Signed-off-by: Hongyan Xu <getshell@seu.edu.cn>
+Link: https://lore.kernel.org/r/20260806060613.1830-1-getshell@seu.edu.cn
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/watchdog/at91sam9_wdt.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
+index aba66b8e9d033..80ba04df54adf 100644
+--- a/drivers/watchdog/at91sam9_wdt.c
++++ b/drivers/watchdog/at91sam9_wdt.c
+@@ -242,7 +242,7 @@ static int at91_wdt_init(struct platform_device *pdev, struct at91wdt *wdt)
+ return 0;
+
+ out_stop_timer:
+- timer_delete(&wdt->timer);
++ timer_shutdown_sync(&wdt->timer);
+ return err;
+ }
+
+@@ -378,7 +378,7 @@ static void at91wdt_remove(struct platform_device *pdev)
+ watchdog_unregister_device(&wdt->wdd);
+
+ pr_warn("I quit now, hardware will probably reboot!\n");
+- timer_delete(&wdt->timer);
++ timer_shutdown_sync(&wdt->timer);
+ }
+
+ #if defined(CONFIG_OF)
+--
+2.53.0
+
--- /dev/null
+From ab60f9ce8de021d0765590fb5369b71434ee7249 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:36:28 +0300
+Subject: watchdog: bd96801_wdt: Fix timeout for enabled WDG
+
+From: Matti Vaittinen <mazziesaccount@gmail.com>
+
+[ Upstream commit 1246aa2b6ccc8944676bd24ff3e37cc56b93b51b ]
+
+When watchdog is enabled at the probe time, the bd96801 driver retrieves
+the timeout configuration from the registers to set-up the heart-beat
+values.
+
+As Sashiko pointed out at
+https://lore.kernel.org/all/20260722085819.495211F000E9@smtp.kernel.org/
+the timeout values are incorrectly computed in driver, resulting wrong
+heartbeat. This leads to devere problems if watchdog was enabled at probe
+time.
+
+According to the data-sheet, the "too fast" ping limit is configured as
+multiple of FASTNG_MIN. Furthermore, the "too slow" ping limit is
+configured as multiples of "too fast" timeout. The FASTNG_MIN is set to
+11, meaning 1.1 mS and "too fast" and "too slow" limits are computed from
+this. Hence, converting the limits to mS should be done by dividing by 10,
+not by dividing by USEC_PER_MSEC.
+
+Fix this by dividing the timeout values with correct scaling factor.
+
+While at it, fix whitespace problem (double empty line).
+
+Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>
+Fixes: 09dad69757b6 ("watchdog: ROHM BD96801 PMIC WDG driver")
+Link: https://lore.kernel.org/r/amxskHmQbi9v-8_l@mva-rohm
+[groeck: Added reference to whitespace change to description]
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/watchdog/bd96801_wdt.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/watchdog/bd96801_wdt.c b/drivers/watchdog/bd96801_wdt.c
+index 12b74fd2bc052..a25b7cf1488b2 100644
+--- a/drivers/watchdog/bd96801_wdt.c
++++ b/drivers/watchdog/bd96801_wdt.c
+@@ -169,7 +169,6 @@ static int bd96801_set_wdt_mode(struct wdtbd96801 *w, unsigned int hw_margin,
+ int fastng, slowng, type, ret, reg, mask;
+ struct device *dev = w->dev;
+
+-
+ if (hw_margin_min * 1000 > FASTNG_MAX_US) {
+ dev_err(dev, "Unsupported fast timeout %u uS [max %u]\n",
+ hw_margin_min * 1000, FASTNG_MAX_US);
+@@ -258,10 +257,10 @@ static int bd96801_set_heartbeat_from_hw(struct wdtbd96801 *w,
+ fast = FASTNG_MIN << sel;
+
+ sel = (val & BD96801_WD_RATIO_MASK) + 1;
+- w->wdt.max_hw_heartbeat_ms = (fast << sel) / USEC_PER_MSEC;
++ w->wdt.max_hw_heartbeat_ms = (fast << sel) / 10;
+
+ if ((conf_reg & BD96801_WD_TYPE_MASK) == BD96801_WD_TYPE_WIN)
+- w->wdt.min_hw_heartbeat_ms = fast / USEC_PER_MSEC;
++ w->wdt.min_hw_heartbeat_ms = fast / 10;
+
+ return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From 16669aa609ee79d30b125ceda917bb883e1bc2b6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 19 Jul 2026 23:11:24 +0800
+Subject: xfs: handle NULL b_addr in xfs_buf_free
+
+From: Yun Zhou <yun.zhou@windriver.com>
+
+[ Upstream commit d852729c5f4f830fbe7413df032e29459b3daf83 ]
+
+When xfs_buf_alloc_backing_mem() fails, xfs_buf_free() is called with
+bp->b_addr still NULL. The code falls through to the folio_put path
+which calls virt_to_folio(NULL), dereferencing an invalid address and
+causing a kernel crash.
+
+ Call Trace:
+ xfs_buf_free+0x25f/0x510
+ xfs_buf_alloc+0xc98/0x19b0
+ xfs_buf_find_insert+0x55/0x14d0
+ xfs_buf_get_map+0x122b/0x17c0
+ xfbtree_init_leaf_block+0x11c/0x4a0
+ xfbtree_init+0x1bb/0x460
+ xrep_rmap_setup_scan+0x100/0x1f0
+ xrep_rmapbt+0x41/0xc0
+
+Fix this by skipping folio_put() when bp->b_addr is NULL.
+
+Fixes: 5076a6040ca1 ("xfs: support in-memory buffer cache targets")
+Reported-by: syzbot+94c22d92f72f5a235b7d@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=94c22d92f72f5a235b7d
+Signed-off-by: Yun Zhou <yun.zhou@windriver.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Carlos Maiolino <cem@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/xfs/xfs_buf.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
+index 0cea458f13536..23bd81fbc2788 100644
+--- a/fs/xfs/xfs_buf.c
++++ b/fs/xfs/xfs_buf.c
+@@ -114,7 +114,7 @@ xfs_buf_free(
+ vfree(bp->b_addr);
+ else if (bp->b_flags & _XBF_KMEM)
+ kfree(bp->b_addr);
+- else
++ else if (bp->b_addr)
+ folio_put(virt_to_folio(bp->b_addr));
+
+ call_rcu(&bp->b_rcu, xfs_buf_free_callback);
+--
+2.53.0
+
--- /dev/null
+From d010e5c4b93c31a79f22e863510710c97a6966b0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 09:19:56 -0700
+Subject: xsk: clear metadata pointer when no timestamp is requested
+
+From: Stanislav Fomichev <sdf.kernel@gmail.com>
+
+[ Upstream commit 9f60a67df8d3c862503bee62bada8e7089cba438 ]
+
+User space can change metadata flags after request processing. Rereading
+them during completion can therefore make the kernel write a timestamp
+that was not requested when the packet was submitted.
+
+Clear the metadata pointer during request processing unless timestamp
+completion is requested. Completion handling can then use the pointer
+itself instead of rereading the flags.
+
+On the mlx5 multi-packet WQE path metadata is evaluated per batch:
+xsk_tx_metadata_request() runs only for the descriptor that starts a
+session, just like the checksum offload that is applied once through the
+shared WQE. Only that descriptor's pointer is reset, so completion
+handling can record a timestamp for the other descriptors of the session
+regardless of their own XDP_TXMD_FLAGS_TIMESTAMP bit. The write stays
+inside the metadata area; the single-WQE, other zero-copy, and generic
+paths reset the pointer per descriptor and are unaffected.
+
+Fixes: ca4419f15abd ("xsk: Add launch time hardware offload support to XDP Tx metadata")
+Cc: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
+Link: https://patch.msgid.link/20260727161959.885642-4-sdf@fomichev.me
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/xdp_sock.h | 14 ++++++++++----
+ net/xdp/xsk.c | 2 ++
+ 2 files changed, 12 insertions(+), 4 deletions(-)
+
+diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h
+index 06c081feff42d..2b2eb9b9d580e 100644
+--- a/include/net/xdp_sock.h
++++ b/include/net/xdp_sock.h
+@@ -141,13 +141,16 @@ INDIRECT_CALLABLE_DECLARE(void xsk_destruct_skb(struct sk_buff *));
+ static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta,
+ struct xsk_tx_metadata_compl *compl)
+ {
++ compl->tx_timestamp = NULL;
++
+ if (!meta)
+ return;
+
+- if (meta->flags & XDP_TXMD_FLAGS_TIMESTAMP)
+- compl->tx_timestamp = &meta->completion.tx_timestamp;
+- else
+- compl->tx_timestamp = NULL;
++ /* we can only arrive here if the completion timestamp has been
++ * requested via XDP_TXMD_FLAGS_TIMESTAMP, see xsk_tx_metadata_request
++ */
++
++ compl->tx_timestamp = &meta->completion.tx_timestamp;
+ }
+
+ /**
+@@ -182,6 +185,9 @@ static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
+ if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM)
+ ops->tmo_request_checksum(meta->request.csum_start,
+ meta->request.csum_offset, priv);
++
++ if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
++ *pmeta = NULL;
+ }
+
+ /**
+diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
+index 855fe92358bac..8d84afb3ad629 100644
+--- a/net/xdp/xsk.c
++++ b/net/xdp/xsk.c
+@@ -997,6 +997,8 @@ static int xsk_skb_metadata(struct sk_buff *skb, void *buffer,
+
+ if (meta->flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
+ skb->skb_mstamp_ns = meta->request.launch_time;
++ if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
++ meta = NULL;
+ xsk_tx_metadata_to_compl(meta, &skb_shinfo(skb)->xsk_meta);
+
+ return 0;
+--
+2.53.0
+
--- /dev/null
+From c480ba05c7db88a29cdad6d2dcbaadacdb4273aa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 09:19:58 -0700
+Subject: xsk: move xsk_tx_metadata_request() to xdp_sock_drv.h
+
+From: Stanislav Fomichev <sdf.kernel@gmail.com>
+
+[ Upstream commit ddd0d6c5bfe2fef7c7cf31f62265f29b7b9eb9ef ]
+
+xsk_tx_metadata_request() must validate metadata with
+xsk_buff_valid_tx_metadata(), which is defined in xdp_sock_drv.h. Move the
+helper there before adding that dependency. All callers already include
+the destination header, so this has no functional effect.
+
+Fixes: ca4419f15abd ("xsk: Add launch time hardware offload support to XDP Tx metadata")
+Cc: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
+Link: https://patch.msgid.link/20260727161959.885642-6-sdf@fomichev.me
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/xdp_sock.h | 43 --------------------------------------
+ include/net/xdp_sock_drv.h | 43 ++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 43 insertions(+), 43 deletions(-)
+
+diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h
+index 2b2eb9b9d580e..6e70b320b399f 100644
+--- a/include/net/xdp_sock.h
++++ b/include/net/xdp_sock.h
+@@ -153,43 +153,6 @@ static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta,
+ compl->tx_timestamp = &meta->completion.tx_timestamp;
+ }
+
+-/**
+- * xsk_tx_metadata_request - Evaluate AF_XDP TX metadata at submission
+- * and call appropriate xsk_tx_metadata_ops operation.
+- * @pmeta: pointer to pointer to AF_XDP metadata area
+- * @ops: pointer to struct xsk_tx_metadata_ops
+- * @priv: pointer to driver-private aread
+- *
+- * This function should be called by the networking device when
+- * it prepares AF_XDP egress packet.
+- */
+-static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
+- const struct xsk_tx_metadata_ops *ops,
+- void *priv)
+-{
+- const struct xsk_tx_metadata *meta = *pmeta;
+-
+- if (!meta)
+- return;
+-
+- if (ops->tmo_request_launch_time)
+- if (meta->flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
+- ops->tmo_request_launch_time(meta->request.launch_time,
+- priv);
+-
+- if (ops->tmo_request_timestamp)
+- if (meta->flags & XDP_TXMD_FLAGS_TIMESTAMP)
+- ops->tmo_request_timestamp(priv);
+-
+- if (ops->tmo_request_checksum)
+- if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM)
+- ops->tmo_request_checksum(meta->request.csum_start,
+- meta->request.csum_offset, priv);
+-
+- if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
+- *pmeta = NULL;
+-}
+-
+ /**
+ * xsk_tx_metadata_complete - Evaluate AF_XDP TX metadata at completion
+ * and call appropriate xsk_tx_metadata_ops operation.
+@@ -239,12 +202,6 @@ static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta,
+ {
+ }
+
+-static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
+- const struct xsk_tx_metadata_ops *ops,
+- void *priv)
+-{
+-}
+-
+ static inline void xsk_tx_metadata_complete(struct xsk_tx_metadata_compl *compl,
+ const struct xsk_tx_metadata_ops *ops,
+ void *priv)
+diff --git a/include/net/xdp_sock_drv.h b/include/net/xdp_sock_drv.h
+index 68a7876013572..f87c4215673ed 100644
+--- a/include/net/xdp_sock_drv.h
++++ b/include/net/xdp_sock_drv.h
+@@ -271,6 +271,43 @@ xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool,
+ return !(*flags & ~XDP_TXMD_FLAGS_VALID);
+ }
+
++/**
++ * xsk_tx_metadata_request - Evaluate AF_XDP TX metadata at submission
++ * and call appropriate xsk_tx_metadata_ops operation.
++ * @pmeta: pointer to pointer to AF_XDP metadata area
++ * @ops: pointer to struct xsk_tx_metadata_ops
++ * @priv: pointer to driver-private aread
++ *
++ * This function should be called by the networking device when
++ * it prepares AF_XDP egress packet.
++ */
++static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
++ const struct xsk_tx_metadata_ops *ops,
++ void *priv)
++{
++ const struct xsk_tx_metadata *meta = *pmeta;
++
++ if (!meta)
++ return;
++
++ if (ops->tmo_request_launch_time)
++ if (meta->flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
++ ops->tmo_request_launch_time(meta->request.launch_time,
++ priv);
++
++ if (ops->tmo_request_timestamp)
++ if (meta->flags & XDP_TXMD_FLAGS_TIMESTAMP)
++ ops->tmo_request_timestamp(priv);
++
++ if (ops->tmo_request_checksum)
++ if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM)
++ ops->tmo_request_checksum(meta->request.csum_start,
++ meta->request.csum_offset, priv);
++
++ if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
++ *pmeta = NULL;
++}
++
+ static inline struct xsk_tx_metadata *
+ __xsk_buff_get_metadata(const struct xsk_buff_pool *pool, void *data)
+ {
+@@ -483,6 +520,12 @@ xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool,
+ return false;
+ }
+
++static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
++ const struct xsk_tx_metadata_ops *ops,
++ void *priv)
++{
++}
++
+ static inline struct xsk_tx_metadata *
+ __xsk_buff_get_metadata(const struct xsk_buff_pool *pool, void *data)
+ {
+--
+2.53.0
+
--- /dev/null
+From 6ff3a7f0577e000c708ced304c826656f6d57191 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 09:19:55 -0700
+Subject: xsk: pass TX metadata pointer by reference
+
+From: Stanislav Fomichev <sdf.kernel@gmail.com>
+
+[ Upstream commit 19366db6dfccac9b0867a151678cd7b89fb8fd99 ]
+
+Completion handling needs to know whether a timestamp was requested when
+the metadata was processed. Let xsk_tx_metadata_request() update the
+caller's metadata pointer so that decision can be carried forward without
+rereading user-controlled flags.
+
+This only changes the interface; behavior remains unchanged.
+
+Fixes: ca4419f15abd ("xsk: Add launch time hardware offload support to XDP Tx metadata")
+Cc: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
+Link: https://patch.msgid.link/20260727161959.885642-3-sdf@fomichev.me
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/igc/igc_main.c | 2 +-
+ drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 +-
+ drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c | 14 +++++++++-----
+ drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h | 4 ++--
+ .../net/ethernet/mellanox/mlx5/core/en/xsk/tx.c | 2 +-
+ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +-
+ include/net/libeth/xsk.h | 2 +-
+ include/net/xdp_sock.h | 8 +++++---
+ 8 files changed, 21 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
+index c0508d2615923..13ddf6cc52eea 100644
+--- a/drivers/net/ethernet/intel/igc/igc_main.c
++++ b/drivers/net/ethernet/intel/igc/igc_main.c
+@@ -3082,7 +3082,7 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring)
+ meta_req.tx_buffer = bi;
+ meta_req.meta = meta;
+ meta_req.used_desc = 0;
+- xsk_tx_metadata_request(meta, &igc_xsk_tx_metadata_ops,
++ xsk_tx_metadata_request(&meta, &igc_xsk_tx_metadata_ops,
+ &meta_req);
+
+ /* xsk_tx_metadata_request() may have updated next_to_use */
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
+index 6867a5aed42c0..822859c360e75 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
+@@ -483,7 +483,7 @@ typedef int (*mlx5e_fp_xmit_xdp_frame_check)(struct mlx5e_xdpsq *);
+ typedef bool (*mlx5e_fp_xmit_xdp_frame)(struct mlx5e_xdpsq *,
+ struct mlx5e_xmit_data *,
+ int,
+- struct xsk_tx_metadata *);
++ struct xsk_tx_metadata **);
+
+ struct mlx5e_xdpsq {
+ /* data path */
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+index d8c7cb8837d74..dac5e9d4c8bdb 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+@@ -452,11 +452,11 @@ INDIRECT_CALLABLE_SCOPE int mlx5e_xmit_xdp_frame_check_mpwqe(struct mlx5e_xdpsq
+
+ INDIRECT_CALLABLE_SCOPE bool
+ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
+- int check_result, struct xsk_tx_metadata *meta);
++ int check_result, struct xsk_tx_metadata **meta);
+
+ INDIRECT_CALLABLE_SCOPE bool
+ mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
+- int check_result, struct xsk_tx_metadata *meta)
++ int check_result, struct xsk_tx_metadata **meta)
+ {
+ struct mlx5e_tx_mpwqe *session = &sq->mpwqe;
+ struct mlx5e_xdpsq_stats *stats = sq->stats;
+@@ -504,7 +504,10 @@ mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptx
+ * and it's safe to complete it at any time.
+ */
+ mlx5e_xdp_mpwqe_session_start(sq);
+- xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, &session->wqe->eth);
++ if (meta)
++ xsk_tx_metadata_request(meta,
++ &mlx5e_xsk_tx_metadata_ops,
++ &session->wqe->eth);
+ }
+
+ mlx5e_xdp_mpwqe_add_dseg(sq, p, stats);
+@@ -535,7 +538,7 @@ INDIRECT_CALLABLE_SCOPE int mlx5e_xmit_xdp_frame_check(struct mlx5e_xdpsq *sq)
+
+ INDIRECT_CALLABLE_SCOPE bool
+ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
+- int check_result, struct xsk_tx_metadata *meta)
++ int check_result, struct xsk_tx_metadata **meta)
+ {
+ struct mlx5e_xmit_data_frags *xdptxdf =
+ container_of(xdptxd, struct mlx5e_xmit_data_frags, xd);
+@@ -649,7 +652,8 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
+
+ sq->pc += num_wqebbs;
+
+- xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, eseg);
++ if (meta)
++ xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, eseg);
+
+ sq->doorbell_cseg = cseg;
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
+index 3c54f8962664f..5b8f4094d5530 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
+@@ -114,11 +114,11 @@ extern const struct xsk_tx_metadata_ops mlx5e_xsk_tx_metadata_ops;
+ INDIRECT_CALLABLE_DECLARE(bool mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq,
+ struct mlx5e_xmit_data *xdptxd,
+ int check_result,
+- struct xsk_tx_metadata *meta));
++ struct xsk_tx_metadata **meta));
+ INDIRECT_CALLABLE_DECLARE(bool mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq,
+ struct mlx5e_xmit_data *xdptxd,
+ int check_result,
+- struct xsk_tx_metadata *meta));
++ struct xsk_tx_metadata **meta));
+ INDIRECT_CALLABLE_DECLARE(int mlx5e_xmit_xdp_frame_check_mpwqe(struct mlx5e_xdpsq *sq));
+ INDIRECT_CALLABLE_DECLARE(int mlx5e_xmit_xdp_frame_check(struct mlx5e_xdpsq *sq));
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
+index 8aeab4b21035c..3d19dad8f8688 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
+@@ -105,7 +105,7 @@ bool mlx5e_xsk_tx(struct mlx5e_xdpsq *sq, unsigned int budget)
+
+ ret = INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe,
+ mlx5e_xmit_xdp_frame, sq, &xdptxd,
+- check_result, meta);
++ check_result, &meta);
+ if (unlikely(!ret)) {
+ if (sq->mpwqe.wqe)
+ mlx5e_xdp_mpwqe_complete(sq);
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index f28367fbcaf81..622f571b30350 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -2748,7 +2748,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
+ meta_req.set_ic = &set_ic;
+ meta_req.tbs = tx_q->tbs;
+ meta_req.edesc = &tx_q->dma_entx[entry];
+- xsk_tx_metadata_request(meta, &stmmac_xsk_tx_metadata_ops,
++ xsk_tx_metadata_request(&meta, &stmmac_xsk_tx_metadata_ops,
+ &meta_req);
+ if (set_ic) {
+ tx_q->tx_count_frames = 0;
+diff --git a/include/net/libeth/xsk.h b/include/net/libeth/xsk.h
+index 82b5d21aae878..e2fa6bf6b1b31 100644
+--- a/include/net/libeth/xsk.h
++++ b/include/net/libeth/xsk.h
+@@ -205,7 +205,7 @@ __libeth_xsk_xmit_fill_buf_md(const struct xdp_desc *xdesc,
+ BUILD_BUG_ON(!__builtin_constant_p(tmo == libeth_xsktmo));
+ tmo = tmo == libeth_xsktmo ? &__libeth_xsktmo : tmo;
+
+- xsk_tx_metadata_request(ctx.meta, tmo, &desc);
++ xsk_tx_metadata_request(&ctx.meta, tmo, &desc);
+
+ return desc;
+ }
+diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h
+index 8b51876efbed1..06c081feff42d 100644
+--- a/include/net/xdp_sock.h
++++ b/include/net/xdp_sock.h
+@@ -153,17 +153,19 @@ static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta,
+ /**
+ * xsk_tx_metadata_request - Evaluate AF_XDP TX metadata at submission
+ * and call appropriate xsk_tx_metadata_ops operation.
+- * @meta: pointer to AF_XDP metadata area
++ * @pmeta: pointer to pointer to AF_XDP metadata area
+ * @ops: pointer to struct xsk_tx_metadata_ops
+ * @priv: pointer to driver-private aread
+ *
+ * This function should be called by the networking device when
+ * it prepares AF_XDP egress packet.
+ */
+-static inline void xsk_tx_metadata_request(const struct xsk_tx_metadata *meta,
++static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
+ const struct xsk_tx_metadata_ops *ops,
+ void *priv)
+ {
++ const struct xsk_tx_metadata *meta = *pmeta;
++
+ if (!meta)
+ return;
+
+@@ -231,7 +233,7 @@ static inline void xsk_tx_metadata_to_compl(struct xsk_tx_metadata *meta,
+ {
+ }
+
+-static inline void xsk_tx_metadata_request(struct xsk_tx_metadata *meta,
++static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
+ const struct xsk_tx_metadata_ops *ops,
+ void *priv)
+ {
+--
+2.53.0
+
--- /dev/null
+From 512627f160ca90829a046eda233e2d84d5294d77 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 09:19:54 -0700
+Subject: xsk: require at least 16 bytes of TX metadata
+
+From: Stanislav Fomichev <sdf.kernel@gmail.com>
+
+[ Upstream commit 1bb30b181d9f0484e141f8411e15ed906d5c6780 ]
+
+AF_XDP accepts a TX metadata length as small as eight bytes, but every
+supported request needs the flags plus at least one eight-byte request
+field. Such short metadata also lets the kernel read beyond the registered
+area.
+
+Require 16 bytes rather than sizeof(struct xsk_tx_metadata) to preserve
+compatibility with applications that do not use launch-time metadata.
+
+Fixes: 341ac980eab9 ("xsk: Support tx_metadata_len")
+Reported-by: AutonomousCodeSecurity@microsoft.com
+Reported-by: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Link: https://lore.kernel.org/netdev/20260720155210.34229-1-blbllhy@gmail.com/
+Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
+Link: https://patch.msgid.link/20260727161959.885642-2-sdf@fomichev.me
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/xdp/xdp_umem.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c
+index 58da2f4f4397a..cd8643360eb3a 100644
+--- a/net/xdp/xdp_umem.c
++++ b/net/xdp/xdp_umem.c
+@@ -210,6 +210,8 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
+ if (mr->flags & XDP_UMEM_TX_METADATA_LEN) {
+ if (mr->tx_metadata_len >= 256 || mr->tx_metadata_len % 8)
+ return -EINVAL;
++ if (mr->tx_metadata_len < 16)
++ return -EINVAL;
+ umem->tx_metadata_len = mr->tx_metadata_len;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 50d4fd2f97145ce38d0d8265e5a2759f070fa284 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 09:19:57 -0700
+Subject: xsk: validate launch-time metadata size
+
+From: Stanislav Fomichev <sdf.kernel@gmail.com>
+
+[ Upstream commit 439ce2dddf3d22129b9113a7881637256a35e936 ]
+
+Launch-time metadata extends beyond the first 16 bytes of struct
+xsk_tx_metadata. Reject the request when the registered metadata area does
+not contain the complete field.
+
+Snapshot the validated flags for the generic transmit path and use that
+snapshot for request and completion processing, avoiding inconsistent
+decisions if user space changes the flags concurrently.
+
+Note that only xsk_skb_metadata is properly using the flags,
+__xsk_buff_get_metadata ignores them. Next commits address that.
+
+Fixes: ca4419f15abd ("xsk: Add launch time hardware offload support to XDP Tx metadata")
+Cc: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
+Link: https://patch.msgid.link/20260727161959.885642-5-sdf@fomichev.me
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/xdp_sock_drv.h | 17 +++++++++++++----
+ net/xdp/xsk.c | 11 ++++++-----
+ 2 files changed, 19 insertions(+), 9 deletions(-)
+
+diff --git a/include/net/xdp_sock_drv.h b/include/net/xdp_sock_drv.h
+index 46797645a0c24..68a7876013572 100644
+--- a/include/net/xdp_sock_drv.h
++++ b/include/net/xdp_sock_drv.h
+@@ -260,21 +260,28 @@ xsk_buff_raw_get_ctx(const struct xsk_buff_pool *pool, u64 addr)
+ 0)
+
+ static inline bool
+-xsk_buff_valid_tx_metadata(const struct xsk_tx_metadata *meta)
++xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool,
++ const struct xsk_tx_metadata *meta, u64 *flags)
+ {
+- return !(meta->flags & ~XDP_TXMD_FLAGS_VALID);
++ *flags = READ_ONCE(meta->flags);
++ if (*flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
++ if (pool->tx_metadata_len <
++ offsetofend(struct xsk_tx_metadata, request.launch_time))
++ return false;
++ return !(*flags & ~XDP_TXMD_FLAGS_VALID);
+ }
+
+ static inline struct xsk_tx_metadata *
+ __xsk_buff_get_metadata(const struct xsk_buff_pool *pool, void *data)
+ {
+ struct xsk_tx_metadata *meta;
++ u64 flags;
+
+ if (!pool->tx_metadata_len)
+ return NULL;
+
+ meta = data - pool->tx_metadata_len;
+- if (unlikely(!xsk_buff_valid_tx_metadata(meta)))
++ if (unlikely(!xsk_buff_valid_tx_metadata(pool, meta, &flags)))
+ return NULL; /* no way to signal the error to the user */
+
+ return meta;
+@@ -469,7 +476,9 @@ xsk_buff_raw_get_ctx(const struct xsk_buff_pool *pool, u64 addr)
+ return (struct xdp_desc_ctx){ };
+ }
+
+-static inline bool xsk_buff_valid_tx_metadata(struct xsk_tx_metadata *meta)
++static inline bool
++xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool,
++ const struct xsk_tx_metadata *meta, u64 *flags)
+ {
+ return false;
+ }
+diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
+index 8d84afb3ad629..95a9ff3d0bdb4 100644
+--- a/net/xdp/xsk.c
++++ b/net/xdp/xsk.c
+@@ -966,15 +966,16 @@ static int xsk_skb_metadata(struct sk_buff *skb, void *buffer,
+ {
+ struct xsk_tx_metadata *meta = NULL;
+ u16 csum_start, csum_offset;
++ u64 flags;
+
+ if (unlikely(pool->tx_metadata_len == 0))
+ return -EINVAL;
+
+ meta = buffer - pool->tx_metadata_len;
+- if (unlikely(!xsk_buff_valid_tx_metadata(meta)))
++ if (unlikely(!xsk_buff_valid_tx_metadata(pool, meta, &flags)))
+ return -EINVAL;
+
+- if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM) {
++ if (flags & XDP_TXMD_FLAGS_CHECKSUM) {
+ csum_start = READ_ONCE(meta->request.csum_start);
+ csum_offset = READ_ONCE(meta->request.csum_offset);
+
+@@ -995,9 +996,9 @@ static int xsk_skb_metadata(struct sk_buff *skb, void *buffer,
+ }
+ }
+
+- if (meta->flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
+- skb->skb_mstamp_ns = meta->request.launch_time;
+- if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
++ if (flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
++ skb->skb_mstamp_ns = READ_ONCE(meta->request.launch_time);
++ if (!(flags & XDP_TXMD_FLAGS_TIMESTAMP))
+ meta = NULL;
+ xsk_tx_metadata_to_compl(meta, &skb_shinfo(skb)->xsk_meta);
+
+--
+2.53.0
+
--- /dev/null
+From 82be16f022eddf0677e1e3d31ffe5d518f26145c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Jul 2026 09:19:59 -0700
+Subject: xsk: validate metadata when processing requests
+
+From: Stanislav Fomichev <sdf.kernel@gmail.com>
+
+[ Upstream commit 849b1664dbda1cf6c63e0fd4f9dec23782b8c851 ]
+
+The zero-copy path validates TX metadata while obtaining the descriptor
+context, then reads it again later when preparing the hardware request.
+User space can change the metadata between those operations and bypass the
+original validation.
+
+Validate the metadata in xsk_tx_metadata_request() and use the resulting
+flags snapshot for every feature check. Read request fields once so all
+zero-copy drivers process only values observed after successful
+validation.
+
+Fixes: ca4419f15abd ("xsk: Add launch time hardware offload support to XDP Tx metadata")
+Cc: Cen Zhang (Microsoft) <blbllhy@gmail.com>
+Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
+Link: https://patch.msgid.link/20260727161959.885642-7-sdf@fomichev.me
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/igc/igc_main.c | 2 +-
+ .../net/ethernet/mellanox/mlx5/core/en/xdp.c | 5 +-
+ .../net/ethernet/stmicro/stmmac/stmmac_main.c | 4 +-
+ include/net/libeth/xsk.h | 2 +-
+ include/net/xdp_sock_drv.h | 51 ++++++++++---------
+ net/xdp/xsk_buff_pool.c | 6 +--
+ 6 files changed, 37 insertions(+), 33 deletions(-)
+
+diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
+index 13ddf6cc52eea..6525ecb666e4c 100644
+--- a/drivers/net/ethernet/intel/igc/igc_main.c
++++ b/drivers/net/ethernet/intel/igc/igc_main.c
+@@ -3082,7 +3082,7 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring)
+ meta_req.tx_buffer = bi;
+ meta_req.meta = meta;
+ meta_req.used_desc = 0;
+- xsk_tx_metadata_request(&meta, &igc_xsk_tx_metadata_ops,
++ xsk_tx_metadata_request(pool, &meta, &igc_xsk_tx_metadata_ops,
+ &meta_req);
+
+ /* xsk_tx_metadata_request() may have updated next_to_use */
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+index dac5e9d4c8bdb..77ea51bfbaae5 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+@@ -505,7 +505,7 @@ mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptx
+ */
+ mlx5e_xdp_mpwqe_session_start(sq);
+ if (meta)
+- xsk_tx_metadata_request(meta,
++ xsk_tx_metadata_request(sq->xsk_pool, meta,
+ &mlx5e_xsk_tx_metadata_ops,
+ &session->wqe->eth);
+ }
+@@ -653,7 +653,8 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
+ sq->pc += num_wqebbs;
+
+ if (meta)
+- xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, eseg);
++ xsk_tx_metadata_request(sq->xsk_pool, meta,
++ &mlx5e_xsk_tx_metadata_ops, eseg);
+
+ sq->doorbell_cseg = cseg;
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index 622f571b30350..b7e3f652501e4 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -2748,8 +2748,8 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
+ meta_req.set_ic = &set_ic;
+ meta_req.tbs = tx_q->tbs;
+ meta_req.edesc = &tx_q->dma_entx[entry];
+- xsk_tx_metadata_request(&meta, &stmmac_xsk_tx_metadata_ops,
+- &meta_req);
++ xsk_tx_metadata_request(pool, &meta,
++ &stmmac_xsk_tx_metadata_ops, &meta_req);
+ if (set_ic) {
+ tx_q->tx_count_frames = 0;
+ stmmac_set_tx_ic(priv, tx_desc);
+diff --git a/include/net/libeth/xsk.h b/include/net/libeth/xsk.h
+index e2fa6bf6b1b31..5dcc0d7f65b76 100644
+--- a/include/net/libeth/xsk.h
++++ b/include/net/libeth/xsk.h
+@@ -205,7 +205,7 @@ __libeth_xsk_xmit_fill_buf_md(const struct xdp_desc *xdesc,
+ BUILD_BUG_ON(!__builtin_constant_p(tmo == libeth_xsktmo));
+ tmo = tmo == libeth_xsktmo ? &__libeth_xsktmo : tmo;
+
+- xsk_tx_metadata_request(&ctx.meta, tmo, &desc);
++ xsk_tx_metadata_request(sq->pool, &ctx.meta, tmo, &desc);
+
+ return desc;
+ }
+diff --git a/include/net/xdp_sock_drv.h b/include/net/xdp_sock_drv.h
+index f87c4215673ed..b344789f5df83 100644
+--- a/include/net/xdp_sock_drv.h
++++ b/include/net/xdp_sock_drv.h
+@@ -245,7 +245,7 @@ static inline void *xsk_buff_raw_get_data(struct xsk_buff_pool *pool, u64 addr)
+ * details.
+ *
+ * Return: new &xdp_desc_ctx struct containing desc's DMA address and metadata
+- * pointer, if it is present and valid (initialized to %NULL otherwise).
++ * pointer, if it is present (initialized to %NULL otherwise).
+ */
+ static inline struct xdp_desc_ctx
+ xsk_buff_raw_get_ctx(const struct xsk_buff_pool *pool, u64 addr)
+@@ -274,54 +274,56 @@ xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool,
+ /**
+ * xsk_tx_metadata_request - Evaluate AF_XDP TX metadata at submission
+ * and call appropriate xsk_tx_metadata_ops operation.
++ * @pool: pointer to AF_XDP buffer pool, used to validate the metadata
+ * @pmeta: pointer to pointer to AF_XDP metadata area
+ * @ops: pointer to struct xsk_tx_metadata_ops
+- * @priv: pointer to driver-private aread
++ * @priv: pointer to driver-private area
+ *
+ * This function should be called by the networking device when
+ * it prepares AF_XDP egress packet.
+ */
+-static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
+- const struct xsk_tx_metadata_ops *ops,
+- void *priv)
++static inline void
++xsk_tx_metadata_request(const struct xsk_buff_pool *pool,
++ struct xsk_tx_metadata **pmeta,
++ const struct xsk_tx_metadata_ops *ops, void *priv)
+ {
+ const struct xsk_tx_metadata *meta = *pmeta;
++ u64 flags;
+
+ if (!meta)
+ return;
+
++ if (unlikely(!xsk_buff_valid_tx_metadata(pool, meta, &flags))) {
++ *pmeta = NULL;
++ return; /* no way to signal the error to the user */
++ }
++
+ if (ops->tmo_request_launch_time)
+- if (meta->flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
+- ops->tmo_request_launch_time(meta->request.launch_time,
+- priv);
++ if (flags & XDP_TXMD_FLAGS_LAUNCH_TIME)
++ ops->tmo_request_launch_time(
++ READ_ONCE(meta->request.launch_time), priv);
+
+ if (ops->tmo_request_timestamp)
+- if (meta->flags & XDP_TXMD_FLAGS_TIMESTAMP)
++ if (flags & XDP_TXMD_FLAGS_TIMESTAMP)
+ ops->tmo_request_timestamp(priv);
+
+ if (ops->tmo_request_checksum)
+- if (meta->flags & XDP_TXMD_FLAGS_CHECKSUM)
+- ops->tmo_request_checksum(meta->request.csum_start,
+- meta->request.csum_offset, priv);
++ if (flags & XDP_TXMD_FLAGS_CHECKSUM)
++ ops->tmo_request_checksum(
++ READ_ONCE(meta->request.csum_start),
++ READ_ONCE(meta->request.csum_offset), priv);
+
+- if (!(meta->flags & XDP_TXMD_FLAGS_TIMESTAMP))
++ if (!(flags & XDP_TXMD_FLAGS_TIMESTAMP))
+ *pmeta = NULL;
+ }
+
+ static inline struct xsk_tx_metadata *
+ __xsk_buff_get_metadata(const struct xsk_buff_pool *pool, void *data)
+ {
+- struct xsk_tx_metadata *meta;
+- u64 flags;
+-
+ if (!pool->tx_metadata_len)
+ return NULL;
+
+- meta = data - pool->tx_metadata_len;
+- if (unlikely(!xsk_buff_valid_tx_metadata(pool, meta, &flags)))
+- return NULL; /* no way to signal the error to the user */
+-
+- return meta;
++ return data - pool->tx_metadata_len;
+ }
+
+ static inline struct xsk_tx_metadata *
+@@ -520,9 +522,10 @@ xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool,
+ return false;
+ }
+
+-static inline void xsk_tx_metadata_request(struct xsk_tx_metadata **pmeta,
+- const struct xsk_tx_metadata_ops *ops,
+- void *priv)
++static inline void
++xsk_tx_metadata_request(const struct xsk_buff_pool *pool,
++ struct xsk_tx_metadata **pmeta,
++ const struct xsk_tx_metadata_ops *ops, void *priv)
+ {
+ }
+
+diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c
+index 4538223f44082..f720422607771 100644
+--- a/net/xdp/xsk_buff_pool.c
++++ b/net/xdp/xsk_buff_pool.c
+@@ -765,11 +765,11 @@ EXPORT_SYMBOL(xp_raw_get_dma);
+ * @addr: desc address (from userspace)
+ *
+ * Helper for getting desc's DMA address and metadata pointer, if present.
+- * Saves one call on hotpath, double calculation of the actual address,
+- * and inline checks for metadata presence and sanity.
++ * Saves one call on hotpath and double calculation of the actual address.
++ * Metadata is validated later by xsk_tx_metadata_request().
+ *
+ * Return: new &xdp_desc_ctx struct containing desc's DMA address and metadata
+- * pointer, if it is present and valid (initialized to %NULL otherwise).
++ * pointer, if it is present (initialized to %NULL otherwise).
+ */
+ struct xdp_desc_ctx xp_raw_get_ctx(const struct xsk_buff_pool *pool, u64 addr)
+ {
+--
+2.53.0
+