From: Sasha Levin Date: Wed, 12 Aug 2026 00:05:09 +0000 (-0400) Subject: Fixes for all trees X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=acae408eb308f75e0babd1f9b548797d1b41e51a;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch b/queue-5.10/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch new file mode 100644 index 0000000000..690fda1345 --- /dev/null +++ b/queue-5.10/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch @@ -0,0 +1,50 @@ +From f2c2e2ba9edf6d4600348efceb6363facd712015 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 24 May 2026 23:38:46 -0400 +Subject: ARM: npcm: Fix OF node refcount leaks in SMP setup + +From: Yuho Choi + +[ 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 +Reviewed-by: Avi Fishman +Signed-off-by: Andrew Jeffery +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch b/queue-5.10/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch new file mode 100644 index 0000000000..4b75ebda24 --- /dev/null +++ b/queue-5.10/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch @@ -0,0 +1,52 @@ +From 6ee612a25f6ddeec742501e8f930df76e3e253b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Aug 2026 14:06:28 +0800 +Subject: ata: pata_sl82c105: fix bridge revision use-after-free + +From: Hongyan Xu + +[ 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 +Reviewed-by: Niklas Cassel +Signed-off-by: Damien Le Moal +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch b/queue-5.10/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch new file mode 100644 index 0000000000..d3e72dd436 --- /dev/null +++ b/queue-5.10/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch @@ -0,0 +1,57 @@ +From ba032c60e7c1eacad914ed8a0ce52f88d837b5eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Kalesh AP +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-5-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch b/queue-5.10/bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch new file mode 100644 index 0000000000..0f4aa95100 --- /dev/null +++ b/queue-5.10/bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch @@ -0,0 +1,66 @@ +From 88c9b3c4172d7cd56b19ea4e44a8a52f68cbc9e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Somnath Kotur +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20251126215648.1885936-6-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: c3faf548a00f ("bnxt_en: Disable EOP for TPA on all chips to prevent data corruption") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch b/queue-5.10/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch new file mode 100644 index 0000000000..b65c3f370e --- /dev/null +++ b/queue-5.10/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch @@ -0,0 +1,80 @@ +From f68d64c59c42a7e3a21a22e43ad690fb810b9a9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) + +[ 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) +Reviewed-by: Nikolay Aleksandrov +Acked-by: Jay Vosburgh +Link: https://patch.msgid.link/20260725233930.2957317-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/bpf-preserve-pointer-state-for-commuted-arithmetic.patch b/queue-5.10/bpf-preserve-pointer-state-for-commuted-arithmetic.patch new file mode 100644 index 0000000000..4770466fc1 --- /dev/null +++ b/queue-5.10/bpf-preserve-pointer-state-for-commuted-arithmetic.patch @@ -0,0 +1,74 @@ +From 196e3e2e72f167c87b14333fceb50c298ebd8915 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 15:18:28 +0000 +Subject: bpf: Preserve pointer state for commuted arithmetic + +From: Yiyang Chen + +[ 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 +Tested-by: Daniel Wade +Acked-by: Shung-Hsi Yu +Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-2-8ee297e2346b@mails.tsinghua.edu.cn +Signed-off-by: Eduard Zingerman +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/counter-microchip-tcb-capture-fix-dt-channel-validat.patch b/queue-5.10/counter-microchip-tcb-capture-fix-dt-channel-validat.patch new file mode 100644 index 0000000000..009bda71f0 --- /dev/null +++ b/queue-5.10/counter-microchip-tcb-capture-fix-dt-channel-validat.patch @@ -0,0 +1,70 @@ +From a1796ce78148ae9006bf059b322b037d68459f34 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Jul 2026 04:29:10 +0000 +Subject: counter: microchip-tcb-capture: Fix DT channel validation + +From: Babanpreet Singh + +[ 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 +Reviewed-by: Joshua Crofts +Link: https://lore.kernel.org/r/20260714042910.7-1-bbnpreetsingh@gmail.com +Signed-off-by: William Breathitt Gray +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch b/queue-5.10/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch new file mode 100644 index 0000000000..df2f4bef54 --- /dev/null +++ b/queue-5.10/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch @@ -0,0 +1,42 @@ +From 576a9fce7878612b4d771f82550c91a6be59a844 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-marvell-prestera-try-to-load-previous-fw-version.patch b/queue-5.10/net-marvell-prestera-try-to-load-previous-fw-version.patch new file mode 100644 index 0000000000..cbac9d8889 --- /dev/null +++ b/queue-5.10/net-marvell-prestera-try-to-load-previous-fw-version.patch @@ -0,0 +1,172 @@ +From f33a4801df1b07ac632666c632d3ea3dc182e5bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 31 May 2021 17:32:46 +0300 +Subject: net: marvell: prestera: try to load previous fw version + +From: Vadym Kochan + +[ 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 +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +Stable-dep-of: 8ae344eb540a ("net: prestera: validate firmware header length") +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-5.10/net-mlx5-fw_tracer-return-null-on-create-error.patch b/queue-5.10/net-mlx5-fw_tracer-return-null-on-create-error.patch new file mode 100644 index 0000000000..a4237c5d77 --- /dev/null +++ b/queue-5.10/net-mlx5-fw_tracer-return-null-on-create-error.patch @@ -0,0 +1,134 @@ +From 786bfed5342fe96166ede365ed85c472312a89bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 11:04:02 +0300 +Subject: net/mlx5: fw_tracer, return NULL on create error + +From: Michael Guralnik + +[ 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 +Reviewed-by: Shay Drori +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260729080402.2427184-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-5.10/net-mlx5-remove-second-fw-tracer-check.patch b/queue-5.10/net-mlx5-remove-second-fw-tracer-check.patch new file mode 100644 index 0000000000..0163097880 --- /dev/null +++ b/queue-5.10/net-mlx5-remove-second-fw-tracer-check.patch @@ -0,0 +1,58 @@ +From 46ec1c475f4f261e39c26c7f9b2bdf540545b29b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 14:42:45 +0200 +Subject: net/mlx5: Remove second FW tracer check + +From: Leon Romanovsky + +[ Upstream commit 7e615b9978021a034124166d4fa3dc4fc0ea4b16 ] + +The FW tracer check is called twice, so delete one of them. + +Signed-off-by: Leon Romanovsky +Signed-off-by: Saeed Mahameed +Stable-dep-of: af39eb111ce6 ("net/mlx5: fw_tracer, return NULL on create error") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch b/queue-5.10/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch new file mode 100644 index 0000000000..8951432bd3 --- /dev/null +++ b/queue-5.10/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch @@ -0,0 +1,60 @@ +From 8dcbc65e8f0df3058b7802377b217d59e8d7f226 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Henry Martin +Link: https://patch.msgid.link/20260803043618.3210301-1-bsdhenrymartin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-openvswitch-check-ethernet-header-length-in-key_.patch b/queue-5.10/net-openvswitch-check-ethernet-header-length-in-key_.patch new file mode 100644 index 0000000000..12a1390b1e --- /dev/null +++ b/queue-5.10/net-openvswitch-check-ethernet-header-length-in-key_.patch @@ -0,0 +1,78 @@ +From 87c478701db0006f128b41f14e8d306dba897f5f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 18:20:06 -0400 +Subject: net/openvswitch: check Ethernet header length in key_extract() + +From: Cen Zhang (Microsoft) + +[ 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 +Signed-off-by: Cen Zhang (Microsoft) +Reviewed-by: Ilya Maximets +Link: https://patch.msgid.link/20260730222006.118652-1-blbllhy@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-openvswitch-fix-kernel-doc-warnings-in-flow.c.patch b/queue-5.10/net-openvswitch-fix-kernel-doc-warnings-in-flow.c.patch new file mode 100644 index 0000000000..e36314e499 --- /dev/null +++ b/queue-5.10/net-openvswitch-fix-kernel-doc-warnings-in-flow.c.patch @@ -0,0 +1,84 @@ +From a579366685aa265dc9bca61e60a3d95f3f99b16f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Aug 2021 12:08:34 -0700 +Subject: net: openvswitch: fix kernel-doc warnings in flow.c + +From: Randy Dunlap + +[ 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 +Cc: Pravin B Shelar +Cc: dev@openvswitch.org +Link: https://lore.kernel.org/r/20210808190834.23362-1-rdunlap@infradead.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: cf6f8b29befb ("net/openvswitch: check Ethernet header length in key_extract()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-openvswitch-fix-kerneldoc-warnings.patch b/queue-5.10/net-openvswitch-fix-kerneldoc-warnings.patch new file mode 100644 index 0000000000..2d2ca7c88d --- /dev/null +++ b/queue-5.10/net-openvswitch-fix-kerneldoc-warnings.patch @@ -0,0 +1,60 @@ +From 10a238ee1e60b47a9419599f44c91a49203b8732 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Oct 2020 01:48:49 +0100 +Subject: net: openvswitch: Fix kerneldoc warnings + +From: Andrew Lunn + +[ 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 +Link: https://lore.kernel.org/r/20201028004849.930094-1-andrew@lunn.ch +Signed-off-by: Jakub Kicinski +Stable-dep-of: cf6f8b29befb ("net/openvswitch: check Ethernet header length in key_extract()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-prestera-validate-firmware-header-length.patch b/queue-5.10/net-prestera-validate-firmware-header-length.patch new file mode 100644 index 0000000000..21cb105fce --- /dev/null +++ b/queue-5.10/net-prestera-validate-firmware-header-length.patch @@ -0,0 +1,42 @@ +From 4e0de47af795cb2bfa63bc29418a4b3ebdfe48e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 22:19:06 +0800 +Subject: net: prestera: validate firmware header length + +From: Pengpeng Hou + +[ 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 +Acked-by: Elad Nachman +Link: https://patch.msgid.link/20260731141500.1-prestera-v2-pengpeng@iscas.ac.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-qrtr-ns-raise-lookup-limit-to-128.patch b/queue-5.10/net-qrtr-ns-raise-lookup-limit-to-128.patch new file mode 100644 index 0000000000..92fb81d774 --- /dev/null +++ b/queue-5.10/net-qrtr-ns-raise-lookup-limit-to-128.patch @@ -0,0 +1,51 @@ +From fd7041340a21e9e91e976363eb3cd754a5b75d88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/20260804201919.1148015-1-priv.luk@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-remove-warn_on_once-from-sk_mc_loop.patch b/queue-5.10/net-remove-warn_on_once-from-sk_mc_loop.patch new file mode 100644 index 0000000000..c24ce0270e --- /dev/null +++ b/queue-5.10/net-remove-warn_on_once-from-sk_mc_loop.patch @@ -0,0 +1,45 @@ +From 497379f2999453c7f76dc44c6c135b83acede912 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 15:20:48 +0000 +Subject: net: remove WARN_ON_ONCE() from sk_mc_loop() + +From: Eric Dumazet + +[ 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 +Link: https://patch.msgid.link/20260804152048.2134341-1-edumazet@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch b/queue-5.10/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch new file mode 100644 index 0000000000..150e6c4000 --- /dev/null +++ b/queue-5.10/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch @@ -0,0 +1,142 @@ +From 8a29fa5617bd7cce0e7f88f186e2680b5c4d8ac9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Suggested-by: Paolo Abeni +Tested-by: Victor Nogueira +Tested-by: Santosh Kalluri +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260729094411.46257-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch b/queue-5.10/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch new file mode 100644 index 0000000000..2ad994416a --- /dev/null +++ b/queue-5.10/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch @@ -0,0 +1,50 @@ +From a1a97b7643c9e9fe3d5a13a31ea26d3d49139bf3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reported-by: Ren Wei +Signed-off-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260729191417.45665-1-toke@toke.dk +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch b/queue-5.10/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch new file mode 100644 index 0000000000..703aea7c74 --- /dev/null +++ b/queue-5.10/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch @@ -0,0 +1,57 @@ +From ff1e83d829b7ef011656a38c67d0c57d8446a81b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Hidayath Khan +Reviewed-by: Sidraya Jayagond +Reviewed-by: Dust Li +Link: https://patch.msgid.link/20260729130153.970800-1-mjambigi@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch b/queue-5.10/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch new file mode 100644 index 0000000000..8445fb4922 --- /dev/null +++ b/queue-5.10/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch @@ -0,0 +1,50 @@ +From 976a83e5b6dc1430f134bd5ea8cab7049c145db8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Jun 2026 14:31:00 -0400 +Subject: NFS: Pin the 'struct nfs_server' during a FREE_STATEID call + +From: Anna Schumaker + +[ 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 +Fixes: 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call") +Tested-by: Dan Aloni +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/nfs4-take-a-reference-on-the-nfs_client-when-running.patch b/queue-5.10/nfs4-take-a-reference-on-the-nfs_client-when-running.patch new file mode 100644 index 0000000000..23b87351b6 --- /dev/null +++ b/queue-5.10/nfs4-take-a-reference-on-the-nfs_client-when-running.patch @@ -0,0 +1,54 @@ +From 88b5017ecd162dfb0f270fbbf049a07a999ddc58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Trond Myklebust +Stable-dep-of: cf616096a0f3 ("NFS: Pin the 'struct nfs_server' during a FREE_STATEID call") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/sctp-clear-control-chunk-transport-if-it-is-being-re.patch b/queue-5.10/sctp-clear-control-chunk-transport-if-it-is-being-re.patch new file mode 100644 index 0000000000..b9caab00cd --- /dev/null +++ b/queue-5.10/sctp-clear-control-chunk-transport-if-it-is-being-re.patch @@ -0,0 +1,54 @@ +From 744a71847e17ae65e6191745b76f9f17cce84c54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 11:18:40 -0400 +Subject: sctp: clear control chunk transport if it is being removed + +From: Xin Long + +[ 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 +Signed-off-by: Xin Long +Link: https://patch.msgid.link/7e1168cb722132152a29d47e5eafaeac4a3bf6f3.1785943120.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/sctp-extract-sctp_v4_err_handle-function-from-sctp_v.patch b/queue-5.10/sctp-extract-sctp_v4_err_handle-function-from-sctp_v.patch new file mode 100644 index 0000000000..4992deaebd --- /dev/null +++ b/queue-5.10/sctp-extract-sctp_v4_err_handle-function-from-sctp_v.patch @@ -0,0 +1,170 @@ +From 418595e4e2b0326da7edc442ab1cc4135fa70ae2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 22 Jun 2021 14:04:59 -0400 +Subject: sctp: extract sctp_v4_err_handle function from sctp_v4_err + +From: Xin Long + +[ 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 +Acked-by: Marcelo Ricardo Leitner +Signed-off-by: David S. Miller +Stable-dep-of: af0e5cdd031f ("tls: don't abort the connection on signal-interrupted sends") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/sctp-extract-sctp_v6_err_handle-function-from-sctp_v.patch b/queue-5.10/sctp-extract-sctp_v6_err_handle-function-from-sctp_v.patch new file mode 100644 index 0000000000..e6362511c2 --- /dev/null +++ b/queue-5.10/sctp-extract-sctp_v6_err_handle-function-from-sctp_v.patch @@ -0,0 +1,137 @@ +From bbff555a08dd2d2eb658a50fba549b2e89f7dd30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 22 Jun 2021 14:04:58 -0400 +Subject: sctp: extract sctp_v6_err_handle function from sctp_v6_err + +From: Xin Long + +[ 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 +Acked-by: Marcelo Ricardo Leitner +Signed-off-by: David S. Miller +Stable-dep-of: af0e5cdd031f ("tls: don't abort the connection on signal-interrupted sends") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch b/queue-5.10/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch new file mode 100644 index 0000000000..82f3e35579 --- /dev/null +++ b/queue-5.10/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch @@ -0,0 +1,57 @@ +From 333351595af73b55419d0fd5f7beb7fe46b84806 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 10:55:14 +0800 +Subject: sctp: fix addip_serial increment on ASCONF_ACK allocation failure + +From: Qing Luo + +[ 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 +Acked-by: Xin Long +Link: https://patch.msgid.link/20260804025514.241767-1-l1138897701@163.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/sctp-remove-the-unessessary-hold-for-idev-in-sctp_v6.patch b/queue-5.10/sctp-remove-the-unessessary-hold-for-idev-in-sctp_v6.patch new file mode 100644 index 0000000000..9104e05970 --- /dev/null +++ b/queue-5.10/sctp-remove-the-unessessary-hold-for-idev-in-sctp_v6.patch @@ -0,0 +1,68 @@ +From 7073a3ae46a9923c73357b7f4f9733a63506e2b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 22 Jun 2021 14:04:57 -0400 +Subject: sctp: remove the unessessary hold for idev in sctp_v6_err + +From: Xin Long + +[ 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 +Acked-by: Marcelo Ricardo Leitner +Signed-off-by: David S. Miller +Stable-dep-of: af0e5cdd031f ("tls: don't abort the connection on signal-interrupted sends") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/series b/queue-5.10/series index d6a8f4a242..28a5dd62e1 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -308,3 +308,33 @@ firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch 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 diff --git a/queue-5.10/tls-don-t-abort-the-connection-on-signal-interrupted.patch b/queue-5.10/tls-don-t-abort-the-connection-on-signal-interrupted.patch new file mode 100644 index 0000000000..2ed1029760 --- /dev/null +++ b/queue-5.10/tls-don-t-abort-the-connection-on-signal-interrupted.patch @@ -0,0 +1,45 @@ +From b91f0b707ce79341e882f8736962c4384a2c9299 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 08:22:48 +0200 +Subject: tls: don't abort the connection on signal-interrupted sends + +From: Maximilian Immanuel Brandtner + +[ 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 +Link: https://patch.msgid.link/20260805063109.1772314-1-maxbr@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch b/queue-5.10/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch new file mode 100644 index 0000000000..61879b175b --- /dev/null +++ b/queue-5.10/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch @@ -0,0 +1,53 @@ +From 3dbbf3bf859911909e0f84ed018a252ba1f5dcd8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 17:35:54 +0800 +Subject: udp: fix potential use-after-free in tunnel segmentation + +From: Xuanqiang Luo + +[ 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 +Reviewed-by: Antoine Tenart +Link: https://patch.msgid.link/20260730093554.68127-1-xuanqiang.luo@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch b/queue-5.15/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch new file mode 100644 index 0000000000..6ffef0889d --- /dev/null +++ b/queue-5.15/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch @@ -0,0 +1,50 @@ +From e8e17ba087e05b378b25acbac1d331ee7984a353 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 24 May 2026 23:38:46 -0400 +Subject: ARM: npcm: Fix OF node refcount leaks in SMP setup + +From: Yuho Choi + +[ 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 +Reviewed-by: Avi Fishman +Signed-off-by: Andrew Jeffery +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch b/queue-5.15/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch new file mode 100644 index 0000000000..c6edf8da74 --- /dev/null +++ b/queue-5.15/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch @@ -0,0 +1,52 @@ +From 1bb1751e7cec2b178425b82d2934839af616eb5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Aug 2026 14:06:28 +0800 +Subject: ata: pata_sl82c105: fix bridge revision use-after-free + +From: Hongyan Xu + +[ 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 +Reviewed-by: Niklas Cassel +Signed-off-by: Damien Le Moal +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch b/queue-5.15/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch new file mode 100644 index 0000000000..91ff252df7 --- /dev/null +++ b/queue-5.15/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch @@ -0,0 +1,57 @@ +From 3f4f9b4edc9ae3bcfc8c9e6bcf6d8a615fa51b0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Kalesh AP +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-5-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch b/queue-5.15/bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch new file mode 100644 index 0000000000..4c495eb5a9 --- /dev/null +++ b/queue-5.15/bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch @@ -0,0 +1,66 @@ +From 59a20e85238e63ef6ae4c80bfb27766e04cbbbce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Somnath Kotur +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20251126215648.1885936-6-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: c3faf548a00f ("bnxt_en: Disable EOP for TPA on all chips to prevent data corruption") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/bnxt_en-fix-ptp-pps-setting-bug.patch b/queue-5.15/bnxt_en-fix-ptp-pps-setting-bug.patch new file mode 100644 index 0000000000..205192a8d2 --- /dev/null +++ b/queue-5.15/bnxt_en-fix-ptp-pps-setting-bug.patch @@ -0,0 +1,54 @@ +From 8b67a7d89f5d61d906942b11b2cc0049dda9febf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:09:37 -0700 +Subject: bnxt_en: Fix PTP PPS setting bug + +From: Keegan Freyhof + +[ 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 +Signed-off-by: Keegan Freyhof +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-6-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch b/queue-5.15/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch new file mode 100644 index 0000000000..95a426ac5d --- /dev/null +++ b/queue-5.15/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch @@ -0,0 +1,80 @@ +From f5d8cb48043bb756b1478664478d295606e17304 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) + +[ 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) +Reviewed-by: Nikolay Aleksandrov +Acked-by: Jay Vosburgh +Link: https://patch.msgid.link/20260725233930.2957317-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/bpf-preserve-pointer-state-for-commuted-arithmetic.patch b/queue-5.15/bpf-preserve-pointer-state-for-commuted-arithmetic.patch new file mode 100644 index 0000000000..0c6f1b4b35 --- /dev/null +++ b/queue-5.15/bpf-preserve-pointer-state-for-commuted-arithmetic.patch @@ -0,0 +1,74 @@ +From e43831d5507e770c5edbbbd08e7175b131e97d2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 15:18:28 +0000 +Subject: bpf: Preserve pointer state for commuted arithmetic + +From: Yiyang Chen + +[ 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 +Tested-by: Daniel Wade +Acked-by: Shung-Hsi Yu +Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-2-8ee297e2346b@mails.tsinghua.edu.cn +Signed-off-by: Eduard Zingerman +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/counter-microchip-tcb-capture-fix-dt-channel-validat.patch b/queue-5.15/counter-microchip-tcb-capture-fix-dt-channel-validat.patch new file mode 100644 index 0000000000..bae632add2 --- /dev/null +++ b/queue-5.15/counter-microchip-tcb-capture-fix-dt-channel-validat.patch @@ -0,0 +1,70 @@ +From 6f384d3ac7ab59dfab784a69cf0dba87e8614991 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Jul 2026 04:29:10 +0000 +Subject: counter: microchip-tcb-capture: Fix DT channel validation + +From: Babanpreet Singh + +[ 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 +Reviewed-by: Joshua Crofts +Link: https://lore.kernel.org/r/20260714042910.7-1-bbnpreetsingh@gmail.com +Signed-off-by: William Breathitt Gray +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch b/queue-5.15/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch new file mode 100644 index 0000000000..150fa41557 --- /dev/null +++ b/queue-5.15/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch @@ -0,0 +1,50 @@ +From 6dbc5a8c76ec733dd687ef7ab1f3f30f4c8cb74c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://lore.kernel.org/r/anLj9gPWRoRDbQBV@monster.localdomain +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch b/queue-5.15/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch new file mode 100644 index 0000000000..25b600c4ef --- /dev/null +++ b/queue-5.15/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch @@ -0,0 +1,42 @@ +From 02e4ccb81a608412e02140dbee90086260ccc479 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-mlx5-fw_tracer-return-null-on-create-error.patch b/queue-5.15/net-mlx5-fw_tracer-return-null-on-create-error.patch new file mode 100644 index 0000000000..705b9458c8 --- /dev/null +++ b/queue-5.15/net-mlx5-fw_tracer-return-null-on-create-error.patch @@ -0,0 +1,134 @@ +From e29ce88890705a04d4e2c39c8cd5d777de06eaac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 11:04:02 +0300 +Subject: net/mlx5: fw_tracer, return NULL on create error + +From: Michael Guralnik + +[ 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 +Reviewed-by: Shay Drori +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260729080402.2427184-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-5.15/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch b/queue-5.15/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch new file mode 100644 index 0000000000..73774e55d8 --- /dev/null +++ b/queue-5.15/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch @@ -0,0 +1,60 @@ +From b6c5958ee95b3aacc4c1ea89f0f249b80dcf62a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Henry Martin +Link: https://patch.msgid.link/20260803043618.3210301-1-bsdhenrymartin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-openvswitch-check-ethernet-header-length-in-key_.patch b/queue-5.15/net-openvswitch-check-ethernet-header-length-in-key_.patch new file mode 100644 index 0000000000..3005519dbf --- /dev/null +++ b/queue-5.15/net-openvswitch-check-ethernet-header-length-in-key_.patch @@ -0,0 +1,78 @@ +From 96a01c91d8bd20af07e77bf4e3e9f484d536abad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 18:20:06 -0400 +Subject: net/openvswitch: check Ethernet header length in key_extract() + +From: Cen Zhang (Microsoft) + +[ 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 +Signed-off-by: Cen Zhang (Microsoft) +Reviewed-by: Ilya Maximets +Link: https://patch.msgid.link/20260730222006.118652-1-blbllhy@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-prestera-validate-firmware-header-length.patch b/queue-5.15/net-prestera-validate-firmware-header-length.patch new file mode 100644 index 0000000000..64223fd4b0 --- /dev/null +++ b/queue-5.15/net-prestera-validate-firmware-header-length.patch @@ -0,0 +1,42 @@ +From 41117a0598512f81b4103636d1225424080fbcc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 22:19:06 +0800 +Subject: net: prestera: validate firmware header length + +From: Pengpeng Hou + +[ 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 +Acked-by: Elad Nachman +Link: https://patch.msgid.link/20260731141500.1-prestera-v2-pengpeng@iscas.ac.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-qrtr-ns-raise-lookup-limit-to-128.patch b/queue-5.15/net-qrtr-ns-raise-lookup-limit-to-128.patch new file mode 100644 index 0000000000..092749109e --- /dev/null +++ b/queue-5.15/net-qrtr-ns-raise-lookup-limit-to-128.patch @@ -0,0 +1,51 @@ +From 0b7d37122ec5a9f43341094c7550673688862ec0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/20260804201919.1148015-1-priv.luk@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-remove-warn_on_once-from-sk_mc_loop.patch b/queue-5.15/net-remove-warn_on_once-from-sk_mc_loop.patch new file mode 100644 index 0000000000..a3771955a4 --- /dev/null +++ b/queue-5.15/net-remove-warn_on_once-from-sk_mc_loop.patch @@ -0,0 +1,45 @@ +From 58217cd42dc8597ff068d1ae68bc24dee1e76377 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 15:20:48 +0000 +Subject: net: remove WARN_ON_ONCE() from sk_mc_loop() + +From: Eric Dumazet + +[ 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 +Link: https://patch.msgid.link/20260804152048.2134341-1-edumazet@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch b/queue-5.15/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch new file mode 100644 index 0000000000..51fc9a27a0 --- /dev/null +++ b/queue-5.15/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch @@ -0,0 +1,142 @@ +From 1c4e37d23627494abd0097d9037e1715d43caa52 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Suggested-by: Paolo Abeni +Tested-by: Victor Nogueira +Tested-by: Santosh Kalluri +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260729094411.46257-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch b/queue-5.15/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch new file mode 100644 index 0000000000..f7be954a7e --- /dev/null +++ b/queue-5.15/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch @@ -0,0 +1,50 @@ +From 2354b1e970b4b66ae5de41e93edb093b20d1543b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reported-by: Ren Wei +Signed-off-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260729191417.45665-1-toke@toke.dk +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch b/queue-5.15/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch new file mode 100644 index 0000000000..e9ab554cf0 --- /dev/null +++ b/queue-5.15/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch @@ -0,0 +1,57 @@ +From f5243ee866d4472a989260b7cff7375b95cb22f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Hidayath Khan +Reviewed-by: Sidraya Jayagond +Reviewed-by: Dust Li +Link: https://patch.msgid.link/20260729130153.970800-1-mjambigi@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch b/queue-5.15/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch new file mode 100644 index 0000000000..95130bcddc --- /dev/null +++ b/queue-5.15/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch @@ -0,0 +1,71 @@ +From 5eaa1334fa42635a0bc8c0a73045deb321611132 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Sidraya Jayagond +Reviewed-by: Breno Leitao +Reviewed-by: Dust Li +Link: https://patch.msgid.link/20260803070701.126339-1-sidraya@linux.ibm.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch b/queue-5.15/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch new file mode 100644 index 0000000000..e92e720bdf --- /dev/null +++ b/queue-5.15/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch @@ -0,0 +1,117 @@ +From b7fe909c6522bf50a0895cddaeb069ddc7c4f03a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 14:38:50 +0000 +Subject: net: thunderbolt: Tear down DMA paths before stopping the rings + +From: Fan XinRan + +[ 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 +Acked-by: Mika Westerberg +Link: https://patch.msgid.link/20260803-b4-tbnet-teardown-v2-1-27de6a13ca2d@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch b/queue-5.15/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch new file mode 100644 index 0000000000..81e6fd1ede --- /dev/null +++ b/queue-5.15/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch @@ -0,0 +1,50 @@ +From efa14b8975e450782e29525d1bad8c72ba856f55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Jun 2026 14:31:00 -0400 +Subject: NFS: Pin the 'struct nfs_server' during a FREE_STATEID call + +From: Anna Schumaker + +[ 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 +Fixes: 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call") +Tested-by: Dan Aloni +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/nfs4-take-a-reference-on-the-nfs_client-when-running.patch b/queue-5.15/nfs4-take-a-reference-on-the-nfs_client-when-running.patch new file mode 100644 index 0000000000..957c18e6c0 --- /dev/null +++ b/queue-5.15/nfs4-take-a-reference-on-the-nfs_client-when-running.patch @@ -0,0 +1,54 @@ +From 6ed2d86d2ae1c17adc72b46f8086d495bb3a1ce1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Trond Myklebust +Stable-dep-of: cf616096a0f3 ("NFS: Pin the 'struct nfs_server' during a FREE_STATEID call") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/sctp-clear-control-chunk-transport-if-it-is-being-re.patch b/queue-5.15/sctp-clear-control-chunk-transport-if-it-is-being-re.patch new file mode 100644 index 0000000000..a684ec2cf6 --- /dev/null +++ b/queue-5.15/sctp-clear-control-chunk-transport-if-it-is-being-re.patch @@ -0,0 +1,54 @@ +From 47087644103d60ae0a5837e7cf6f9d5bf2509258 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 11:18:40 -0400 +Subject: sctp: clear control chunk transport if it is being removed + +From: Xin Long + +[ 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 +Signed-off-by: Xin Long +Link: https://patch.msgid.link/7e1168cb722132152a29d47e5eafaeac4a3bf6f3.1785943120.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch b/queue-5.15/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch new file mode 100644 index 0000000000..1b5f67753a --- /dev/null +++ b/queue-5.15/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch @@ -0,0 +1,57 @@ +From b08f944054f473e96eccc65cc045e6740c3ba46f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 10:55:14 +0800 +Subject: sctp: fix addip_serial increment on ASCONF_ACK allocation failure + +From: Qing Luo + +[ 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 +Acked-by: Xin Long +Link: https://patch.msgid.link/20260804025514.241767-1-l1138897701@163.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/selftests-ftrace-add-test-case-for-grp-only-input.patch b/queue-5.15/selftests-ftrace-add-test-case-for-grp-only-input.patch new file mode 100644 index 0000000000..0fe17c900d --- /dev/null +++ b/queue-5.15/selftests-ftrace-add-test-case-for-grp-only-input.patch @@ -0,0 +1,68 @@ +From 1027ded263b9c11d589922e595e132057622ae0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jun 2022 10:19:08 +0800 +Subject: selftests/ftrace: Add test case for GRP/ only input + +From: Linyu Yuan + +[ 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) +Reviewed-by: Tom Zanussi +Signed-off-by: Linyu Yuan +Signed-off-by: Steven Rostedt (Google) +Stable-dep-of: 6e3abef2a27e ("selftests/ftrace: refactor eprobes test to fix argument checks") +Signed-off-by: Sasha Levin +--- + .../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[:[/]] . []":README ++# requires: dynamic_events events/syscalls/sys_enter_openat ". []":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\[:\[/]\[]]" 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\[:\[/]\[]]" 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 + diff --git a/queue-5.15/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch b/queue-5.15/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch new file mode 100644 index 0000000000..cd122f221b --- /dev/null +++ b/queue-5.15/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch @@ -0,0 +1,88 @@ +From 334fc362a7659923df346db5a29a0e21b2f13187 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 21:46:35 +0200 +Subject: selftests/ftrace: refactor eprobes test to fix argument checks + +From: Martin Kaiser + +[ 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 " 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 +Closes: https://lore.kernel.org/oe-lkp/202607151010.b68428e1-lkp@intel.com +Signed-off-by: Martin Kaiser +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + .../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 ". []":README ++# requires: dynamic_events events/syscalls/sys_enter_chdir ". []":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 + diff --git a/queue-5.15/series b/queue-5.15/series index 3651ff94c5..2659fdafc4 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -365,3 +365,34 @@ firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch 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 diff --git a/queue-5.15/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch b/queue-5.15/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch new file mode 100644 index 0000000000..12cf866e9b --- /dev/null +++ b/queue-5.15/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch @@ -0,0 +1,72 @@ +From b2b3a9f29049b94855df062394e9d7824c836153 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 14:17:38 +0800 +Subject: tcp: fix TFO max_qlen accounting across reuseport migration + +From: Jiayuan Chen + +[ 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 +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260803061739.134737-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/tls-don-t-abort-the-connection-on-signal-interrupted.patch b/queue-5.15/tls-don-t-abort-the-connection-on-signal-interrupted.patch new file mode 100644 index 0000000000..beeba3131b --- /dev/null +++ b/queue-5.15/tls-don-t-abort-the-connection-on-signal-interrupted.patch @@ -0,0 +1,45 @@ +From 5cec22ef9eab45369103a8c7a53aff760bd5abcf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 08:22:48 +0200 +Subject: tls: don't abort the connection on signal-interrupted sends + +From: Maximilian Immanuel Brandtner + +[ 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 +Link: https://patch.msgid.link/20260805063109.1772314-1-maxbr@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch b/queue-5.15/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch new file mode 100644 index 0000000000..81efcb80cf --- /dev/null +++ b/queue-5.15/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch @@ -0,0 +1,53 @@ +From 92a63ad90e252b5b91da77094278b14b572d2f0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 17:35:54 +0800 +Subject: udp: fix potential use-after-free in tunnel segmentation + +From: Xuanqiang Luo + +[ 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 +Reviewed-by: Antoine Tenart +Link: https://patch.msgid.link/20260730093554.68127-1-xuanqiang.luo@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch b/queue-5.15/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch new file mode 100644 index 0000000000..8bbfc434eb --- /dev/null +++ b/queue-5.15/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch @@ -0,0 +1,56 @@ +From c4b54f0ea4f35790510c2a46681f91cabe973517 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 15:02:02 -0700 +Subject: vhost/vdpa: reject overflowing PA map page counts on 32-bit + +From: Yousef Alhouseen + +[ 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 +Signed-off-by: Yousef Alhouseen +Signed-off-by: Michael S. Tsirkin +Message-ID: +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch b/queue-6.1/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch new file mode 100644 index 0000000000..7a38c7ef63 --- /dev/null +++ b/queue-6.1/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch @@ -0,0 +1,50 @@ +From f0f491009a617fcc8cb2b81635d364c2e49d9a42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 24 May 2026 23:38:46 -0400 +Subject: ARM: npcm: Fix OF node refcount leaks in SMP setup + +From: Yuho Choi + +[ 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 +Reviewed-by: Avi Fishman +Signed-off-by: Andrew Jeffery +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch b/queue-6.1/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch new file mode 100644 index 0000000000..262f0bbb53 --- /dev/null +++ b/queue-6.1/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch @@ -0,0 +1,52 @@ +From 44f559ea20bcc124135c8986e70c04eaf5fb6b81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Aug 2026 14:06:28 +0800 +Subject: ata: pata_sl82c105: fix bridge revision use-after-free + +From: Hongyan Xu + +[ 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 +Reviewed-by: Niklas Cassel +Signed-off-by: Damien Le Moal +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch b/queue-6.1/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch new file mode 100644 index 0000000000..241ff8c3c9 --- /dev/null +++ b/queue-6.1/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch @@ -0,0 +1,57 @@ +From 02148f889fe85a08046145deeacff8581e5e3181 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Kalesh AP +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-5-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch b/queue-6.1/bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch new file mode 100644 index 0000000000..4e3857590e --- /dev/null +++ b/queue-6.1/bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch @@ -0,0 +1,66 @@ +From 8c84e7921b8869be09f190d24338d604cdecfef9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Somnath Kotur +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20251126215648.1885936-6-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: c3faf548a00f ("bnxt_en: Disable EOP for TPA on all chips to prevent data corruption") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bnxt_en-fix-ptp-pps-setting-bug.patch b/queue-6.1/bnxt_en-fix-ptp-pps-setting-bug.patch new file mode 100644 index 0000000000..da6e83e094 --- /dev/null +++ b/queue-6.1/bnxt_en-fix-ptp-pps-setting-bug.patch @@ -0,0 +1,54 @@ +From 45f6016d5b4edd8cb0df04a4ea3fdfc112b25860 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:09:37 -0700 +Subject: bnxt_en: Fix PTP PPS setting bug + +From: Keegan Freyhof + +[ 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 +Signed-off-by: Keegan Freyhof +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-6-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch b/queue-6.1/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch new file mode 100644 index 0000000000..e970446e62 --- /dev/null +++ b/queue-6.1/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch @@ -0,0 +1,80 @@ +From 67849cf8c52004548aaddff6ea7fa23cc2cb7889 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) + +[ 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) +Reviewed-by: Nikolay Aleksandrov +Acked-by: Jay Vosburgh +Link: https://patch.msgid.link/20260725233930.2957317-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bpf-preserve-pointer-state-for-commuted-arithmetic.patch b/queue-6.1/bpf-preserve-pointer-state-for-commuted-arithmetic.patch new file mode 100644 index 0000000000..836fed3358 --- /dev/null +++ b/queue-6.1/bpf-preserve-pointer-state-for-commuted-arithmetic.patch @@ -0,0 +1,74 @@ +From 5906b8f9ad2b939d61abb276d5cb1eea1683ac50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 15:18:28 +0000 +Subject: bpf: Preserve pointer state for commuted arithmetic + +From: Yiyang Chen + +[ 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 +Tested-by: Daniel Wade +Acked-by: Shung-Hsi Yu +Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-2-8ee297e2346b@mails.tsinghua.edu.cn +Signed-off-by: Eduard Zingerman +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bpf-tcp-avoid-socket-skips-and-repeats-during-iterat.patch b/queue-6.1/bpf-tcp-avoid-socket-skips-and-repeats-during-iterat.patch new file mode 100644 index 0000000000..565a9537c4 --- /dev/null +++ b/queue-6.1/bpf-tcp-avoid-socket-skips-and-repeats-during-iterat.patch @@ -0,0 +1,240 @@ +From b816ecb15c6f02a446cc5cdecf61032140721a8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Jul 2025 11:09:09 -0700 +Subject: bpf: tcp: Avoid socket skips and repeats during iteration + +From: Jordan Rife + +[ 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 +Signed-off-by: Martin KaFai Lau +Acked-by: Stanislav Fomichev +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + + #include + #include +@@ -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 + diff --git a/queue-6.1/bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch b/queue-6.1/bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch new file mode 100644 index 0000000000..d8b60e9cdc --- /dev/null +++ b/queue-6.1/bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch @@ -0,0 +1,170 @@ +From f00b8e518ee706106c203941d9b6a2c5c7aefe7d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) + +[ 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) +Reviewed-by: Kuniyuki Iwashima +Link: https://lore.kernel.org/bpf/20260730-bpf-iter-tcp-refcnt-v3-1-754b9c8a6717@linux.dev +Signed-off-by: Kumar Kartikeya Dwivedi +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bpf-tcp-get-rid-of-st_bucket_done.patch b/queue-6.1/bpf-tcp-get-rid-of-st_bucket_done.patch new file mode 100644 index 0000000000..35ab7cb5a9 --- /dev/null +++ b/queue-6.1/bpf-tcp-get-rid-of-st_bucket_done.patch @@ -0,0 +1,82 @@ +From 152c092fa6ea7f2459644d30af6d57ac6f6e301f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Jul 2025 11:09:07 -0700 +Subject: bpf: tcp: Get rid of st_bucket_done + +From: Jordan Rife + +[ 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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Acked-by: Stanislav Fomichev +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bpf-tcp-make-mem-flags-configurable-through-bpf_iter.patch b/queue-6.1/bpf-tcp-make-mem-flags-configurable-through-bpf_iter.patch new file mode 100644 index 0000000000..edafe42026 --- /dev/null +++ b/queue-6.1/bpf-tcp-make-mem-flags-configurable-through-bpf_iter.patch @@ -0,0 +1,64 @@ +From e55f46d6888c865fcfb440c07388157d9cc9f00e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Acked-by: Stanislav Fomichev +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bpf-tcp-make-sure-iter-batch-always-contains-a-full-.patch b/queue-6.1/bpf-tcp-make-sure-iter-batch-always-contains-a-full-.patch new file mode 100644 index 0000000000..4876a097fc --- /dev/null +++ b/queue-6.1/bpf-tcp-make-sure-iter-batch-always-contains-a-full-.patch @@ -0,0 +1,257 @@ +From ee0fda8353af9fbcbb1f0d0daf786b19806e088d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Acked-by: Stanislav Fomichev +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bpf-tcp-use-bpf_tcp_iter_batch_item-for-bpf_tcp_iter.patch b/queue-6.1/bpf-tcp-use-bpf_tcp_iter_batch_item-for-bpf_tcp_iter.patch new file mode 100644 index 0000000000..c17d4ea263 --- /dev/null +++ b/queue-6.1/bpf-tcp-use-bpf_tcp_iter_batch_item-for-bpf_tcp_iter.patch @@ -0,0 +1,124 @@ +From 0dc2b0f88c1c5f6e8a4bfa9e598623b7a967f7ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Acked-by: Stanislav Fomichev +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch b/queue-6.1/btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch new file mode 100644 index 0000000000..c4db97842f --- /dev/null +++ b/queue-6.1/btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch @@ -0,0 +1,96 @@ +From d777275b37f35293379d4d7c61d934a191182100 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 14:53:52 +0300 +Subject: btrfs: fix memory leak in btrfs_do_encoded_write() + +From: Dmitry Antipov + +[ 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 +Signed-off-by: Dmitry Antipov +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/counter-microchip-tcb-capture-fix-dt-channel-validat.patch b/queue-6.1/counter-microchip-tcb-capture-fix-dt-channel-validat.patch new file mode 100644 index 0000000000..a02d6268ba --- /dev/null +++ b/queue-6.1/counter-microchip-tcb-capture-fix-dt-channel-validat.patch @@ -0,0 +1,70 @@ +From da9005daa8f982289b2d8eb873fb5b6228f75e84 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Jul 2026 04:29:10 +0000 +Subject: counter: microchip-tcb-capture: Fix DT channel validation + +From: Babanpreet Singh + +[ 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 +Reviewed-by: Joshua Crofts +Link: https://lore.kernel.org/r/20260714042910.7-1-bbnpreetsingh@gmail.com +Signed-off-by: William Breathitt Gray +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/hwmon-ads7828-fix-external-vref-regulator-handling.patch b/queue-6.1/hwmon-ads7828-fix-external-vref-regulator-handling.patch new file mode 100644 index 0000000000..0e976caad2 --- /dev/null +++ b/queue-6.1/hwmon-ads7828-fix-external-vref-regulator-handling.patch @@ -0,0 +1,71 @@ +From c36c6d9465eae41f81a36337fd0c1f692196764b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 14:16:45 +0800 +Subject: hwmon: (ads7828) Fix external VREF regulator handling + +From: Qingshuang Fu + +[ 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 +Link: https://lore.kernel.org/r/20260805061645.1331652-1-fffsqian@163.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch b/queue-6.1/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch new file mode 100644 index 0000000000..0e50645f81 --- /dev/null +++ b/queue-6.1/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch @@ -0,0 +1,50 @@ +From 703d024563555b8974dc7f1be605e2ac58525ca9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://lore.kernel.org/r/anLj9gPWRoRDbQBV@monster.localdomain +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/hwmon-lm25066-use-i2c_get_match_data.patch b/queue-6.1/hwmon-lm25066-use-i2c_get_match_data.patch new file mode 100644 index 0000000000..f8de8f3ac6 --- /dev/null +++ b/queue-6.1/hwmon-lm25066-use-i2c_get_match_data.patch @@ -0,0 +1,71 @@ +From fcd629107158eced94836794797bebd4e1ca0315 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Nov 2023 14:57:02 -0600 +Subject: hwmon: (lm25066) Use i2c_get_match_data() + +From: Rob Herring + +[ 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 +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 +Stable-dep-of: 0dabe8a56f77 ("hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations") +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include ++#include + #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 + diff --git a/queue-6.1/hwmon-nzxt-smart2-check-return-value-of-init_device-.patch b/queue-6.1/hwmon-nzxt-smart2-check-return-value-of-init_device-.patch new file mode 100644 index 0000000000..87bf5499da --- /dev/null +++ b/queue-6.1/hwmon-nzxt-smart2-check-return-value-of-init_device-.patch @@ -0,0 +1,57 @@ +From 95713dd6d48c71f7a786121f5dfd07d24e6d3050 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 15:48:42 +0800 +Subject: hwmon: (nzxt-smart2) Check return value of init_device() in probe + +From: Qingshuang Fu + +[ 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 +Link: https://lore.kernel.org/r/20260804074842.505923-1-fffsqian@163.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch b/queue-6.1/hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch new file mode 100644 index 0000000000..84c9972931 --- /dev/null +++ b/queue-6.1/hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch @@ -0,0 +1,71 @@ +From 634f82a6d696eaad404d18bdf639a86bc982ced2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 14:12:31 -0700 +Subject: hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations + +From: Guenter Roeck + +[ 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 +Fixes: 94ee5fcc240fe ("hwmon: (pmbus/lm25066) Support configurable sense resistor values") +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + #include + #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 + diff --git a/queue-6.1/ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch b/queue-6.1/ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch new file mode 100644 index 0000000000..33110c7f90 --- /dev/null +++ b/queue-6.1/ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch @@ -0,0 +1,259 @@ +From 94832c514362b1ae3be0df45a070205b6cd78671 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 21:35:05 +0300 +Subject: ipvs: avoid out-of-bounds write in ip_vs_nat_icmp + +From: Julian Anastasov + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/ipvs-return-the-csum-validation-for-forward-hook.patch b/queue-6.1/ipvs-return-the-csum-validation-for-forward-hook.patch new file mode 100644 index 0000000000..971685c742 --- /dev/null +++ b/queue-6.1/ipvs-return-the-csum-validation-for-forward-hook.patch @@ -0,0 +1,100 @@ +From fac0aed665efce9a6b432cb8ee6e70d167de36ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 21:35:06 +0300 +Subject: ipvs: return the csum validation for forward hook + +From: Julian Anastasov + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 /* for union nf_inet_addr */ + #include + #include /* for struct ipv6hdr */ +-#include + #include +-#include + #if IS_ENABLED(CONFIG_NF_CONNTRACK) + #include + #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 + diff --git a/queue-6.1/net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch b/queue-6.1/net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch new file mode 100644 index 0000000000..59c28027aa --- /dev/null +++ b/queue-6.1/net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch @@ -0,0 +1,81 @@ +From 6163896209d085306952514d3a56cca333ea87af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 13:15:08 +0000 +Subject: net/atm: fix slab-out-of-bounds read in vcc_setsockopt() + +From: Eric Dumazet + +[ 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 +Link: https://patch.msgid.link/20260805131508.3227331-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch b/queue-6.1/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch new file mode 100644 index 0000000000..e9b06f6abe --- /dev/null +++ b/queue-6.1/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch @@ -0,0 +1,42 @@ +From 682dc10f686b8843f13984b0392ce72d4f2ecc37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-mlx5-fw_tracer-return-null-on-create-error.patch b/queue-6.1/net-mlx5-fw_tracer-return-null-on-create-error.patch new file mode 100644 index 0000000000..bed369f9cf --- /dev/null +++ b/queue-6.1/net-mlx5-fw_tracer-return-null-on-create-error.patch @@ -0,0 +1,134 @@ +From 516393aa3719ededb21082b34e837e6d3e9b76dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 11:04:02 +0300 +Subject: net/mlx5: fw_tracer, return NULL on create error + +From: Michael Guralnik + +[ 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 +Reviewed-by: Shay Drori +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260729080402.2427184-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.1/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch b/queue-6.1/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch new file mode 100644 index 0000000000..3c0c7da237 --- /dev/null +++ b/queue-6.1/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch @@ -0,0 +1,60 @@ +From b66009d5c7991c62e5c0131d9b6b8bc6e84c363c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Henry Martin +Link: https://patch.msgid.link/20260803043618.3210301-1-bsdhenrymartin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-openvswitch-check-ethernet-header-length-in-key_.patch b/queue-6.1/net-openvswitch-check-ethernet-header-length-in-key_.patch new file mode 100644 index 0000000000..1b6564d72c --- /dev/null +++ b/queue-6.1/net-openvswitch-check-ethernet-header-length-in-key_.patch @@ -0,0 +1,78 @@ +From f661bc67ecd3eeafe360f154de70faed4599e9cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 18:20:06 -0400 +Subject: net/openvswitch: check Ethernet header length in key_extract() + +From: Cen Zhang (Microsoft) + +[ 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 +Signed-off-by: Cen Zhang (Microsoft) +Reviewed-by: Ilya Maximets +Link: https://patch.msgid.link/20260730222006.118652-1-blbllhy@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-prestera-validate-firmware-header-length.patch b/queue-6.1/net-prestera-validate-firmware-header-length.patch new file mode 100644 index 0000000000..c8f78cc32a --- /dev/null +++ b/queue-6.1/net-prestera-validate-firmware-header-length.patch @@ -0,0 +1,42 @@ +From d29ad82db7a015f25b85c8b616e0ba9db3a007c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 22:19:06 +0800 +Subject: net: prestera: validate firmware header length + +From: Pengpeng Hou + +[ 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 +Acked-by: Elad Nachman +Link: https://patch.msgid.link/20260731141500.1-prestera-v2-pengpeng@iscas.ac.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-qrtr-ns-raise-lookup-limit-to-128.patch b/queue-6.1/net-qrtr-ns-raise-lookup-limit-to-128.patch new file mode 100644 index 0000000000..699d37c23b --- /dev/null +++ b/queue-6.1/net-qrtr-ns-raise-lookup-limit-to-128.patch @@ -0,0 +1,51 @@ +From 5a6fafeeaba1a57577cc0e4cc8dfeebbd936dbd5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/20260804201919.1148015-1-priv.luk@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-remove-warn_on_once-from-sk_mc_loop.patch b/queue-6.1/net-remove-warn_on_once-from-sk_mc_loop.patch new file mode 100644 index 0000000000..4984e1c00f --- /dev/null +++ b/queue-6.1/net-remove-warn_on_once-from-sk_mc_loop.patch @@ -0,0 +1,45 @@ +From 5892613efbacc66ce4c0cfc3c20061a250920a47 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 15:20:48 +0000 +Subject: net: remove WARN_ON_ONCE() from sk_mc_loop() + +From: Eric Dumazet + +[ 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 +Link: https://patch.msgid.link/20260804152048.2134341-1-edumazet@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch b/queue-6.1/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch new file mode 100644 index 0000000000..108fe09a6c --- /dev/null +++ b/queue-6.1/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch @@ -0,0 +1,142 @@ +From be9bc8cf78e82986787cd3d488a0e3ff2962688b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Suggested-by: Paolo Abeni +Tested-by: Victor Nogueira +Tested-by: Santosh Kalluri +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260729094411.46257-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch b/queue-6.1/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch new file mode 100644 index 0000000000..995aec88b4 --- /dev/null +++ b/queue-6.1/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch @@ -0,0 +1,50 @@ +From 7968377f51e1c15ef1ef879abb10af5107cffa19 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reported-by: Ren Wei +Signed-off-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260729191417.45665-1-toke@toke.dk +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch b/queue-6.1/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch new file mode 100644 index 0000000000..f6f67eec65 --- /dev/null +++ b/queue-6.1/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch @@ -0,0 +1,57 @@ +From 56572156102cd788fca51de6d955e3a01526b988 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Hidayath Khan +Reviewed-by: Sidraya Jayagond +Reviewed-by: Dust Li +Link: https://patch.msgid.link/20260729130153.970800-1-mjambigi@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch b/queue-6.1/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch new file mode 100644 index 0000000000..6de9666aad --- /dev/null +++ b/queue-6.1/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch @@ -0,0 +1,71 @@ +From 2684d3671434507c511aa4a421f18f8aafdb657b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Sidraya Jayagond +Reviewed-by: Breno Leitao +Reviewed-by: Dust Li +Link: https://patch.msgid.link/20260803070701.126339-1-sidraya@linux.ibm.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch b/queue-6.1/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch new file mode 100644 index 0000000000..ade0d3d806 --- /dev/null +++ b/queue-6.1/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch @@ -0,0 +1,117 @@ +From fc31608ca42507671304f132c77a0d941e95556d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 14:38:50 +0000 +Subject: net: thunderbolt: Tear down DMA paths before stopping the rings + +From: Fan XinRan + +[ 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 +Acked-by: Mika Westerberg +Link: https://patch.msgid.link/20260803-b4-tbnet-teardown-v2-1-27de6a13ca2d@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/netfilter-ipset-switch-ext_size-to-atomic64_t.patch b/queue-6.1/netfilter-ipset-switch-ext_size-to-atomic64_t.patch new file mode 100644 index 0000000000..25cded1db0 --- /dev/null +++ b/queue-6.1/netfilter-ipset-switch-ext_size-to-atomic64_t.patch @@ -0,0 +1,134 @@ +From b2476013c836f66a0a3414150d4c9c6c6723724d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 20:38:50 +0200 +Subject: netfilter: ipset: switch ext_size to atomic64_t + +From: Jozsef Kadlecsik + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/ipset/ip_set.h | 2 +- + net/netfilter/ipset/ip_set_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 + diff --git a/queue-6.1/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch b/queue-6.1/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch new file mode 100644 index 0000000000..b19e0e0952 --- /dev/null +++ b/queue-6.1/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch @@ -0,0 +1,50 @@ +From a637182c814db7b4aa588fbed7ce9f7139d49aa9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Jun 2026 14:31:00 -0400 +Subject: NFS: Pin the 'struct nfs_server' during a FREE_STATEID call + +From: Anna Schumaker + +[ 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 +Fixes: 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call") +Tested-by: Dan Aloni +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/regulator-devres-add-api-for-reference-voltage-suppl.patch b/queue-6.1/regulator-devres-add-api-for-reference-voltage-suppl.patch new file mode 100644 index 0000000000..74b8b6339a --- /dev/null +++ b/queue-6.1/regulator-devres-add-api-for-reference-voltage-suppl.patch @@ -0,0 +1,135 @@ +From 3e6e6c7428efd2361b315e4d25ab7d9f46999d75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Apr 2024 18:40:09 -0500 +Subject: regulator: devres: add API for reference voltage supplies + +From: David Lechner + +[ 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 +Link: https://lore.kernel.org/r/20240429-regulator-get-enable-get-votlage-v2-1-b1f11ab766c1@baylibre.com +Signed-off-by: Mark Brown +Stable-dep-of: fddb5ceaf901 ("hwmon: (ads7828) Fix external VREF regulator handling") +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.1/revert-net-thunderbolt-enable-end-to-end-flow-contro.patch b/queue-6.1/revert-net-thunderbolt-enable-end-to-end-flow-contro.patch new file mode 100644 index 0000000000..fa8294ef12 --- /dev/null +++ b/queue-6.1/revert-net-thunderbolt-enable-end-to-end-flow-contro.patch @@ -0,0 +1,104 @@ +From b027f0b01039c63870bf12cd123f200908a3738e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Fan Ye +Acked-by: Mika Westerberg +Link: https://patch.msgid.link/20260727123002.25225-1-fy15309206903@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/sctp-clear-control-chunk-transport-if-it-is-being-re.patch b/queue-6.1/sctp-clear-control-chunk-transport-if-it-is-being-re.patch new file mode 100644 index 0000000000..f296968af5 --- /dev/null +++ b/queue-6.1/sctp-clear-control-chunk-transport-if-it-is-being-re.patch @@ -0,0 +1,54 @@ +From 879e9ab6a6e3aff68f8f71bf31158ef05ca48427 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 11:18:40 -0400 +Subject: sctp: clear control chunk transport if it is being removed + +From: Xin Long + +[ 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 +Signed-off-by: Xin Long +Link: https://patch.msgid.link/7e1168cb722132152a29d47e5eafaeac4a3bf6f3.1785943120.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch b/queue-6.1/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch new file mode 100644 index 0000000000..98e2668618 --- /dev/null +++ b/queue-6.1/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch @@ -0,0 +1,57 @@ +From 65c7b65748a0675ca35dad92c4acd80bebd5063e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 10:55:14 +0800 +Subject: sctp: fix addip_serial increment on ASCONF_ACK allocation failure + +From: Qing Luo + +[ 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 +Acked-by: Xin Long +Link: https://patch.msgid.link/20260804025514.241767-1-l1138897701@163.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch b/queue-6.1/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch new file mode 100644 index 0000000000..50aaa5d967 --- /dev/null +++ b/queue-6.1/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch @@ -0,0 +1,88 @@ +From 75fc146554b94371e37cac9821244db25bd37c27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 21:46:35 +0200 +Subject: selftests/ftrace: refactor eprobes test to fix argument checks + +From: Martin Kaiser + +[ 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 " 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 +Closes: https://lore.kernel.org/oe-lkp/202607151010.b68428e1-lkp@intel.com +Signed-off-by: Martin Kaiser +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + .../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 ". []":README ++# requires: dynamic_events events/syscalls/sys_enter_chdir ". []":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 + diff --git a/queue-6.1/series b/queue-6.1/series index 437503364c..d76905fd83 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -485,3 +485,50 @@ bluetooth-6lowpan-fix-using-chan-conn-as-indication-.patch 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 diff --git a/queue-6.1/tcp-add-a-scheduling-point-in-established_get_first.patch b/queue-6.1/tcp-add-a-scheduling-point-in-established_get_first.patch new file mode 100644 index 0000000000..2ed2472fcc --- /dev/null +++ b/queue-6.1/tcp-add-a-scheduling-point-in-established_get_first.patch @@ -0,0 +1,59 @@ +From 9e8a8420178d9d36a834579bd7d9d7583b31343e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Jul 2023 11:24:05 +0800 +Subject: tcp: add a scheduling point in established_get_first() + +From: Jian Wen + +[ 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 +Reviewed-by: Simon Horman +Link: https://lore.kernel.org/r/20230711032405.3253025-1-wenjian1@xiaomi.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + + #include + #include +@@ -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 + diff --git a/queue-6.1/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch b/queue-6.1/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch new file mode 100644 index 0000000000..17d337c3ba --- /dev/null +++ b/queue-6.1/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch @@ -0,0 +1,72 @@ +From b46f82e783f2f0681bd1909b9108db735c1c0ce8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 14:17:38 +0800 +Subject: tcp: fix TFO max_qlen accounting across reuseport migration + +From: Jiayuan Chen + +[ 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 +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260803061739.134737-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/tls-don-t-abort-the-connection-on-signal-interrupted.patch b/queue-6.1/tls-don-t-abort-the-connection-on-signal-interrupted.patch new file mode 100644 index 0000000000..8357296846 --- /dev/null +++ b/queue-6.1/tls-don-t-abort-the-connection-on-signal-interrupted.patch @@ -0,0 +1,45 @@ +From 63ed3bacda49ea105900dcc7ff518c9c99ff608e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 08:22:48 +0200 +Subject: tls: don't abort the connection on signal-interrupted sends + +From: Maximilian Immanuel Brandtner + +[ 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 +Link: https://patch.msgid.link/20260805063109.1772314-1-maxbr@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch b/queue-6.1/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch new file mode 100644 index 0000000000..d8a45eae80 --- /dev/null +++ b/queue-6.1/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch @@ -0,0 +1,53 @@ +From 9fd99edd87f85f925d5d78255f681109cc34c539 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 17:35:54 +0800 +Subject: udp: fix potential use-after-free in tunnel segmentation + +From: Xuanqiang Luo + +[ 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 +Reviewed-by: Antoine Tenart +Link: https://patch.msgid.link/20260730093554.68127-1-xuanqiang.luo@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch b/queue-6.1/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch new file mode 100644 index 0000000000..34851e918b --- /dev/null +++ b/queue-6.1/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch @@ -0,0 +1,56 @@ +From ba38e29ad91f4d3dbbe63dfe5142cba98e94c0d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 15:02:02 -0700 +Subject: vhost/vdpa: reject overflowing PA map page counts on 32-bit + +From: Yousef Alhouseen + +[ 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 +Signed-off-by: Yousef Alhouseen +Signed-off-by: Michael S. Tsirkin +Message-ID: +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch b/queue-6.12/arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch new file mode 100644 index 0000000000..26d449c0d1 --- /dev/null +++ b/queue-6.12/arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch @@ -0,0 +1,39 @@ +From 00e90e1126706b1f5d9a21ddcc2adb8ca4d81471 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Jul 2026 14:57:22 -0700 +Subject: ARM: dts: BCM5301X: fix PCIe controller 2 second interrupt + +From: Rosen Penev + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch b/queue-6.12/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch new file mode 100644 index 0000000000..b18b978b36 --- /dev/null +++ b/queue-6.12/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch @@ -0,0 +1,50 @@ +From 04d0bd8271e8d4919abe1bdbd73a4789a8a1e68f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 24 May 2026 23:38:46 -0400 +Subject: ARM: npcm: Fix OF node refcount leaks in SMP setup + +From: Yuho Choi + +[ 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 +Reviewed-by: Avi Fishman +Signed-off-by: Andrew Jeffery +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/arm64-dts-broadcom-bcm2712-remove-non-functional-el2.patch b/queue-6.12/arm64-dts-broadcom-bcm2712-remove-non-functional-el2.patch new file mode 100644 index 0000000000..6d1e52e1ce --- /dev/null +++ b/queue-6.12/arm64-dts-broadcom-bcm2712-remove-non-functional-el2.patch @@ -0,0 +1,52 @@ +From 043772828440f5fcf298190ad3f107baa002cc74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 21:45:27 +0100 +Subject: arm64: dts: broadcom: bcm2712: Remove non-functional EL2 virtual + timer + +From: Daniel Drake + +[ 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 +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 +Link: https://lore.kernel.org/r/20260716-bcm2712-el2-v2-1-e708f7fb42fa@reactivated.net +Signed-off-by: Florian Fainelli +Signed-off-by: Sasha Levin +--- + 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)>, + , + , +- ; + }; + }; +-- +2.53.0 + diff --git a/queue-6.12/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch b/queue-6.12/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch new file mode 100644 index 0000000000..b03499d26b --- /dev/null +++ b/queue-6.12/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch @@ -0,0 +1,52 @@ +From 6de6aaa202d283ccc747b28870d61ed42956dd2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Aug 2026 14:06:28 +0800 +Subject: ata: pata_sl82c105: fix bridge revision use-after-free + +From: Hongyan Xu + +[ 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 +Reviewed-by: Niklas Cassel +Signed-off-by: Damien Le Moal +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bnxt_en-determine-and-store-default-rx-ring-in-vnic-.patch b/queue-6.12/bnxt_en-determine-and-store-default-rx-ring-in-vnic-.patch new file mode 100644 index 0000000000..531302c2b2 --- /dev/null +++ b/queue-6.12/bnxt_en-determine-and-store-default-rx-ring-in-vnic-.patch @@ -0,0 +1,155 @@ +From fb2de7155c33a54ebc8104369b5db136c6e8eb60 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:09:34 -0700 +Subject: bnxt_en: Determine and store default RX ring in vnic structure + +From: Shravya KN + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: Shravya KN +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-3-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 0b137529a899 ("bnxt_en: Refresh VNIC default ring on queue restart if needed") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bnxt_en-fix-ptp-pps-setting-bug.patch b/queue-6.12/bnxt_en-fix-ptp-pps-setting-bug.patch new file mode 100644 index 0000000000..c96adb2512 --- /dev/null +++ b/queue-6.12/bnxt_en-fix-ptp-pps-setting-bug.patch @@ -0,0 +1,54 @@ +From 6cb21e23d9f2c83e3a40bd7a3326a06500b3c1a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:09:37 -0700 +Subject: bnxt_en: Fix PTP PPS setting bug + +From: Keegan Freyhof + +[ 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 +Signed-off-by: Keegan Freyhof +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-6-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bnxt_en-move-rss-table-fill-outside-__bnxt_hwrm_vnic.patch b/queue-6.12/bnxt_en-move-rss-table-fill-outside-__bnxt_hwrm_vnic.patch new file mode 100644 index 0000000000..5d9b75befc --- /dev/null +++ b/queue-6.12/bnxt_en-move-rss-table-fill-outside-__bnxt_hwrm_vnic.patch @@ -0,0 +1,75 @@ +From 89afe7938643972de8d72e7efa0bef8090cc3614 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: Shravya KN +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-2-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 0b137529a899 ("bnxt_en: Refresh VNIC default ring on queue restart if needed") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bnxt_en-refresh-vnic-default-ring-on-queue-restart-i.patch b/queue-6.12/bnxt_en-refresh-vnic-default-ring-on-queue-restart-i.patch new file mode 100644 index 0000000000..73649dfc2b --- /dev/null +++ b/queue-6.12/bnxt_en-refresh-vnic-default-ring-on-queue-restart-i.patch @@ -0,0 +1,46 @@ +From a00c79fd277fc35ea09d592e55766b979e1cd5cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:09:35 -0700 +Subject: bnxt_en: Refresh VNIC default ring on queue restart if needed + +From: Shravya KN + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: Shravya KN +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-4-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch b/queue-6.12/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch new file mode 100644 index 0000000000..3ffa574d70 --- /dev/null +++ b/queue-6.12/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch @@ -0,0 +1,80 @@ +From 27a457e89c78d1324b92e92ff0deb5395fe76840 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) + +[ 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) +Reviewed-by: Nikolay Aleksandrov +Acked-by: Jay Vosburgh +Link: https://patch.msgid.link/20260725233930.2957317-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bpf-preserve-pointer-state-for-commuted-arithmetic.patch b/queue-6.12/bpf-preserve-pointer-state-for-commuted-arithmetic.patch new file mode 100644 index 0000000000..612cab1728 --- /dev/null +++ b/queue-6.12/bpf-preserve-pointer-state-for-commuted-arithmetic.patch @@ -0,0 +1,74 @@ +From 436fac20447f0da139539fc8ce1882f9bba4f227 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 15:18:28 +0000 +Subject: bpf: Preserve pointer state for commuted arithmetic + +From: Yiyang Chen + +[ 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 +Tested-by: Daniel Wade +Acked-by: Shung-Hsi Yu +Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-2-8ee297e2346b@mails.tsinghua.edu.cn +Signed-off-by: Eduard Zingerman +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bpf-tcp-avoid-socket-skips-and-repeats-during-iterat.patch b/queue-6.12/bpf-tcp-avoid-socket-skips-and-repeats-during-iterat.patch new file mode 100644 index 0000000000..906a7a2938 --- /dev/null +++ b/queue-6.12/bpf-tcp-avoid-socket-skips-and-repeats-during-iterat.patch @@ -0,0 +1,240 @@ +From 9ae64c65e362fdbae2f62491e7e87f50e6ed3cf1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Jul 2025 11:09:09 -0700 +Subject: bpf: tcp: Avoid socket skips and repeats during iteration + +From: Jordan Rife + +[ 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 +Signed-off-by: Martin KaFai Lau +Acked-by: Stanislav Fomichev +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + + #include + #include +@@ -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 + diff --git a/queue-6.12/bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch b/queue-6.12/bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch new file mode 100644 index 0000000000..89e867009d --- /dev/null +++ b/queue-6.12/bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch @@ -0,0 +1,170 @@ +From 8d7757764746b30097751e52c837e09313d587df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) + +[ 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) +Reviewed-by: Kuniyuki Iwashima +Link: https://lore.kernel.org/bpf/20260730-bpf-iter-tcp-refcnt-v3-1-754b9c8a6717@linux.dev +Signed-off-by: Kumar Kartikeya Dwivedi +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bpf-tcp-get-rid-of-st_bucket_done.patch b/queue-6.12/bpf-tcp-get-rid-of-st_bucket_done.patch new file mode 100644 index 0000000000..f8d96a5588 --- /dev/null +++ b/queue-6.12/bpf-tcp-get-rid-of-st_bucket_done.patch @@ -0,0 +1,82 @@ +From 139dc03673e06ef584644ff2116efe20a1a97d4c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Jul 2025 11:09:07 -0700 +Subject: bpf: tcp: Get rid of st_bucket_done + +From: Jordan Rife + +[ 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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Acked-by: Stanislav Fomichev +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bpf-tcp-make-mem-flags-configurable-through-bpf_iter.patch b/queue-6.12/bpf-tcp-make-mem-flags-configurable-through-bpf_iter.patch new file mode 100644 index 0000000000..ff7a98f53d --- /dev/null +++ b/queue-6.12/bpf-tcp-make-mem-flags-configurable-through-bpf_iter.patch @@ -0,0 +1,64 @@ +From 009d9d25c6e9cbf1db069fb3ff0686e37c2a939b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Acked-by: Stanislav Fomichev +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bpf-tcp-make-sure-iter-batch-always-contains-a-full-.patch b/queue-6.12/bpf-tcp-make-sure-iter-batch-always-contains-a-full-.patch new file mode 100644 index 0000000000..f3a9bee8b9 --- /dev/null +++ b/queue-6.12/bpf-tcp-make-sure-iter-batch-always-contains-a-full-.patch @@ -0,0 +1,257 @@ +From f3e42445ab9d1223446821a4e07ebd1692bfd80b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Acked-by: Stanislav Fomichev +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bpf-tcp-use-bpf_tcp_iter_batch_item-for-bpf_tcp_iter.patch b/queue-6.12/bpf-tcp-use-bpf_tcp_iter_batch_item-for-bpf_tcp_iter.patch new file mode 100644 index 0000000000..fcec70d253 --- /dev/null +++ b/queue-6.12/bpf-tcp-use-bpf_tcp_iter_batch_item-for-bpf_tcp_iter.patch @@ -0,0 +1,124 @@ +From 7e3b3d5ea0bbccea9dc8004d4d619bcaa8ec62f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Acked-by: Stanislav Fomichev +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch b/queue-6.12/btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch new file mode 100644 index 0000000000..b0555684ba --- /dev/null +++ b/queue-6.12/btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch @@ -0,0 +1,96 @@ +From 85600276fea216f797cf6d957f07becd1f798476 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 14:53:52 +0300 +Subject: btrfs: fix memory leak in btrfs_do_encoded_write() + +From: Dmitry Antipov + +[ 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 +Signed-off-by: Dmitry Antipov +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/counter-microchip-tcb-capture-fix-dt-channel-validat.patch b/queue-6.12/counter-microchip-tcb-capture-fix-dt-channel-validat.patch new file mode 100644 index 0000000000..7b3a73f523 --- /dev/null +++ b/queue-6.12/counter-microchip-tcb-capture-fix-dt-channel-validat.patch @@ -0,0 +1,70 @@ +From 9c6d694eb55ebc03717e944215ae8b4df9955e92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Jul 2026 04:29:10 +0000 +Subject: counter: microchip-tcb-capture: Fix DT channel validation + +From: Babanpreet Singh + +[ 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 +Reviewed-by: Joshua Crofts +Link: https://lore.kernel.org/r/20260714042910.7-1-bbnpreetsingh@gmail.com +Signed-off-by: William Breathitt Gray +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/devlink-fix-net-namespace-reference-leak-in-reload.patch b/queue-6.12/devlink-fix-net-namespace-reference-leak-in-reload.patch new file mode 100644 index 0000000000..b3c205b567 --- /dev/null +++ b/queue-6.12/devlink-fix-net-namespace-reference-leak-in-reload.patch @@ -0,0 +1,42 @@ +From 1f8dec0746a763ff605a09a5f978abfb1954dab6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 11:06:00 +0300 +Subject: devlink: fix net namespace reference leak in reload + +From: Or Har-Toov + +[ 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 +Reviewed-by: Jiri Pirko +Signed-off-by: Tariq Toukan +Reviewed-by: Antoine Tenart +Link: https://patch.msgid.link/20260729080600.2427721-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/drm-bridge-ps8640-propagate-aux-transfer-register-er.patch b/queue-6.12/drm-bridge-ps8640-propagate-aux-transfer-register-er.patch new file mode 100644 index 0000000000..0135d6e441 --- /dev/null +++ b/queue-6.12/drm-bridge-ps8640-propagate-aux-transfer-register-er.patch @@ -0,0 +1,79 @@ +From 832ccf4113810dad4ebb60a53cab7ed017244a79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jul 2026 10:38:06 +0800 +Subject: drm/bridge: ps8640: propagate AUX transfer register errors + +From: Pengpeng Hou + +[ 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 +Reviewed-by: Douglas Anderson +Signed-off-by: Douglas Anderson +Link: https://patch.msgid.link/20260723103509.2-ps8640-v2-pengpeng@iscas.ac.cn +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/enic-fix-tx_hang_reset-use-after-free-on-device-remo.patch b/queue-6.12/enic-fix-tx_hang_reset-use-after-free-on-device-remo.patch new file mode 100644 index 0000000000..53dfc21620 --- /dev/null +++ b/queue-6.12/enic-fix-tx_hang_reset-use-after-free-on-device-remo.patch @@ -0,0 +1,49 @@ +From 09810a3f6ddacb2cfe1759de76979bac22a5cf8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 23:26:30 -0700 +Subject: enic: fix tx_hang_reset use-after-free on device removal + +From: Satish Kharat + +[ 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 +Link: https://patch.msgid.link/20260728062730.2394873-1-satishkh@cisco.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/hwmon-ads7828-fix-external-vref-regulator-handling.patch b/queue-6.12/hwmon-ads7828-fix-external-vref-regulator-handling.patch new file mode 100644 index 0000000000..e2833eb921 --- /dev/null +++ b/queue-6.12/hwmon-ads7828-fix-external-vref-regulator-handling.patch @@ -0,0 +1,71 @@ +From 63cb1925c4569549cbef27de999074df14cb6d51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 14:16:45 +0800 +Subject: hwmon: (ads7828) Fix external VREF regulator handling + +From: Qingshuang Fu + +[ 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 +Link: https://lore.kernel.org/r/20260805061645.1331652-1-fffsqian@163.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch b/queue-6.12/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch new file mode 100644 index 0000000000..67049eb2fe --- /dev/null +++ b/queue-6.12/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch @@ -0,0 +1,50 @@ +From fb2a43eb8e0a907cfa44b6b6e519a4ab1efd0205 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://lore.kernel.org/r/anLj9gPWRoRDbQBV@monster.localdomain +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/hwmon-ltc4282-avoid-overflow-in-maximum-power-calcul.patch b/queue-6.12/hwmon-ltc4282-avoid-overflow-in-maximum-power-calcul.patch new file mode 100644 index 0000000000..b3e3840cec --- /dev/null +++ b/queue-6.12/hwmon-ltc4282-avoid-overflow-in-maximum-power-calcul.patch @@ -0,0 +1,105 @@ +From eb613b8de08db6dfaadc9ff4e30e052f0a5e98f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282") +Cc: Nuno Sa +Reviewed-by: Nuno Sá +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/hwmon-ltc4282-clamp-negative-current-limits.patch b/queue-6.12/hwmon-ltc4282-clamp-negative-current-limits.patch new file mode 100644 index 0000000000..3acca3e750 --- /dev/null +++ b/queue-6.12/hwmon-ltc4282-clamp-negative-current-limits.patch @@ -0,0 +1,69 @@ +From d786a3cac4126469ec120c715d6dc3151c38c5e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282") +Cc: Nuno Sa +Reviewed-by: Nuno Sá +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 + diff --git a/queue-6.12/hwmon-ltc4282-fix-parsing-adi-current-limit-sense-mi.patch b/queue-6.12/hwmon-ltc4282-fix-parsing-adi-current-limit-sense-mi.patch new file mode 100644 index 0000000000..57b444f45f --- /dev/null +++ b/queue-6.12/hwmon-ltc4282-fix-parsing-adi-current-limit-sense-mi.patch @@ -0,0 +1,68 @@ +From 32ff69a79971fb12637f5867ef4de8ebf635cda4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282") +Cc: Nuno Sa +Reviewed-by: Nuno Sá +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/hwmon-nzxt-smart2-check-return-value-of-init_device-.patch b/queue-6.12/hwmon-nzxt-smart2-check-return-value-of-init_device-.patch new file mode 100644 index 0000000000..7c0d041de5 --- /dev/null +++ b/queue-6.12/hwmon-nzxt-smart2-check-return-value-of-init_device-.patch @@ -0,0 +1,57 @@ +From 6f15db240b39e6e8737de4011417ace1738f3885 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 15:48:42 +0800 +Subject: hwmon: (nzxt-smart2) Check return value of init_device() in probe + +From: Qingshuang Fu + +[ 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 +Link: https://lore.kernel.org/r/20260804074842.505923-1-fffsqian@163.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch b/queue-6.12/hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch new file mode 100644 index 0000000000..867fd106b7 --- /dev/null +++ b/queue-6.12/hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch @@ -0,0 +1,71 @@ +From 39949a72bea670fd17987e778cc779f802aad964 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 14:12:31 -0700 +Subject: hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations + +From: Guenter Roeck + +[ 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 +Fixes: 94ee5fcc240fe ("hwmon: (pmbus/lm25066) Support configurable sense resistor values") +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + #include + #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 + diff --git a/queue-6.12/ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch b/queue-6.12/ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch new file mode 100644 index 0000000000..692842305c --- /dev/null +++ b/queue-6.12/ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch @@ -0,0 +1,259 @@ +From 25f23689466cbbb504002ef387913d04cfb9d09a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 21:35:05 +0300 +Subject: ipvs: avoid out-of-bounds write in ip_vs_nat_icmp + +From: Julian Anastasov + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/ipvs-return-the-csum-validation-for-forward-hook.patch b/queue-6.12/ipvs-return-the-csum-validation-for-forward-hook.patch new file mode 100644 index 0000000000..20d8e8425c --- /dev/null +++ b/queue-6.12/ipvs-return-the-csum-validation-for-forward-hook.patch @@ -0,0 +1,100 @@ +From 4a66052a6c966c86cc63f9e7658c5646f79b9408 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 21:35:06 +0300 +Subject: ipvs: return the csum validation for forward hook + +From: Julian Anastasov + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 /* for union nf_inet_addr */ + #include + #include /* for struct ipv6hdr */ +-#include + #include +-#include + #if IS_ENABLED(CONFIG_NF_CONNTRACK) + #include + #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 + diff --git a/queue-6.12/net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch b/queue-6.12/net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch new file mode 100644 index 0000000000..c5904de204 --- /dev/null +++ b/queue-6.12/net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch @@ -0,0 +1,81 @@ +From 44eb5f3ba89966232a30ecde4bad6e59d7093c1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 13:15:08 +0000 +Subject: net/atm: fix slab-out-of-bounds read in vcc_setsockopt() + +From: Eric Dumazet + +[ 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 +Link: https://patch.msgid.link/20260805131508.3227331-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch b/queue-6.12/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch new file mode 100644 index 0000000000..58b18e1959 --- /dev/null +++ b/queue-6.12/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch @@ -0,0 +1,42 @@ +From eef0796e2400996a278249697bd16f8f599919bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-hns3-fix-speed-configuration-residue-after-drive.patch b/queue-6.12/net-hns3-fix-speed-configuration-residue-after-drive.patch new file mode 100644 index 0000000000..66d7f7fd55 --- /dev/null +++ b/queue-6.12/net-hns3-fix-speed-configuration-residue-after-drive.patch @@ -0,0 +1,76 @@ +From be5615afc4cda920f79408139c9e104ad86183ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 17:30:36 +0800 +Subject: net: hns3: fix speed configuration residue after driver reload + +From: Jijie Shao + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260724093036.426631-1-shaojijie@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-mlx5-fw_tracer-return-null-on-create-error.patch b/queue-6.12/net-mlx5-fw_tracer-return-null-on-create-error.patch new file mode 100644 index 0000000000..85576eec33 --- /dev/null +++ b/queue-6.12/net-mlx5-fw_tracer-return-null-on-create-error.patch @@ -0,0 +1,134 @@ +From 12ee39e1d8741dace9c1b2257a088e0d8630a378 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 11:04:02 +0300 +Subject: net/mlx5: fw_tracer, return NULL on create error + +From: Michael Guralnik + +[ 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 +Reviewed-by: Shay Drori +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260729080402.2427184-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.12/net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch b/queue-6.12/net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch new file mode 100644 index 0000000000..6231b4789b --- /dev/null +++ b/queue-6.12/net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch @@ -0,0 +1,100 @@ +From d40cda53d7f3115b37b88f7d65037f3964c806ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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 + + +Fixes: 04de7dda7394 ("net/mlx5e: Infrastructure for duplicated offloading of TC flows") +Signed-off-by: Shay Drory +Reviewed-by: Cosmin Ratiu +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260728044338.2271143-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch b/queue-6.12/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch new file mode 100644 index 0000000000..ccd5534036 --- /dev/null +++ b/queue-6.12/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch @@ -0,0 +1,60 @@ +From bbba96b65172c59c4b73969d8187ee32555a118e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Henry Martin +Link: https://patch.msgid.link/20260803043618.3210301-1-bsdhenrymartin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-openvswitch-check-ethernet-header-length-in-key_.patch b/queue-6.12/net-openvswitch-check-ethernet-header-length-in-key_.patch new file mode 100644 index 0000000000..491e394e76 --- /dev/null +++ b/queue-6.12/net-openvswitch-check-ethernet-header-length-in-key_.patch @@ -0,0 +1,78 @@ +From f8b4f08db0c680fbc67b7b4209c6f507f8da3da5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 18:20:06 -0400 +Subject: net/openvswitch: check Ethernet header length in key_extract() + +From: Cen Zhang (Microsoft) + +[ 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 +Signed-off-by: Cen Zhang (Microsoft) +Reviewed-by: Ilya Maximets +Link: https://patch.msgid.link/20260730222006.118652-1-blbllhy@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-prestera-validate-firmware-header-length.patch b/queue-6.12/net-prestera-validate-firmware-header-length.patch new file mode 100644 index 0000000000..80a0dadd82 --- /dev/null +++ b/queue-6.12/net-prestera-validate-firmware-header-length.patch @@ -0,0 +1,42 @@ +From a9f480441ad7481fbf3775bb5d66002f7b5fcdce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 22:19:06 +0800 +Subject: net: prestera: validate firmware header length + +From: Pengpeng Hou + +[ 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 +Acked-by: Elad Nachman +Link: https://patch.msgid.link/20260731141500.1-prestera-v2-pengpeng@iscas.ac.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-remove-warn_on_once-from-sk_mc_loop.patch b/queue-6.12/net-remove-warn_on_once-from-sk_mc_loop.patch new file mode 100644 index 0000000000..51fd57178f --- /dev/null +++ b/queue-6.12/net-remove-warn_on_once-from-sk_mc_loop.patch @@ -0,0 +1,45 @@ +From 36425ae87025956c1a7d109e6208592bf701706a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 15:20:48 +0000 +Subject: net: remove WARN_ON_ONCE() from sk_mc_loop() + +From: Eric Dumazet + +[ 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 +Link: https://patch.msgid.link/20260804152048.2134341-1-edumazet@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch b/queue-6.12/net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch new file mode 100644 index 0000000000..ef7cc2cdd4 --- /dev/null +++ b/queue-6.12/net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch @@ -0,0 +1,116 @@ +From 64e91994f52a60753479ee4dea674bc7b5755d51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Tested-by: Victor Nogueira +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260801125632.360365-1-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch b/queue-6.12/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch new file mode 100644 index 0000000000..80294988b8 --- /dev/null +++ b/queue-6.12/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch @@ -0,0 +1,142 @@ +From 838c70142b181c6adb74f7939a48fa49b5b8d156 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Suggested-by: Paolo Abeni +Tested-by: Victor Nogueira +Tested-by: Santosh Kalluri +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260729094411.46257-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch b/queue-6.12/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch new file mode 100644 index 0000000000..eda526a7c6 --- /dev/null +++ b/queue-6.12/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch @@ -0,0 +1,50 @@ +From 8355e9ad33518ce0b79c83b05c20e23d357587ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reported-by: Ren Wei +Signed-off-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260729191417.45665-1-toke@toke.dk +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch b/queue-6.12/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch new file mode 100644 index 0000000000..76810bb485 --- /dev/null +++ b/queue-6.12/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch @@ -0,0 +1,57 @@ +From 0427380ab1515e4e31419c3cf965c2b5a51bb4f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Hidayath Khan +Reviewed-by: Sidraya Jayagond +Reviewed-by: Dust Li +Link: https://patch.msgid.link/20260729130153.970800-1-mjambigi@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch b/queue-6.12/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch new file mode 100644 index 0000000000..94a4b154d3 --- /dev/null +++ b/queue-6.12/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch @@ -0,0 +1,71 @@ +From 2d9d7284200dfa2b9a76e8a092c9b575255ccffb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Sidraya Jayagond +Reviewed-by: Breno Leitao +Reviewed-by: Dust Li +Link: https://patch.msgid.link/20260803070701.126339-1-sidraya@linux.ibm.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch b/queue-6.12/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch new file mode 100644 index 0000000000..9b8b37fd0c --- /dev/null +++ b/queue-6.12/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch @@ -0,0 +1,117 @@ +From f835e31bec55bd97eec618d3f5d7b51115e218b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 14:38:50 +0000 +Subject: net: thunderbolt: Tear down DMA paths before stopping the rings + +From: Fan XinRan + +[ 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 +Acked-by: Mika Westerberg +Link: https://patch.msgid.link/20260803-b4-tbnet-teardown-v2-1-27de6a13ca2d@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/netfilter-ipset-switch-ext_size-to-atomic64_t.patch b/queue-6.12/netfilter-ipset-switch-ext_size-to-atomic64_t.patch new file mode 100644 index 0000000000..78cb3327ee --- /dev/null +++ b/queue-6.12/netfilter-ipset-switch-ext_size-to-atomic64_t.patch @@ -0,0 +1,134 @@ +From e150589a970d2808d2190209e0c52aee3a7696b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 20:38:50 +0200 +Subject: netfilter: ipset: switch ext_size to atomic64_t + +From: Jozsef Kadlecsik + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/ipset/ip_set.h | 2 +- + net/netfilter/ipset/ip_set_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 + diff --git a/queue-6.12/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch b/queue-6.12/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch new file mode 100644 index 0000000000..9ed75fe9cc --- /dev/null +++ b/queue-6.12/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch @@ -0,0 +1,50 @@ +From 5f96b7d574fd9c09b49512dd098211ef3aeb436b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Jun 2026 14:31:00 -0400 +Subject: NFS: Pin the 'struct nfs_server' during a FREE_STATEID call + +From: Anna Schumaker + +[ 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 +Fixes: 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call") +Tested-by: Dan Aloni +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/pds_core-cancel-pending-pci-reset-work-on-aer-recove.patch b/queue-6.12/pds_core-cancel-pending-pci-reset-work-on-aer-recove.patch new file mode 100644 index 0000000000..bc05bd3ccc --- /dev/null +++ b/queue-6.12/pds_core-cancel-pending-pci-reset-work-on-aer-recove.patch @@ -0,0 +1,54 @@ +From b448d20c7ea930a4ab80846136ccfbfad91b6db7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 17:00:30 +0000 +Subject: pds_core: cancel pending PCI reset work on AER recovery + +From: Nikhil P. Rao + +[ 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 +Closes: https://sashiko.dev/#/patchset/20260714180223.1642792-2-nikhil.rao%40amd.com?part=1 +Signed-off-by: Nikhil P. Rao +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260727170030.361116-1-nikhil.rao@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/pds_core-keep-the-health-thread-stopped-during-reset.patch b/queue-6.12/pds_core-keep-the-health-thread-stopped-during-reset.patch new file mode 100644 index 0000000000..0fa90de677 --- /dev/null +++ b/queue-6.12/pds_core-keep-the-health-thread-stopped-during-reset.patch @@ -0,0 +1,87 @@ +From d7214c5db97de33d0312a0657fefd5e0352ccc6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 16:45:48 +0000 +Subject: pds_core: keep the health thread stopped during reset + +From: Nikhil P. Rao + +[ 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 +Closes: https://sashiko.dev/#/patchset/20260629200358.2626129-1-nikhil.rao%40amd.com?part=2 +Signed-off-by: Nikhil P. Rao +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260727164548.359562-1-nikhil.rao@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/revert-net-thunderbolt-enable-end-to-end-flow-contro.patch b/queue-6.12/revert-net-thunderbolt-enable-end-to-end-flow-contro.patch new file mode 100644 index 0000000000..09ec81e666 --- /dev/null +++ b/queue-6.12/revert-net-thunderbolt-enable-end-to-end-flow-contro.patch @@ -0,0 +1,104 @@ +From c20093e513b188043cfddb54cf1b19c7f46c5167 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Fan Ye +Acked-by: Mika Westerberg +Link: https://patch.msgid.link/20260727123002.25225-1-fy15309206903@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/sctp-clear-control-chunk-transport-if-it-is-being-re.patch b/queue-6.12/sctp-clear-control-chunk-transport-if-it-is-being-re.patch new file mode 100644 index 0000000000..0ed9c534e7 --- /dev/null +++ b/queue-6.12/sctp-clear-control-chunk-transport-if-it-is-being-re.patch @@ -0,0 +1,54 @@ +From 518cad2e31e88bf9af01a051848b761626d77be6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 11:18:40 -0400 +Subject: sctp: clear control chunk transport if it is being removed + +From: Xin Long + +[ 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 +Signed-off-by: Xin Long +Link: https://patch.msgid.link/7e1168cb722132152a29d47e5eafaeac4a3bf6f3.1785943120.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch b/queue-6.12/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch new file mode 100644 index 0000000000..8f44e0bcff --- /dev/null +++ b/queue-6.12/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch @@ -0,0 +1,57 @@ +From cdcadca44dbfabc328f32087de184c92f166c53b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 10:55:14 +0800 +Subject: sctp: fix addip_serial increment on ASCONF_ACK allocation failure + +From: Qing Luo + +[ 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 +Acked-by: Xin Long +Link: https://patch.msgid.link/20260804025514.241767-1-l1138897701@163.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch b/queue-6.12/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch new file mode 100644 index 0000000000..8da8271852 --- /dev/null +++ b/queue-6.12/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch @@ -0,0 +1,88 @@ +From ef4fb802705b6b0b3209e543dd57b40010a1fb40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 21:46:35 +0200 +Subject: selftests/ftrace: refactor eprobes test to fix argument checks + +From: Martin Kaiser + +[ 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 " 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 +Closes: https://lore.kernel.org/oe-lkp/202607151010.b68428e1-lkp@intel.com +Signed-off-by: Martin Kaiser +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + .../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 ". []":README ++# requires: dynamic_events events/syscalls/sys_enter_chdir ". []":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 + diff --git a/queue-6.12/series b/queue-6.12/series index 92cae60f74..3aa996e848 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -3,3 +3,64 @@ selftests-bpf-fail-unbound-udp-on-sockmap-update.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 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 diff --git a/queue-6.12/tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch b/queue-6.12/tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch new file mode 100644 index 0000000000..237e73bf1a --- /dev/null +++ b/queue-6.12/tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch @@ -0,0 +1,61 @@ +From cddddf06cb080f0040e0f289d29fcb155a4a4744 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 20:08:06 -0700 +Subject: tcp: do not change rcv_ssthresh in tcp_measure_rcv_mss() + +From: Nathan Gao + +[ 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 +Link: https://patch.msgid.link/20260725030806.28135-1-zcgao@amazon.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch b/queue-6.12/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch new file mode 100644 index 0000000000..1d573f4700 --- /dev/null +++ b/queue-6.12/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch @@ -0,0 +1,72 @@ +From 8745835bc1b74aa07d0199ef3d21c486b6da09ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 14:17:38 +0800 +Subject: tcp: fix TFO max_qlen accounting across reuseport migration + +From: Jiayuan Chen + +[ 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 +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260803061739.134737-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/tls-don-t-abort-the-connection-on-signal-interrupted.patch b/queue-6.12/tls-don-t-abort-the-connection-on-signal-interrupted.patch new file mode 100644 index 0000000000..e14848777d --- /dev/null +++ b/queue-6.12/tls-don-t-abort-the-connection-on-signal-interrupted.patch @@ -0,0 +1,45 @@ +From eeed188adcc1abaa2277217059a79b95f9b207c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 08:22:48 +0200 +Subject: tls: don't abort the connection on signal-interrupted sends + +From: Maximilian Immanuel Brandtner + +[ 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 +Link: https://patch.msgid.link/20260805063109.1772314-1-maxbr@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch b/queue-6.12/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch new file mode 100644 index 0000000000..331dead5a5 --- /dev/null +++ b/queue-6.12/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch @@ -0,0 +1,53 @@ +From 73c2b0537a3cf7795645a0026f10b90ffad884f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 17:35:54 +0800 +Subject: udp: fix potential use-after-free in tunnel segmentation + +From: Xuanqiang Luo + +[ 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 +Reviewed-by: Antoine Tenart +Link: https://patch.msgid.link/20260730093554.68127-1-xuanqiang.luo@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/vdpa-mlx5-fix-buffer-length-in-create_direct_keys.patch b/queue-6.12/vdpa-mlx5-fix-buffer-length-in-create_direct_keys.patch new file mode 100644 index 0000000000..6bdc7d2608 --- /dev/null +++ b/queue-6.12/vdpa-mlx5-fix-buffer-length-in-create_direct_keys.patch @@ -0,0 +1,61 @@ +From f521737662e751a84c1220161011c413eecf026b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Jul 2026 16:15:37 +0200 +Subject: vdpa/mlx5: Fix buffer length in create_direct_keys() + +From: Christian Borntraeger + +[ 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 +Tested-by: Dragos Tatulea +Reviewed-by: Dragos Tatulea +Signed-off-by: Michael S. Tsirkin +Message-ID: <20260706141537.3510294-1-borntraeger@linux.ibm.com> +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch b/queue-6.12/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch new file mode 100644 index 0000000000..3f94821012 --- /dev/null +++ b/queue-6.12/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch @@ -0,0 +1,56 @@ +From cfc7f69b3756b93dcef4b1ceef8f776b4f9282eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 15:02:02 -0700 +Subject: vhost/vdpa: reject overflowing PA map page counts on 32-bit + +From: Yousef Alhouseen + +[ 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 +Signed-off-by: Yousef Alhouseen +Signed-off-by: Michael S. Tsirkin +Message-ID: +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/watchdog-bd96801_wdt-fix-timeout-for-enabled-wdg.patch b/queue-6.12/watchdog-bd96801_wdt-fix-timeout-for-enabled-wdg.patch new file mode 100644 index 0000000000..0f39a7573d --- /dev/null +++ b/queue-6.12/watchdog-bd96801_wdt-fix-timeout-for-enabled-wdg.patch @@ -0,0 +1,68 @@ +From 2dd8b4d1f264b9bcd20d171b5b46a015c112b2f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:36:28 +0300 +Subject: watchdog: bd96801_wdt: Fix timeout for enabled WDG + +From: Matti Vaittinen + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/xsk-require-at-least-16-bytes-of-tx-metadata.patch b/queue-6.12/xsk-require-at-least-16-bytes-of-tx-metadata.patch new file mode 100644 index 0000000000..e941494fe9 --- /dev/null +++ b/queue-6.12/xsk-require-at-least-16-bytes-of-tx-metadata.patch @@ -0,0 +1,45 @@ +From a387a9a36e20bee53f038ba56377a4b76fa180bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 09:19:54 -0700 +Subject: xsk: require at least 16 bytes of TX metadata + +From: Stanislav Fomichev + +[ 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) +Link: https://lore.kernel.org/netdev/20260720155210.34229-1-blbllhy@gmail.com/ +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20260727161959.885642-2-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch b/queue-6.18/arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch new file mode 100644 index 0000000000..3b93119c46 --- /dev/null +++ b/queue-6.18/arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch @@ -0,0 +1,39 @@ +From e103ae3ce08a81e9f370eed76a64937c46035332 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Jul 2026 14:57:22 -0700 +Subject: ARM: dts: BCM5301X: fix PCIe controller 2 second interrupt + +From: Rosen Penev + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch b/queue-6.18/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch new file mode 100644 index 0000000000..b90eb8bfd4 --- /dev/null +++ b/queue-6.18/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch @@ -0,0 +1,50 @@ +From 4500feb8c4badefb3b7d7405c51046d084fd1f87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 24 May 2026 23:38:46 -0400 +Subject: ARM: npcm: Fix OF node refcount leaks in SMP setup + +From: Yuho Choi + +[ 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 +Reviewed-by: Avi Fishman +Signed-off-by: Andrew Jeffery +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/arm64-dts-broadcom-bcm2712-remove-non-functional-el2.patch b/queue-6.18/arm64-dts-broadcom-bcm2712-remove-non-functional-el2.patch new file mode 100644 index 0000000000..9b15d1d183 --- /dev/null +++ b/queue-6.18/arm64-dts-broadcom-bcm2712-remove-non-functional-el2.patch @@ -0,0 +1,52 @@ +From 17e2b92983b06e1a1448635e9a75164a4ef5cb5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 21:45:27 +0100 +Subject: arm64: dts: broadcom: bcm2712: Remove non-functional EL2 virtual + timer + +From: Daniel Drake + +[ 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 +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 +Link: https://lore.kernel.org/r/20260716-bcm2712-el2-v2-1-e708f7fb42fa@reactivated.net +Signed-off-by: Florian Fainelli +Signed-off-by: Sasha Levin +--- + 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)>, + , + , +- ; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-purwa-fix-gpu-iommu-property.patch b/queue-6.18/arm64-dts-qcom-purwa-fix-gpu-iommu-property.patch new file mode 100644 index 0000000000..03831e4297 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-purwa-fix-gpu-iommu-property.patch @@ -0,0 +1,99 @@ +From 76f8ef835980d62931cab55379a8488d334ae727 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 02:38:51 +0530 +Subject: arm64: dts: qcom: purwa: Fix GPU IOMMU property + +From: Akhil P Oommen + +[ 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 +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260410-purwa-gpu-dt-fix-v1-1-4637892156cf@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/arm64-dts-qcom-rename-x1e80100-to-hamoa.patch b/queue-6.18/arm64-dts-qcom-rename-x1e80100-to-hamoa.patch new file mode 100644 index 0000000000..ceee5918bf --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-rename-x1e80100-to-hamoa.patch @@ -0,0 +1,323 @@ +From 807dad9bdf0b161d92887feb27f705ed28503ec2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Sep 2025 14:01:55 +0300 +Subject: arm64: dts: qcom: rename x1e80100 to hamoa + +From: Dmitry Baryshkov + +[ 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 +Link: https://lore.kernel.org/r/20250923-rename-dts-v1-2-21888b68c781@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Stable-dep-of: 4cd774c1feb3 ("arm64: dts: qcom: purwa: Fix GPU IOMMU property") +Signed-off-by: Sasha Levin +--- + 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 + #include + +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 + #include + +-#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 + #include + +-#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 + #include + +-#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 + #include + +-#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 + #include + +-#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 + #include + +-#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 + #include + +-#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 + #include + +-#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 + #include + +-#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 + #include + +-#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 + + #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 + diff --git a/queue-6.18/arm64-dts-qcom-rename-x1p42100-to-purwa.patch b/queue-6.18/arm64-dts-qcom-rename-x1p42100-to-purwa.patch new file mode 100644 index 0000000000..ffcf0fa052 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-rename-x1p42100-to-purwa.patch @@ -0,0 +1,84 @@ +From 161ad2851d1c0a69ea962ce11d1d4e4eec2544fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Oct 2025 20:20:15 +0200 +Subject: arm64: dts: qcom: rename x1p42100 to purwa + +From: Dmitry Baryshkov + +[ Upstream commit ef659a5bd91bed7fae2c2a150f8ecca06599ac03 ] + +Follow the example of other platforms and rename X1P42100 to purwa.dtsi. + +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20251030-rename-dts-2-v1-3-80c0b81c4d77@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Stable-dep-of: 4cd774c1feb3 ("arm64: dts: qcom: purwa: Fix GPU IOMMU property") +Signed-off-by: Sasha Levin +--- + 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 + #include + +-#include "x1p42100.dtsi" ++#include "purwa.dtsi" + #include "hamoa-pmics.dtsi" + + /delete-node/ &pmc8380_6; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-rework-x1-based-asus-zenbook-a14-s-di.patch b/queue-6.18/arm64-dts-qcom-rework-x1-based-asus-zenbook-a14-s-di.patch new file mode 100644 index 0000000000..266ab7e4ca --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-rework-x1-based-asus-zenbook-a14-s-di.patch @@ -0,0 +1,471 @@ +From 15d4f31b0ddff9eb4816a2093625418b4558247b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Sep 2025 15:21:36 +0200 +Subject: arm64: dts: qcom: Rework X1-based Asus Zenbook A14's displays + +From: Aleksandrs Vinarskis + +[ 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 +Signed-off-by: Jens Glathe +Reviewed-by: Konrad Dybcio +Signed-off-by: Aleksandrs Vinarskis +Link: https://lore.kernel.org/r/20250927-zenbook-improvements-v3-2-d46c7368dc70@vinarskis.com +Signed-off-by: Bjorn Andersson +Stable-dep-of: 4cd774c1feb3 ("arm64: dts: qcom: purwa: Fix GPU IOMMU property") +Signed-off-by: Sasha Levin +--- + 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 ++ */ ++ ++/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 ++ */ ++ ++/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 + diff --git a/queue-6.18/arm64-dts-qcom-sdm850-lenovo-yoga-c630-lower-psci-cl.patch b/queue-6.18/arm64-dts-qcom-sdm850-lenovo-yoga-c630-lower-psci-cl.patch new file mode 100644 index 0000000000..0fa9b3926d --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sdm850-lenovo-yoga-c630-lower-psci-cl.patch @@ -0,0 +1,45 @@ +From e305238465c6ecc7471b7f9a7eff6f0b2aa0f313 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 01:27:12 +0300 +Subject: arm64: dts: qcom: sdm850-lenovo-yoga-c630: lower PSCI cluster idle + +From: Dmitry Baryshkov + +[ 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 +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260429-c630-fix-idle-v2-1-ac867dad6f21@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + 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 = , + , +-- +2.53.0 + diff --git a/queue-6.18/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch b/queue-6.18/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch new file mode 100644 index 0000000000..5a76d7ef48 --- /dev/null +++ b/queue-6.18/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch @@ -0,0 +1,52 @@ +From d0ce29b412f31047d778be95b9f5c38b0367420f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Aug 2026 14:06:28 +0800 +Subject: ata: pata_sl82c105: fix bridge revision use-after-free + +From: Hongyan Xu + +[ 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 +Reviewed-by: Niklas Cassel +Signed-off-by: Damien Le Moal +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bnge-fix-resource-leak-in-bnge_init_nic-error-path.patch b/queue-6.18/bnge-fix-resource-leak-in-bnge_init_nic-error-path.patch new file mode 100644 index 0000000000..1f785e0666 --- /dev/null +++ b/queue-6.18/bnge-fix-resource-leak-in-bnge_init_nic-error-path.patch @@ -0,0 +1,42 @@ +From 84dd0c16507dfba6d7c95eec452568121e7f6d25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 15:10:22 +0530 +Subject: bnge: Fix resource leak in bnge_init_nic() error path + +From: Bhargava Marreddy + +[ 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 +Reviewed-by: Dharmender Garg +Reviewed-by: Rajashekar Hudumula +Link: https://patch.msgid.link/20260805094022.15487-1-bhargava.marreddy@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bnge-use-int-for-bnge_fix_rings_count-return-value.patch b/queue-6.18/bnge-use-int-for-bnge_fix_rings_count-return-value.patch new file mode 100644 index 0000000000..f5c8e2cab2 --- /dev/null +++ b/queue-6.18/bnge-use-int-for-bnge_fix_rings_count-return-value.patch @@ -0,0 +1,44 @@ +From 694e49b1f0eabf7010d99842845d02cb75d65d3f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 1 Aug 2026 03:09:20 -0700 +Subject: bnge: use int for bnge_fix_rings_count() return value + +From: Alok Tiwari + +[ 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 +Reviewed-by: Bhargava Marreddy +Link: https://patch.msgid.link/20260801100923.1498570-1-alok.a.tiwari@oracle.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bnxt-fix-memory-leak-in-bnxt_queue_mem_alloc-error-c.patch b/queue-6.18/bnxt-fix-memory-leak-in-bnxt_queue_mem_alloc-error-c.patch new file mode 100644 index 0000000000..2a3a543c3b --- /dev/null +++ b/queue-6.18/bnxt-fix-memory-leak-in-bnxt_queue_mem_alloc-error-c.patch @@ -0,0 +1,54 @@ +From ee3c78709260609d7601337ef841a8ebd8da23ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 15:01:31 -0700 +Subject: bnxt: fix memory leak in bnxt_queue_mem_alloc error cases + +From: Will Chen + +[ 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 +Reviewed-by: Joe Damato +Reviewed-by: Michael Chan +Link: https://patch.msgid.link/20260729220132.1256924-1-will.chen.tty@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bnxt_en-determine-and-store-default-rx-ring-in-vnic-.patch b/queue-6.18/bnxt_en-determine-and-store-default-rx-ring-in-vnic-.patch new file mode 100644 index 0000000000..592e5623e5 --- /dev/null +++ b/queue-6.18/bnxt_en-determine-and-store-default-rx-ring-in-vnic-.patch @@ -0,0 +1,155 @@ +From 2a5bdd8f758b2323345ebbcafc622a8476a1ebc3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:09:34 -0700 +Subject: bnxt_en: Determine and store default RX ring in vnic structure + +From: Shravya KN + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: Shravya KN +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-3-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 0b137529a899 ("bnxt_en: Refresh VNIC default ring on queue restart if needed") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch b/queue-6.18/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch new file mode 100644 index 0000000000..b9175c96ac --- /dev/null +++ b/queue-6.18/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch @@ -0,0 +1,57 @@ +From aee1e001495da03a388d6b2cdfea5aa1f5007383 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Kalesh AP +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-5-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch b/queue-6.18/bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch new file mode 100644 index 0000000000..6592a7a19d --- /dev/null +++ b/queue-6.18/bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch @@ -0,0 +1,66 @@ +From aacfa2daf3d8b132e43e6eb38721d0788f8b7832 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Somnath Kotur +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20251126215648.1885936-6-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bnxt_en-fix-ptp-pps-setting-bug.patch b/queue-6.18/bnxt_en-fix-ptp-pps-setting-bug.patch new file mode 100644 index 0000000000..3162363fbc --- /dev/null +++ b/queue-6.18/bnxt_en-fix-ptp-pps-setting-bug.patch @@ -0,0 +1,54 @@ +From fbf62b5c86a648fc5a46f53081460449b32a991f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:09:37 -0700 +Subject: bnxt_en: Fix PTP PPS setting bug + +From: Keegan Freyhof + +[ 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 +Signed-off-by: Keegan Freyhof +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-6-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bnxt_en-move-rss-table-fill-outside-__bnxt_hwrm_vnic.patch b/queue-6.18/bnxt_en-move-rss-table-fill-outside-__bnxt_hwrm_vnic.patch new file mode 100644 index 0000000000..45b5597451 --- /dev/null +++ b/queue-6.18/bnxt_en-move-rss-table-fill-outside-__bnxt_hwrm_vnic.patch @@ -0,0 +1,75 @@ +From a1030280b63fcdac7fc9e586e7fa5ce9982f70c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: Shravya KN +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-2-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 0b137529a899 ("bnxt_en: Refresh VNIC default ring on queue restart if needed") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bnxt_en-refresh-vnic-default-ring-on-queue-restart-i.patch b/queue-6.18/bnxt_en-refresh-vnic-default-ring-on-queue-restart-i.patch new file mode 100644 index 0000000000..0eca72a2e0 --- /dev/null +++ b/queue-6.18/bnxt_en-refresh-vnic-default-ring-on-queue-restart-i.patch @@ -0,0 +1,46 @@ +From 1ff9996190e57f9f4ff49d24cc8b362d75c0c39b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:09:35 -0700 +Subject: bnxt_en: Refresh VNIC default ring on queue restart if needed + +From: Shravya KN + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: Shravya KN +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-4-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch b/queue-6.18/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch new file mode 100644 index 0000000000..e6dbfa4d03 --- /dev/null +++ b/queue-6.18/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch @@ -0,0 +1,80 @@ +From 3b559a15596e2418c9a530f1a89502a4e11b5651 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) + +[ 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) +Reviewed-by: Nikolay Aleksandrov +Acked-by: Jay Vosburgh +Link: https://patch.msgid.link/20260725233930.2957317-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bpf-preserve-pointer-state-for-commuted-arithmetic.patch b/queue-6.18/bpf-preserve-pointer-state-for-commuted-arithmetic.patch new file mode 100644 index 0000000000..496136f686 --- /dev/null +++ b/queue-6.18/bpf-preserve-pointer-state-for-commuted-arithmetic.patch @@ -0,0 +1,74 @@ +From 01c95813af37e406055b7e67372ae48bd3e300e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 15:18:28 +0000 +Subject: bpf: Preserve pointer state for commuted arithmetic + +From: Yiyang Chen + +[ 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 +Tested-by: Daniel Wade +Acked-by: Shung-Hsi Yu +Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-2-8ee297e2346b@mails.tsinghua.edu.cn +Signed-off-by: Eduard Zingerman +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bpf-propagate-untrusted-pointer-state-in-commuted-ar.patch b/queue-6.18/bpf-propagate-untrusted-pointer-state-in-commuted-ar.patch new file mode 100644 index 0000000000..942ec22d4b --- /dev/null +++ b/queue-6.18/bpf-propagate-untrusted-pointer-state-in-commuted-ar.patch @@ -0,0 +1,59 @@ +From 9fb7974d831b5f9814d9ba0bbc74ed3df62c62d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 15:18:29 +0000 +Subject: bpf: Propagate untrusted pointer state in commuted arithmetic + +From: Yiyang Chen + +[ 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 +Tested-by: Daniel Wade +Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-3-8ee297e2346b@mails.tsinghua.edu.cn +Signed-off-by: Eduard Zingerman +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bpf-split-check_reg_sane_offset-in-two-parts.patch b/queue-6.18/bpf-split-check_reg_sane_offset-in-two-parts.patch new file mode 100644 index 0000000000..c2cf795a2a --- /dev/null +++ b/queue-6.18/bpf-split-check_reg_sane_offset-in-two-parts.patch @@ -0,0 +1,112 @@ +From b8e7076f524063ba4e7f374868757137f94e065a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 13:34:21 -0800 +Subject: bpf: split check_reg_sane_offset() in two parts + +From: Eduard Zingerman + +[ 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 +Link: https://lore.kernel.org/r/20260212-ptrs-off-migration-v2-1-00820e4d3438@gmail.com +Signed-off-by: Alexei Starovoitov +Stable-dep-of: cdf19b1b3c01 ("bpf: Propagate untrusted pointer state in commuted arithmetic") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch b/queue-6.18/bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch new file mode 100644 index 0000000000..079eb47914 --- /dev/null +++ b/queue-6.18/bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch @@ -0,0 +1,170 @@ +From ccb35938773815882e066696dbda415f1d0f0d2b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) + +[ 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) +Reviewed-by: Kuniyuki Iwashima +Link: https://lore.kernel.org/bpf/20260730-bpf-iter-tcp-refcnt-v3-1-754b9c8a6717@linux.dev +Signed-off-by: Kumar Kartikeya Dwivedi +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/btrfs-disable-bs-ps-support-if-no-transparent-hugepa.patch b/queue-6.18/btrfs-disable-bs-ps-support-if-no-transparent-hugepa.patch new file mode 100644 index 0000000000..32924215a1 --- /dev/null +++ b/queue-6.18/btrfs-disable-bs-ps-support-if-no-transparent-hugepa.patch @@ -0,0 +1,67 @@ +From 9b2b7318df597191bf84329f5e6e74a56cb73d0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 16:37:39 +0930 +Subject: btrfs: disable bs > ps support if no transparent hugepage support + +From: Qu Wenruo + +[ 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 +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch b/queue-6.18/btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch new file mode 100644 index 0000000000..eaefa74453 --- /dev/null +++ b/queue-6.18/btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch @@ -0,0 +1,96 @@ +From edcab8276b4fe316fe5c1e52c8c15ec4636fe137 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 14:53:52 +0300 +Subject: btrfs: fix memory leak in btrfs_do_encoded_write() + +From: Dmitry Antipov + +[ 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 +Signed-off-by: Dmitry Antipov +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/btrfs-move-large-data-folios-out-of-experimental-fea.patch b/queue-6.18/btrfs-move-large-data-folios-out-of-experimental-fea.patch new file mode 100644 index 0000000000..21c9a37037 --- /dev/null +++ b/queue-6.18/btrfs-move-large-data-folios-out-of-experimental-fea.patch @@ -0,0 +1,96 @@ +From edd1fee37171e82730173367ff9ae8cfc44a8296 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 10:20:25 +0930 +Subject: btrfs: move large data folios out of experimental features + +From: Qu Wenruo + +[ 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 +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Stable-dep-of: 4c375ac546ea ("btrfs: disable bs > ps support if no transparent hugepage support") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/btrfs-update-the-kconfig-string-for-config_btrfs_exp.patch b/queue-6.18/btrfs-update-the-kconfig-string-for-config_btrfs_exp.patch new file mode 100644 index 0000000000..e712867b06 --- /dev/null +++ b/queue-6.18/btrfs-update-the-kconfig-string-for-config_btrfs_exp.patch @@ -0,0 +1,46 @@ +From 712ac69e62af09ee2c9d66ae8c196713d1583fbe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 14:01:14 +1030 +Subject: btrfs: update the Kconfig string for CONFIG_BTRFS_EXPERIMENTAL + +From: Qu Wenruo + +[ 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 +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Stable-dep-of: 4c375ac546ea ("btrfs: disable bs > ps support if no transparent hugepage support") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/counter-microchip-tcb-capture-fix-dt-channel-validat.patch b/queue-6.18/counter-microchip-tcb-capture-fix-dt-channel-validat.patch new file mode 100644 index 0000000000..b6ab6ad3a0 --- /dev/null +++ b/queue-6.18/counter-microchip-tcb-capture-fix-dt-channel-validat.patch @@ -0,0 +1,70 @@ +From 4ffa634392b99b5d073f4e33073160b27cdf927b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Jul 2026 04:29:10 +0000 +Subject: counter: microchip-tcb-capture: Fix DT channel validation + +From: Babanpreet Singh + +[ 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 +Reviewed-by: Joshua Crofts +Link: https://lore.kernel.org/r/20260714042910.7-1-bbnpreetsingh@gmail.com +Signed-off-by: William Breathitt Gray +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/devlink-fix-net-namespace-reference-leak-in-reload.patch b/queue-6.18/devlink-fix-net-namespace-reference-leak-in-reload.patch new file mode 100644 index 0000000000..0a6abd98b4 --- /dev/null +++ b/queue-6.18/devlink-fix-net-namespace-reference-leak-in-reload.patch @@ -0,0 +1,42 @@ +From cc145e70baf7a1cdaf437fb3dc4a5fb51ed45e41 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 11:06:00 +0300 +Subject: devlink: fix net namespace reference leak in reload + +From: Or Har-Toov + +[ 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 +Reviewed-by: Jiri Pirko +Signed-off-by: Tariq Toukan +Reviewed-by: Antoine Tenart +Link: https://patch.msgid.link/20260729080600.2427721-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/drm-bridge-ps8640-propagate-aux-transfer-register-er.patch b/queue-6.18/drm-bridge-ps8640-propagate-aux-transfer-register-er.patch new file mode 100644 index 0000000000..69f5a7fbc2 --- /dev/null +++ b/queue-6.18/drm-bridge-ps8640-propagate-aux-transfer-register-er.patch @@ -0,0 +1,79 @@ +From e3855d2b96d64b35e4fc56c3e25f1c23738f197a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jul 2026 10:38:06 +0800 +Subject: drm/bridge: ps8640: propagate AUX transfer register errors + +From: Pengpeng Hou + +[ 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 +Reviewed-by: Douglas Anderson +Signed-off-by: Douglas Anderson +Link: https://patch.msgid.link/20260723103509.2-ps8640-v2-pengpeng@iscas.ac.cn +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/drm-xe-uc-apply-rcs-ccs-yield-policy-to-sr-iov-vfs.patch b/queue-6.18/drm-xe-uc-apply-rcs-ccs-yield-policy-to-sr-iov-vfs.patch new file mode 100644 index 0000000000..05386db4de --- /dev/null +++ b/queue-6.18/drm-xe-uc-apply-rcs-ccs-yield-policy-to-sr-iov-vfs.patch @@ -0,0 +1,63 @@ +From 1865e71f3fb4885f01ec3ba8c92281d8bde935c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Marcin Bernatowicz +Cc: Daniele Ceraolo Spurio +Cc: Michal Wajdeczko +Reviewed-by: Daniele Ceraolo Spurio +Link: https://patch.msgid.link/20260709075945.1337660-1-marcin.bernatowicz@linux.intel.com +Signed-off-by: Michał Winiarski +(cherry picked from commit f09360e857130f7ab7f069e2421e6b4a6e502531) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/enic-fix-tx_hang_reset-use-after-free-on-device-remo.patch b/queue-6.18/enic-fix-tx_hang_reset-use-after-free-on-device-remo.patch new file mode 100644 index 0000000000..5eacb19429 --- /dev/null +++ b/queue-6.18/enic-fix-tx_hang_reset-use-after-free-on-device-remo.patch @@ -0,0 +1,49 @@ +From f411b21abd65a052fdac454837fb4120d4276142 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 23:26:30 -0700 +Subject: enic: fix tx_hang_reset use-after-free on device removal + +From: Satish Kharat + +[ 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 +Link: https://patch.msgid.link/20260728062730.2394873-1-satishkh@cisco.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/eth-bnxt-store-rx-buffer-size-per-queue.patch b/queue-6.18/eth-bnxt-store-rx-buffer-size-per-queue.patch new file mode 100644 index 0000000000..c4556488ce --- /dev/null +++ b/queue-6.18/eth-bnxt-store-rx-buffer-size-per-queue.patch @@ -0,0 +1,310 @@ +From 38ccb00a12bf489e36975ecc880f154886b60d39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Apr 2025 15:28:11 -0700 +Subject: eth: bnxt: store rx buffer size per queue + +From: Pavel Begunkov + +[ 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 +Signed-off-by: Pavel Begunkov +Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/eth-bnxt-support-qcfg-provided-rx-page-size.patch b/queue-6.18/eth-bnxt-support-qcfg-provided-rx-page-size.patch new file mode 100644 index 0000000000..c60e1f284e --- /dev/null +++ b/queue-6.18/eth-bnxt-support-qcfg-provided-rx-page-size.patch @@ -0,0 +1,126 @@ +From a59a81103a6acf1ab7301d46ab0dc041cb976384 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Oct 2025 23:10:32 +0100 +Subject: eth: bnxt: support qcfg provided rx page size + +From: Pavel Begunkov + +[ 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 +Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/hwmon-ads7828-fix-external-vref-regulator-handling.patch b/queue-6.18/hwmon-ads7828-fix-external-vref-regulator-handling.patch new file mode 100644 index 0000000000..c07a4c1a7a --- /dev/null +++ b/queue-6.18/hwmon-ads7828-fix-external-vref-regulator-handling.patch @@ -0,0 +1,71 @@ +From 05573f9cac201179c53b2a5fa41a294b66a6f649 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 14:16:45 +0800 +Subject: hwmon: (ads7828) Fix external VREF regulator handling + +From: Qingshuang Fu + +[ 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 +Link: https://lore.kernel.org/r/20260805061645.1331652-1-fffsqian@163.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch b/queue-6.18/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch new file mode 100644 index 0000000000..2a8b01f9f4 --- /dev/null +++ b/queue-6.18/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch @@ -0,0 +1,50 @@ +From 8d6687b405b9c2caa6341e1dfc81bf7dc2f47e59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://lore.kernel.org/r/anLj9gPWRoRDbQBV@monster.localdomain +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/hwmon-ltc4282-avoid-overflow-in-maximum-power-calcul.patch b/queue-6.18/hwmon-ltc4282-avoid-overflow-in-maximum-power-calcul.patch new file mode 100644 index 0000000000..f318b7c14b --- /dev/null +++ b/queue-6.18/hwmon-ltc4282-avoid-overflow-in-maximum-power-calcul.patch @@ -0,0 +1,105 @@ +From 26b682eeccf8c3539e863f0ef97e32a5f01b5d10 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282") +Cc: Nuno Sa +Reviewed-by: Nuno Sá +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/hwmon-ltc4282-clamp-negative-current-limits.patch b/queue-6.18/hwmon-ltc4282-clamp-negative-current-limits.patch new file mode 100644 index 0000000000..100ccfff19 --- /dev/null +++ b/queue-6.18/hwmon-ltc4282-clamp-negative-current-limits.patch @@ -0,0 +1,69 @@ +From 448377d436425cf61b5ddbcc1d7e2823d0ec6f0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282") +Cc: Nuno Sa +Reviewed-by: Nuno Sá +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 + diff --git a/queue-6.18/hwmon-ltc4282-fix-parsing-adi-current-limit-sense-mi.patch b/queue-6.18/hwmon-ltc4282-fix-parsing-adi-current-limit-sense-mi.patch new file mode 100644 index 0000000000..263112e691 --- /dev/null +++ b/queue-6.18/hwmon-ltc4282-fix-parsing-adi-current-limit-sense-mi.patch @@ -0,0 +1,68 @@ +From 2e61ebc39d33c9c30c0e57215677414ba53634ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282") +Cc: Nuno Sa +Reviewed-by: Nuno Sá +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/hwmon-nzxt-smart2-check-return-value-of-init_device-.patch b/queue-6.18/hwmon-nzxt-smart2-check-return-value-of-init_device-.patch new file mode 100644 index 0000000000..f83800e58c --- /dev/null +++ b/queue-6.18/hwmon-nzxt-smart2-check-return-value-of-init_device-.patch @@ -0,0 +1,57 @@ +From 44b774092b414caeb155a01a7502fcf314c31595 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 15:48:42 +0800 +Subject: hwmon: (nzxt-smart2) Check return value of init_device() in probe + +From: Qingshuang Fu + +[ 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 +Link: https://lore.kernel.org/r/20260804074842.505923-1-fffsqian@163.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/hwmon-pmbus-fix-type-confusion-in-notification-logic.patch b/queue-6.18/hwmon-pmbus-fix-type-confusion-in-notification-logic.patch new file mode 100644 index 0000000000..8ce4bde537 --- /dev/null +++ b/queue-6.18/hwmon-pmbus-fix-type-confusion-in-notification-logic.patch @@ -0,0 +1,234 @@ +From be4c8782c47bbeb107212621f1f7ec2ea28590a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jul 2026 10:57:35 -0700 +Subject: hwmon: (pmbus) Fix type confusion in notification logic + +From: Guenter Roeck + +[ 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 +Tested-by: Vincent Jardin +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch b/queue-6.18/hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch new file mode 100644 index 0000000000..11f0a3e7eb --- /dev/null +++ b/queue-6.18/hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch @@ -0,0 +1,71 @@ +From 21c8dbd4d0f82468f8825dd772f74951d344f1d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 14:12:31 -0700 +Subject: hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations + +From: Guenter Roeck + +[ 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 +Fixes: 94ee5fcc240fe ("hwmon: (pmbus/lm25066) Support configurable sense resistor values") +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + #include + #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 + diff --git a/queue-6.18/hwmon-pmbus_core-use-guard-for-mutex-protection.patch b/queue-6.18/hwmon-pmbus_core-use-guard-for-mutex-protection.patch new file mode 100644 index 0000000000..0857207116 --- /dev/null +++ b/queue-6.18/hwmon-pmbus_core-use-guard-for-mutex-protection.patch @@ -0,0 +1,558 @@ +From 6aee13770ebae0710e220f91c03381d5dd5f0dbf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 07:45:55 -0700 +Subject: hwmon: (pmbus_core) Use guard() for mutex protection + +From: Guenter Roeck + +[ 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 +Signed-off-by: Guenter Roeck +Stable-dep-of: 59bd68ab05a8 ("hwmon: (pmbus) Fix type confusion in notification logic") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch b/queue-6.18/ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch new file mode 100644 index 0000000000..d9da3f8b27 --- /dev/null +++ b/queue-6.18/ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch @@ -0,0 +1,259 @@ +From 6b5a62c1854f99c5c70617574cde5b6944d75c6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 21:35:05 +0300 +Subject: ipvs: avoid out-of-bounds write in ip_vs_nat_icmp + +From: Julian Anastasov + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/ipvs-return-the-csum-validation-for-forward-hook.patch b/queue-6.18/ipvs-return-the-csum-validation-for-forward-hook.patch new file mode 100644 index 0000000000..e599a57666 --- /dev/null +++ b/queue-6.18/ipvs-return-the-csum-validation-for-forward-hook.patch @@ -0,0 +1,100 @@ +From cfce862a01d8cfd7f60dfc533eff1fa537741863 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 21:35:06 +0300 +Subject: ipvs: return the csum validation for forward hook + +From: Julian Anastasov + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 /* for union nf_inet_addr */ + #include + #include /* for struct ipv6hdr */ +-#include + #include +-#include + #if IS_ENABLED(CONFIG_NF_CONNTRACK) + #include + #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 + diff --git a/queue-6.18/net-add-bare-bone-queue-configs.patch b/queue-6.18/net-add-bare-bone-queue-configs.patch new file mode 100644 index 0000000000..c2877e3256 --- /dev/null +++ b/queue-6.18/net-add-bare-bone-queue-configs.patch @@ -0,0 +1,328 @@ +From 2c798cddd711a9895fd7c51d5dc1b86ca62f64e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 13:25:40 +0000 +Subject: net: add bare bone queue configs + +From: Pavel Begunkov + +[ 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 +Signed-off-by: Pavel Begunkov +Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases") +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + + /* 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 + diff --git a/queue-6.18/net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch b/queue-6.18/net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch new file mode 100644 index 0000000000..ce57196bca --- /dev/null +++ b/queue-6.18/net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch @@ -0,0 +1,81 @@ +From 29cdbab9bcd2e7dba7f145c95ccf34d98b3ce8f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 13:15:08 +0000 +Subject: net/atm: fix slab-out-of-bounds read in vcc_setsockopt() + +From: Eric Dumazet + +[ 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 +Link: https://patch.msgid.link/20260805131508.3227331-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch b/queue-6.18/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch new file mode 100644 index 0000000000..b8b1a7c920 --- /dev/null +++ b/queue-6.18/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch @@ -0,0 +1,42 @@ +From f85fc2f0b87800e63b00f5d0247d15aa328d45ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-hns3-fix-speed-configuration-residue-after-drive.patch b/queue-6.18/net-hns3-fix-speed-configuration-residue-after-drive.patch new file mode 100644 index 0000000000..071e42b523 --- /dev/null +++ b/queue-6.18/net-hns3-fix-speed-configuration-residue-after-drive.patch @@ -0,0 +1,76 @@ +From 14b6ecce397d8f08fa8d54bac30a5a21f0852567 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 17:30:36 +0800 +Subject: net: hns3: fix speed configuration residue after driver reload + +From: Jijie Shao + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260724093036.426631-1-shaojijie@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-mlx5-fw_tracer-return-null-on-create-error.patch b/queue-6.18/net-mlx5-fw_tracer-return-null-on-create-error.patch new file mode 100644 index 0000000000..e34c682d97 --- /dev/null +++ b/queue-6.18/net-mlx5-fw_tracer-return-null-on-create-error.patch @@ -0,0 +1,134 @@ +From c407f2d60c0f5a44fa5e60229849286d9a2f44e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 11:04:02 +0300 +Subject: net/mlx5: fw_tracer, return NULL on create error + +From: Michael Guralnik + +[ 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 +Reviewed-by: Shay Drori +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260729080402.2427184-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.18/net-mlx5e-fix-bql-reset-on-sq-re-activation.patch b/queue-6.18/net-mlx5e-fix-bql-reset-on-sq-re-activation.patch new file mode 100644 index 0000000000..4fee36f804 --- /dev/null +++ b/queue-6.18/net-mlx5e-fix-bql-reset-on-sq-re-activation.patch @@ -0,0 +1,58 @@ +From 6371349ea2dfbcc3d33de7c97292ee4e75f9ccea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 16:47:29 -0700 +Subject: net/mlx5e: fix BQL reset on SQ re-activation + +From: Bobby Eshleman + +[ 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: + + 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 +Reviewed-by: Tariq Toukan +Link: https://patch.msgid.link/20260803-mlx5-bql-v3-1-a30d4c66fe1d@meta.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch b/queue-6.18/net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch new file mode 100644 index 0000000000..b65af84059 --- /dev/null +++ b/queue-6.18/net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch @@ -0,0 +1,100 @@ +From d513e5a9d3274974e85faba87cf8adaca7eb6619 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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 + + +Fixes: 04de7dda7394 ("net/mlx5e: Infrastructure for duplicated offloading of TC flows") +Signed-off-by: Shay Drory +Reviewed-by: Cosmin Ratiu +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260728044338.2271143-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch b/queue-6.18/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch new file mode 100644 index 0000000000..0ade155b40 --- /dev/null +++ b/queue-6.18/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch @@ -0,0 +1,60 @@ +From 37898435c35b4fcd5c4eb9d33eb0d846f9476bbd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Henry Martin +Link: https://patch.msgid.link/20260803043618.3210301-1-bsdhenrymartin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-openvswitch-check-ethernet-header-length-in-key_.patch b/queue-6.18/net-openvswitch-check-ethernet-header-length-in-key_.patch new file mode 100644 index 0000000000..82eed75b60 --- /dev/null +++ b/queue-6.18/net-openvswitch-check-ethernet-header-length-in-key_.patch @@ -0,0 +1,78 @@ +From f05ba68c48e829e2d513ed9d4047af14e2f19b6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 18:20:06 -0400 +Subject: net/openvswitch: check Ethernet header length in key_extract() + +From: Cen Zhang (Microsoft) + +[ 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 +Signed-off-by: Cen Zhang (Microsoft) +Reviewed-by: Ilya Maximets +Link: https://patch.msgid.link/20260730222006.118652-1-blbllhy@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-pass-queue-rx-page-size-from-memory-provider.patch b/queue-6.18/net-pass-queue-rx-page-size-from-memory-provider.patch new file mode 100644 index 0000000000..15d1bd0533 --- /dev/null +++ b/queue-6.18/net-pass-queue-rx-page-size-from-memory-provider.patch @@ -0,0 +1,111 @@ +From 5bdf7ae5af6e7417d271955d8193c1dde850d7ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 13:25:40 +0000 +Subject: net: pass queue rx page size from memory provider + +From: Pavel Begunkov + +[ 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 +Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-prestera-validate-firmware-header-length.patch b/queue-6.18/net-prestera-validate-firmware-header-length.patch new file mode 100644 index 0000000000..bc15220102 --- /dev/null +++ b/queue-6.18/net-prestera-validate-firmware-header-length.patch @@ -0,0 +1,42 @@ +From 2ef5ff19fdf14ff7d193831ae8ca6e2d903c7b63 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 22:19:06 +0800 +Subject: net: prestera: validate firmware header length + +From: Pengpeng Hou + +[ 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 +Acked-by: Elad Nachman +Link: https://patch.msgid.link/20260731141500.1-prestera-v2-pengpeng@iscas.ac.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-reduce-indent-of-struct-netdev_queue_mgmt_ops-me.patch b/queue-6.18/net-reduce-indent-of-struct-netdev_queue_mgmt_ops-me.patch new file mode 100644 index 0000000000..b13135d456 --- /dev/null +++ b/queue-6.18/net-reduce-indent-of-struct-netdev_queue_mgmt_ops-me.patch @@ -0,0 +1,64 @@ +From 2209506efea0bd9b6b24d96a485326140d2f89f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Apr 2025 15:28:15 -0700 +Subject: net: reduce indent of struct netdev_queue_mgmt_ops members + +From: Jakub Kicinski + +[ 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 +Reviewed-by: Mina Almasry +Signed-off-by: Pavel Begunkov +Stable-dep-of: d1000fd7995e ("bnxt: fix memory leak in bnxt_queue_mem_alloc error cases") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-remove-warn_on_once-from-sk_mc_loop.patch b/queue-6.18/net-remove-warn_on_once-from-sk_mc_loop.patch new file mode 100644 index 0000000000..a7eb6d5e51 --- /dev/null +++ b/queue-6.18/net-remove-warn_on_once-from-sk_mc_loop.patch @@ -0,0 +1,45 @@ +From 2680d67ddd192bd42d887bbe837c73e558f2bb65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 15:20:48 +0000 +Subject: net: remove WARN_ON_ONCE() from sk_mc_loop() + +From: Eric Dumazet + +[ 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 +Link: https://patch.msgid.link/20260804152048.2134341-1-edumazet@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch b/queue-6.18/net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch new file mode 100644 index 0000000000..86eb383d0c --- /dev/null +++ b/queue-6.18/net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch @@ -0,0 +1,116 @@ +From 76d1acd39b44c4fa0ec75f9a04f60e933b7cdcd5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Tested-by: Victor Nogueira +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260801125632.360365-1-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch b/queue-6.18/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch new file mode 100644 index 0000000000..480d2d8dab --- /dev/null +++ b/queue-6.18/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch @@ -0,0 +1,142 @@ +From 0a82a2f52684cf16105c80364e1c48e4b891c7f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Suggested-by: Paolo Abeni +Tested-by: Victor Nogueira +Tested-by: Santosh Kalluri +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260729094411.46257-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch b/queue-6.18/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch new file mode 100644 index 0000000000..7fdaf79104 --- /dev/null +++ b/queue-6.18/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch @@ -0,0 +1,50 @@ +From e5db135a91ef6f4e032eca151060bac30fa41a77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reported-by: Ren Wei +Signed-off-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260729191417.45665-1-toke@toke.dk +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch b/queue-6.18/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch new file mode 100644 index 0000000000..16370001d1 --- /dev/null +++ b/queue-6.18/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch @@ -0,0 +1,57 @@ +From 8273786ed9a3f5ae6704d9f909ca84fb058f2c60 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Hidayath Khan +Reviewed-by: Sidraya Jayagond +Reviewed-by: Dust Li +Link: https://patch.msgid.link/20260729130153.970800-1-mjambigi@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch b/queue-6.18/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch new file mode 100644 index 0000000000..cee78c9df5 --- /dev/null +++ b/queue-6.18/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch @@ -0,0 +1,71 @@ +From 5bb2833c886f1d22a54be87ab492b935118e4dd0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Sidraya Jayagond +Reviewed-by: Breno Leitao +Reviewed-by: Dust Li +Link: https://patch.msgid.link/20260803070701.126339-1-sidraya@linux.ibm.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-stmmac-resume-phy-before-hardware-setup-when-ope.patch b/queue-6.18/net-stmmac-resume-phy-before-hardware-setup-when-ope.patch new file mode 100644 index 0000000000..a6c4dca611 --- /dev/null +++ b/queue-6.18/net-stmmac-resume-phy-before-hardware-setup-when-ope.patch @@ -0,0 +1,79 @@ +From 7fd83da1105a04ce07766dff932c16e2dfb38723 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 11:51:56 +0200 +Subject: net: stmmac: resume PHY before hardware setup when opening the + interface + +From: Stefan Agner + +[ 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 +Signed-off-by: Stefan Agner +Tested-by: Maxime Chevallier +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260803095156.132827-1-stefan@agner.ch +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch b/queue-6.18/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch new file mode 100644 index 0000000000..834c2068ee --- /dev/null +++ b/queue-6.18/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch @@ -0,0 +1,117 @@ +From 080b6c6c90917a15935d807d1a70a1f58a762a6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 14:38:50 +0000 +Subject: net: thunderbolt: Tear down DMA paths before stopping the rings + +From: Fan XinRan + +[ 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 +Acked-by: Mika Westerberg +Link: https://patch.msgid.link/20260803-b4-tbnet-teardown-v2-1-27de6a13ca2d@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/netfilter-flowtable-consolidate-xmit-path.patch b/queue-6.18/netfilter-flowtable-consolidate-xmit-path.patch new file mode 100644 index 0000000000..d2ecf5a0c6 --- /dev/null +++ b/queue-6.18/netfilter-flowtable-consolidate-xmit-path.patch @@ -0,0 +1,238 @@ +From 49a7a1d02e725ae2483dbb5b44c9741fa6d50a61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Oct 2025 12:32:35 +0200 +Subject: netfilter: flowtable: consolidate xmit path + +From: Pablo Neira Ayuso + +[ 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 +Stable-dep-of: 8aecf0bbcc72 ("netfilter: nf_flow_table: drop existing skb dst before skb_dst_set_noref()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/netfilter-ipset-switch-ext_size-to-atomic64_t.patch b/queue-6.18/netfilter-ipset-switch-ext_size-to-atomic64_t.patch new file mode 100644 index 0000000000..6216466797 --- /dev/null +++ b/queue-6.18/netfilter-ipset-switch-ext_size-to-atomic64_t.patch @@ -0,0 +1,134 @@ +From 1703eae1a67c3333688298d7f719689ee4bb5615 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 20:38:50 +0200 +Subject: netfilter: ipset: switch ext_size to atomic64_t + +From: Jozsef Kadlecsik + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/ipset/ip_set.h | 2 +- + net/netfilter/ipset/ip_set_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 + diff --git a/queue-6.18/netfilter-nf_flow_table-drop-existing-skb-dst-before.patch b/queue-6.18/netfilter-nf_flow_table-drop-existing-skb-dst-before.patch new file mode 100644 index 0000000000..293a231c7c --- /dev/null +++ b/queue-6.18/netfilter-nf_flow_table-drop-existing-skb-dst-before.patch @@ -0,0 +1,69 @@ +From dd838483a282d1c937c2b629851cef55c798ad6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Pablo Neira Ayuso +Link: https://patch.msgid.link/20260804093328.1831847-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch b/queue-6.18/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch new file mode 100644 index 0000000000..84d2ffd58e --- /dev/null +++ b/queue-6.18/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch @@ -0,0 +1,50 @@ +From f4e6e5895b5ddc83aac2cc77db7ca6a121aeaec9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Jun 2026 14:31:00 -0400 +Subject: NFS: Pin the 'struct nfs_server' during a FREE_STATEID call + +From: Anna Schumaker + +[ 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 +Fixes: 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call") +Tested-by: Dan Aloni +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/ovpn-add-missing-rtnl_link_ops-get_size-callback.patch b/queue-6.18/ovpn-add-missing-rtnl_link_ops-get_size-callback.patch new file mode 100644 index 0000000000..9fe43caf2f --- /dev/null +++ b/queue-6.18/ovpn-add-missing-rtnl_link_ops-get_size-callback.patch @@ -0,0 +1,56 @@ +From 622571253e3085f96653236b4deda54a6021afa3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 15:41:30 +0200 +Subject: ovpn: add missing rtnl_link_ops->get_size callback + +From: Ralf Lici + +[ 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 +Signed-off-by: Antonio Quartulli +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/ovpn-disable-ipv4-redirects-on-mp-interfaces.patch b/queue-6.18/ovpn-disable-ipv4-redirects-on-mp-interfaces.patch new file mode 100644 index 0000000000..94ea64b222 --- /dev/null +++ b/queue-6.18/ovpn-disable-ipv4-redirects-on-mp-interfaces.patch @@ -0,0 +1,130 @@ +From 40440ca620174039934fd3f69fe7a114c3dd1eb5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 13:48:53 +0200 +Subject: ovpn: disable IPv4 redirects on MP interfaces + +From: Antonio Quartulli + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/ovpn-ensure-socket-is-owned-by-ovpn-before-deref-sk_.patch b/queue-6.18/ovpn-ensure-socket-is-owned-by-ovpn-before-deref-sk_.patch new file mode 100644 index 0000000000..1b07c94852 --- /dev/null +++ b/queue-6.18/ovpn-ensure-socket-is-owned-by-ovpn-before-deref-sk_.patch @@ -0,0 +1,47 @@ +From 55a8eeb38f781ff5af3f719d22ba85bbde7c319a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/ovpn-ensure-tcp-vars-are-initialized-first.patch b/queue-6.18/ovpn-ensure-tcp-vars-are-initialized-first.patch new file mode 100644 index 0000000000..5084979d65 --- /dev/null +++ b/queue-6.18/ovpn-ensure-tcp-vars-are-initialized-first.patch @@ -0,0 +1,52 @@ +From cb8b183eea118ea7e7e5625f3f7d92c351d70752 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 13:48:54 +0200 +Subject: ovpn: ensure TCP vars are initialized first + +From: Antonio Quartulli + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/ovpn-fix-incorrect-use-of-rcu_access_pointer.patch b/queue-6.18/ovpn-fix-incorrect-use-of-rcu_access_pointer.patch new file mode 100644 index 0000000000..08ed6f7627 --- /dev/null +++ b/queue-6.18/ovpn-fix-incorrect-use-of-rcu_access_pointer.patch @@ -0,0 +1,37 @@ +From 445050eef4ddad043b32be7ca30bcbd1688c505c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 09:49:26 +0800 +Subject: ovpn: fix incorrect use of rcu_access_pointer() + +From: Qingfang Deng + +[ 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 +Signed-off-by: Antonio Quartulli +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/ovpn-hash-floated-peer-by-transport-identity-only.patch b/queue-6.18/ovpn-hash-floated-peer-by-transport-identity-only.patch new file mode 100644 index 0000000000..a63ca16129 --- /dev/null +++ b/queue-6.18/ovpn-hash-floated-peer-by-transport-identity-only.patch @@ -0,0 +1,94 @@ +From 4bacaecf06b752798d5539ab1e7381b58adf4533 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 13:48:52 +0200 +Subject: ovpn: hash floated peer by transport identity only + +From: Antonio Quartulli + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/ovpn-rehash-peer-in-by_transp_addr-table-on-cmd_peer.patch b/queue-6.18/ovpn-rehash-peer-in-by_transp_addr-table-on-cmd_peer.patch new file mode 100644 index 0000000000..185bf107a4 --- /dev/null +++ b/queue-6.18/ovpn-rehash-peer-in-by_transp_addr-table-on-cmd_peer.patch @@ -0,0 +1,215 @@ +From f878351bc1bb8901897a14ba0aa7b2797d92d1ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/ovpn-skip-rehash-for-peers-already-removed-from-by_i.patch b/queue-6.18/ovpn-skip-rehash-for-peers-already-removed-from-by_i.patch new file mode 100644 index 0000000000..513290a2d8 --- /dev/null +++ b/queue-6.18/ovpn-skip-rehash-for-peers-already-removed-from-by_i.patch @@ -0,0 +1,142 @@ +From 0eb6a27c132eb080761d78d1fc3fc3e5f0fc8c30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 13:48:47 +0200 +Subject: ovpn: skip rehash for peers already removed from by_id + +From: Antonio Quartulli + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/ovpn-zero-initialize-sockaddr-before-learning-a-floa.patch b/queue-6.18/ovpn-zero-initialize-sockaddr-before-learning-a-floa.patch new file mode 100644 index 0000000000..ac4e70df24 --- /dev/null +++ b/queue-6.18/ovpn-zero-initialize-sockaddr-before-learning-a-floa.patch @@ -0,0 +1,91 @@ +From b86375bc7a97bb870b966e1d260187ea400e9af3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 13:48:51 +0200 +Subject: ovpn: zero-initialize sockaddr before learning a floated endpoint + +From: Antonio Quartulli + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/pds_core-cancel-pending-pci-reset-work-on-aer-recove.patch b/queue-6.18/pds_core-cancel-pending-pci-reset-work-on-aer-recove.patch new file mode 100644 index 0000000000..21ee2c3bc0 --- /dev/null +++ b/queue-6.18/pds_core-cancel-pending-pci-reset-work-on-aer-recove.patch @@ -0,0 +1,54 @@ +From 884aa49e157bf14ac7f79502cbf920348b8041ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 17:00:30 +0000 +Subject: pds_core: cancel pending PCI reset work on AER recovery + +From: Nikhil P. Rao + +[ 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 +Closes: https://sashiko.dev/#/patchset/20260714180223.1642792-2-nikhil.rao%40amd.com?part=1 +Signed-off-by: Nikhil P. Rao +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260727170030.361116-1-nikhil.rao@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/pds_core-keep-the-health-thread-stopped-during-reset.patch b/queue-6.18/pds_core-keep-the-health-thread-stopped-during-reset.patch new file mode 100644 index 0000000000..c7dd6ae373 --- /dev/null +++ b/queue-6.18/pds_core-keep-the-health-thread-stopped-during-reset.patch @@ -0,0 +1,87 @@ +From 1db3da527cdd7c78345e3f374a490511bed9a356 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 16:45:48 +0000 +Subject: pds_core: keep the health thread stopped during reset + +From: Nikhil P. Rao + +[ 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 +Closes: https://sashiko.dev/#/patchset/20260629200358.2626129-1-nikhil.rao%40amd.com?part=2 +Signed-off-by: Nikhil P. Rao +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260727164548.359562-1-nikhil.rao@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/pinctrl-qcom-ipq806x-mark-gpio-as-a-gpio-pin-functio.patch b/queue-6.18/pinctrl-qcom-ipq806x-mark-gpio-as-a-gpio-pin-functio.patch new file mode 100644 index 0000000000..e59de02b80 --- /dev/null +++ b/queue-6.18/pinctrl-qcom-ipq806x-mark-gpio-as-a-gpio-pin-functio.patch @@ -0,0 +1,65 @@ +From 50f1d566604c4da03cf2f95dbd7abdce9bc428a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Jul 2026 15:35:59 +0200 +Subject: pinctrl: qcom: ipq806x: mark gpio as a GPIO pin function + +From: Hans Ulli Kroll + +[ 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 +Acked-by: Linus Walleij +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260719134548.8830-2-linux@ulli-kroll.de +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/pinctrl-qcom-ipq806x-mark-pci-reset-as-a-gpio-pin-fu.patch b/queue-6.18/pinctrl-qcom-ipq806x-mark-pci-reset-as-a-gpio-pin-fu.patch new file mode 100644 index 0000000000..644ce7b43a --- /dev/null +++ b/queue-6.18/pinctrl-qcom-ipq806x-mark-pci-reset-as-a-gpio-pin-fu.patch @@ -0,0 +1,59 @@ +From eced0e0c1d916d59fe09ecfe4ef2c394ec6d0fdc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Acked-by: Linus Walleij +Reviewed-by: Dmitry Baryshkov +Link: https://patch.msgid.link/20260719134548.8830-3-linux@ulli-kroll.de +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/revert-net-thunderbolt-enable-end-to-end-flow-contro.patch b/queue-6.18/revert-net-thunderbolt-enable-end-to-end-flow-contro.patch new file mode 100644 index 0000000000..e370ec1f16 --- /dev/null +++ b/queue-6.18/revert-net-thunderbolt-enable-end-to-end-flow-contro.patch @@ -0,0 +1,104 @@ +From 66615729bc455a5c238a8a00bc2e94161aced88d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Fan Ye +Acked-by: Mika Westerberg +Link: https://patch.msgid.link/20260727123002.25225-1-fy15309206903@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/s390-ism-fix-uaf-of-sba-and-ieq-during-ism_dev_exit.patch b/queue-6.18/s390-ism-fix-uaf-of-sba-and-ieq-during-ism_dev_exit.patch new file mode 100644 index 0000000000..c03ac0ac4b --- /dev/null +++ b/queue-6.18/s390-ism-fix-uaf-of-sba-and-ieq-during-ism_dev_exit.patch @@ -0,0 +1,91 @@ +From c700d726caf538a73ac46a4f5177250ce019fa6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/20260805131043.954639-1-wintera@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/sctp-clear-control-chunk-transport-if-it-is-being-re.patch b/queue-6.18/sctp-clear-control-chunk-transport-if-it-is-being-re.patch new file mode 100644 index 0000000000..7c51079f9b --- /dev/null +++ b/queue-6.18/sctp-clear-control-chunk-transport-if-it-is-being-re.patch @@ -0,0 +1,54 @@ +From 00537ea419ca796773b9ca4883ed23d9e095f27b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 11:18:40 -0400 +Subject: sctp: clear control chunk transport if it is being removed + +From: Xin Long + +[ 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 +Signed-off-by: Xin Long +Link: https://patch.msgid.link/7e1168cb722132152a29d47e5eafaeac4a3bf6f3.1785943120.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch b/queue-6.18/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch new file mode 100644 index 0000000000..132801fd2e --- /dev/null +++ b/queue-6.18/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch @@ -0,0 +1,57 @@ +From a676a8861312848d181a8f11f169642523a26535 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 10:55:14 +0800 +Subject: sctp: fix addip_serial increment on ASCONF_ACK allocation failure + +From: Qing Luo + +[ 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 +Acked-by: Xin Long +Link: https://patch.msgid.link/20260804025514.241767-1-l1138897701@163.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch b/queue-6.18/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch new file mode 100644 index 0000000000..21b4130c32 --- /dev/null +++ b/queue-6.18/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch @@ -0,0 +1,88 @@ +From 277b423d991c08381f4f213fdda7662f33e38c16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 21:46:35 +0200 +Subject: selftests/ftrace: refactor eprobes test to fix argument checks + +From: Martin Kaiser + +[ 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 " 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 +Closes: https://lore.kernel.org/oe-lkp/202607151010.b68428e1-lkp@intel.com +Signed-off-by: Martin Kaiser +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + .../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 ". []":README ++# requires: dynamic_events events/syscalls/sys_enter_chdir ". []":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 + diff --git a/queue-6.18/selftests-sched_ext-handle-sleeping-task-affinity-ch.patch b/queue-6.18/selftests-sched_ext-handle-sleeping-task-affinity-ch.patch new file mode 100644 index 0000000000..fa3a99a882 --- /dev/null +++ b/queue-6.18/selftests-sched_ext-handle-sleeping-task-affinity-ch.patch @@ -0,0 +1,81 @@ +From f568f0154a0abdf922768ea44088083cb82f6ef9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jul 2026 09:59:55 +0000 +Subject: selftests/sched_ext: Handle sleeping task affinity changes in numa + test + +From: Kuba Piecuch + +[ 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 +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/series b/queue-6.18/series index 8b6e6d52cf..a8dda1b00f 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -5,3 +5,108 @@ selftests-bpf-fail-unbound-udp-on-sockmap-update.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 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 diff --git a/queue-6.18/tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch b/queue-6.18/tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch new file mode 100644 index 0000000000..da98585758 --- /dev/null +++ b/queue-6.18/tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch @@ -0,0 +1,61 @@ +From 96a6f0678c70b43bf0fa845a1f0d2f8ad095406e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 20:08:06 -0700 +Subject: tcp: do not change rcv_ssthresh in tcp_measure_rcv_mss() + +From: Nathan Gao + +[ 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 +Link: https://patch.msgid.link/20260725030806.28135-1-zcgao@amazon.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch b/queue-6.18/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch new file mode 100644 index 0000000000..fdccdbab58 --- /dev/null +++ b/queue-6.18/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch @@ -0,0 +1,72 @@ +From 7e86e9b8110ceababbb04802bcc19451390ca755 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 14:17:38 +0800 +Subject: tcp: fix TFO max_qlen accounting across reuseport migration + +From: Jiayuan Chen + +[ 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 +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260803061739.134737-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/tls-don-t-abort-the-connection-on-signal-interrupted.patch b/queue-6.18/tls-don-t-abort-the-connection-on-signal-interrupted.patch new file mode 100644 index 0000000000..1bcb7a8f59 --- /dev/null +++ b/queue-6.18/tls-don-t-abort-the-connection-on-signal-interrupted.patch @@ -0,0 +1,45 @@ +From b75da59a45af8c4dc2ffcfbe98aa66511fde66c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 08:22:48 +0200 +Subject: tls: don't abort the connection on signal-interrupted sends + +From: Maximilian Immanuel Brandtner + +[ 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 +Link: https://patch.msgid.link/20260805063109.1772314-1-maxbr@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch b/queue-6.18/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch new file mode 100644 index 0000000000..955d9056ad --- /dev/null +++ b/queue-6.18/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch @@ -0,0 +1,53 @@ +From 1c1642d941c8de9becfd7650f85cd40847ebee29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 17:35:54 +0800 +Subject: udp: fix potential use-after-free in tunnel segmentation + +From: Xuanqiang Luo + +[ 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 +Reviewed-by: Antoine Tenart +Link: https://patch.msgid.link/20260730093554.68127-1-xuanqiang.luo@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/vdpa-mlx5-fix-buffer-length-in-create_direct_keys.patch b/queue-6.18/vdpa-mlx5-fix-buffer-length-in-create_direct_keys.patch new file mode 100644 index 0000000000..0165ca380e --- /dev/null +++ b/queue-6.18/vdpa-mlx5-fix-buffer-length-in-create_direct_keys.patch @@ -0,0 +1,61 @@ +From 27b0de378d91ed8119b23b8c4d238ccc68d973a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Jul 2026 16:15:37 +0200 +Subject: vdpa/mlx5: Fix buffer length in create_direct_keys() + +From: Christian Borntraeger + +[ 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 +Tested-by: Dragos Tatulea +Reviewed-by: Dragos Tatulea +Signed-off-by: Michael S. Tsirkin +Message-ID: <20260706141537.3510294-1-borntraeger@linux.ibm.com> +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/vhost-scsi-reject-feature-changes-after-endpoint.patch b/queue-6.18/vhost-scsi-reject-feature-changes-after-endpoint.patch new file mode 100644 index 0000000000..ab41f51332 --- /dev/null +++ b/queue-6.18/vhost-scsi-reject-feature-changes-after-endpoint.patch @@ -0,0 +1,102 @@ +From a3a430f3c447e06a0c139c2ebe5c66e1dbd71b35 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Jul 2026 22:43:14 +0800 +Subject: vhost-scsi: reject feature changes after endpoint + +From: Jia Jia + +[ 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: + + ? __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 + + + 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 +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Michael S. Tsirkin +Message-ID: <20260726144314.1652934-1-physicalmtea@gmail.com> +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/vhost-scsi-validate-t10-pi-scatterlist-counts.patch b/queue-6.18/vhost-scsi-validate-t10-pi-scatterlist-counts.patch new file mode 100644 index 0000000000..ec270e5fe7 --- /dev/null +++ b/queue-6.18/vhost-scsi-validate-t10-pi-scatterlist-counts.patch @@ -0,0 +1,63 @@ +From de1ecc4d02139e98f84174a4139e1997337d605c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 16:18:41 +0800 +Subject: vhost-scsi: Validate T10 PI scatterlist counts + +From: Linfeng Sun + +[ 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 +Signed-off-by: Jia Jia +Assisted-by: OpenAI-Codex:GPT-5 +Signed-off-by: Linfeng Sun +Message-ID: <20260727081841.923151-1-slf@hdu.edu.cn> +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch b/queue-6.18/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch new file mode 100644 index 0000000000..910b20f849 --- /dev/null +++ b/queue-6.18/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch @@ -0,0 +1,56 @@ +From ac480eb9d1cc42e8a00eb58acd9b0e7df24e0e8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 15:02:02 -0700 +Subject: vhost/vdpa: reject overflowing PA map page counts on 32-bit + +From: Yousef Alhouseen + +[ 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 +Signed-off-by: Yousef Alhouseen +Signed-off-by: Michael S. Tsirkin +Message-ID: +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/watchdog-at91sam9_wdt-prevent-timer-rearm-during-tea.patch b/queue-6.18/watchdog-at91sam9_wdt-prevent-timer-rearm-during-tea.patch new file mode 100644 index 0000000000..4095fcb6b6 --- /dev/null +++ b/queue-6.18/watchdog-at91sam9_wdt-prevent-timer-rearm-during-tea.patch @@ -0,0 +1,51 @@ +From 91152754adf84a760e52e3146a7b1c425ce9c7d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Aug 2026 14:06:13 +0800 +Subject: watchdog: at91sam9_wdt: prevent timer rearm during teardown + +From: Hongyan Xu + +[ 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 +Link: https://lore.kernel.org/r/20260806060613.1830-1-getshell@seu.edu.cn +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/watchdog-bd96801_wdt-fix-timeout-for-enabled-wdg.patch b/queue-6.18/watchdog-bd96801_wdt-fix-timeout-for-enabled-wdg.patch new file mode 100644 index 0000000000..19e8e058f8 --- /dev/null +++ b/queue-6.18/watchdog-bd96801_wdt-fix-timeout-for-enabled-wdg.patch @@ -0,0 +1,68 @@ +From e15d0c58114a685cc347911a36b06033976ddfe5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:36:28 +0300 +Subject: watchdog: bd96801_wdt: Fix timeout for enabled WDG + +From: Matti Vaittinen + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/xfs-handle-null-b_addr-in-xfs_buf_free.patch b/queue-6.18/xfs-handle-null-b_addr-in-xfs_buf_free.patch new file mode 100644 index 0000000000..b72b681431 --- /dev/null +++ b/queue-6.18/xfs-handle-null-b_addr-in-xfs_buf_free.patch @@ -0,0 +1,53 @@ +From dfde8f3107af91bc697d1bb1ad7ffc7e3fd31309 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Jul 2026 23:11:24 +0800 +Subject: xfs: handle NULL b_addr in xfs_buf_free + +From: Yun Zhou + +[ 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 +Reviewed-by: Christoph Hellwig +Signed-off-by: Carlos Maiolino +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/xsk-clear-metadata-pointer-when-no-timestamp-is-requ.patch b/queue-6.18/xsk-clear-metadata-pointer-when-no-timestamp-is-requ.patch new file mode 100644 index 0000000000..c48a8bd4b7 --- /dev/null +++ b/queue-6.18/xsk-clear-metadata-pointer-when-no-timestamp-is-requ.patch @@ -0,0 +1,88 @@ +From a41dd9dbb3f50c2e46cd72c66491ba36c3179b14 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 09:19:56 -0700 +Subject: xsk: clear metadata pointer when no timestamp is requested + +From: Stanislav Fomichev + +[ 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) +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20260727161959.885642-4-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/xsk-move-xsk_tx_metadata_request-to-xdp_sock_drv.h.patch b/queue-6.18/xsk-move-xsk_tx_metadata_request-to-xdp_sock_drv.h.patch new file mode 100644 index 0000000000..c683cf76e6 --- /dev/null +++ b/queue-6.18/xsk-move-xsk_tx_metadata_request-to-xdp_sock_drv.h.patch @@ -0,0 +1,150 @@ +From abcfa6d57a0bacd1d65dd67279105ab9cae86a0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 09:19:58 -0700 +Subject: xsk: move xsk_tx_metadata_request() to xdp_sock_drv.h + +From: Stanislav Fomichev + +[ 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) +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20260727161959.885642-6-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/xsk-pass-tx-metadata-pointer-by-reference.patch b/queue-6.18/xsk-pass-tx-metadata-pointer-by-reference.patch new file mode 100644 index 0000000000..274aad9477 --- /dev/null +++ b/queue-6.18/xsk-pass-tx-metadata-pointer-by-reference.patch @@ -0,0 +1,203 @@ +From 4ef0c56635e67b82407fc88eb2f91af4381ae332 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 09:19:55 -0700 +Subject: xsk: pass TX metadata pointer by reference + +From: Stanislav Fomichev + +[ 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) +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20260727161959.885642-3-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/xsk-require-at-least-16-bytes-of-tx-metadata.patch b/queue-6.18/xsk-require-at-least-16-bytes-of-tx-metadata.patch new file mode 100644 index 0000000000..d0d27b03e0 --- /dev/null +++ b/queue-6.18/xsk-require-at-least-16-bytes-of-tx-metadata.patch @@ -0,0 +1,45 @@ +From 2a16becdb05a95ddae2dd899f162164424231361 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 09:19:54 -0700 +Subject: xsk: require at least 16 bytes of TX metadata + +From: Stanislav Fomichev + +[ 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) +Link: https://lore.kernel.org/netdev/20260720155210.34229-1-blbllhy@gmail.com/ +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20260727161959.885642-2-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/xsk-validate-launch-time-metadata-size.patch b/queue-6.18/xsk-validate-launch-time-metadata-size.patch new file mode 100644 index 0000000000..850dae8b16 --- /dev/null +++ b/queue-6.18/xsk-validate-launch-time-metadata-size.patch @@ -0,0 +1,117 @@ +From cfd011a88a3249cdfe4769db8f037c6d218dddb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 09:19:57 -0700 +Subject: xsk: validate launch-time metadata size + +From: Stanislav Fomichev + +[ 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) +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20260727161959.885642-5-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/xsk-validate-metadata-when-processing-requests.patch b/queue-6.18/xsk-validate-metadata-when-processing-requests.patch new file mode 100644 index 0000000000..2b90377ca7 --- /dev/null +++ b/queue-6.18/xsk-validate-metadata-when-processing-requests.patch @@ -0,0 +1,224 @@ +From 5afc7703d0517d79788630ecac877e73a2eed699 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 09:19:59 -0700 +Subject: xsk: validate metadata when processing requests + +From: Stanislav Fomichev + +[ 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) +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20260727161959.885642-7-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch b/queue-6.6/arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch new file mode 100644 index 0000000000..6906abf959 --- /dev/null +++ b/queue-6.6/arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch @@ -0,0 +1,39 @@ +From 4c5e419746faf443d57a8f7d942011207af9192f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Jul 2026 14:57:22 -0700 +Subject: ARM: dts: BCM5301X: fix PCIe controller 2 second interrupt + +From: Rosen Penev + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch b/queue-6.6/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch new file mode 100644 index 0000000000..a5cb851f0b --- /dev/null +++ b/queue-6.6/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch @@ -0,0 +1,50 @@ +From 164e8b22112f23dc119a8f72ab3bee69b2146793 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 24 May 2026 23:38:46 -0400 +Subject: ARM: npcm: Fix OF node refcount leaks in SMP setup + +From: Yuho Choi + +[ 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 +Reviewed-by: Avi Fishman +Signed-off-by: Andrew Jeffery +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/arm64-dts-qcom-sdm850-lenovo-yoga-c630-lower-psci-cl.patch b/queue-6.6/arm64-dts-qcom-sdm850-lenovo-yoga-c630-lower-psci-cl.patch new file mode 100644 index 0000000000..d856ef0ec1 --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sdm850-lenovo-yoga-c630-lower-psci-cl.patch @@ -0,0 +1,45 @@ +From 32fe4d76959b548d832f3ad3415a25a4040de6f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 01:27:12 +0300 +Subject: arm64: dts: qcom: sdm850-lenovo-yoga-c630: lower PSCI cluster idle + +From: Dmitry Baryshkov + +[ 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 +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260429-c630-fix-idle-v2-1-ac867dad6f21@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + 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 = , + , +-- +2.53.0 + diff --git a/queue-6.6/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch b/queue-6.6/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch new file mode 100644 index 0000000000..11d73d14a2 --- /dev/null +++ b/queue-6.6/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch @@ -0,0 +1,52 @@ +From d767bb78e56f0355095f01e8e284faa41c5bb594 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Aug 2026 14:06:28 +0800 +Subject: ata: pata_sl82c105: fix bridge revision use-after-free + +From: Hongyan Xu + +[ 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 +Reviewed-by: Niklas Cassel +Signed-off-by: Damien Le Moal +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch b/queue-6.6/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch new file mode 100644 index 0000000000..cf955ca4b5 --- /dev/null +++ b/queue-6.6/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch @@ -0,0 +1,57 @@ +From 68ad54d85e8926aed69e357bbdf3610c452e17ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Kalesh AP +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-5-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch b/queue-6.6/bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch new file mode 100644 index 0000000000..49f63037f1 --- /dev/null +++ b/queue-6.6/bnxt_en-do-not-set-eop-on-rx-agg-bds-on-5760x-chips.patch @@ -0,0 +1,66 @@ +From 736828f51287f39241f06aaa0f3119db678b4b38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Somnath Kotur +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20251126215648.1885936-6-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: c3faf548a00f ("bnxt_en: Disable EOP for TPA on all chips to prevent data corruption") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bnxt_en-fix-ptp-pps-setting-bug.patch b/queue-6.6/bnxt_en-fix-ptp-pps-setting-bug.patch new file mode 100644 index 0000000000..bf85d95aab --- /dev/null +++ b/queue-6.6/bnxt_en-fix-ptp-pps-setting-bug.patch @@ -0,0 +1,54 @@ +From 76a14183e5bc55749810fc18628fa351f389d6fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:09:37 -0700 +Subject: bnxt_en: Fix PTP PPS setting bug + +From: Keegan Freyhof + +[ 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 +Signed-off-by: Keegan Freyhof +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-6-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch b/queue-6.6/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch new file mode 100644 index 0000000000..a8b33ef649 --- /dev/null +++ b/queue-6.6/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch @@ -0,0 +1,80 @@ +From c802dc61a0ad5325870acce50d36621ae334c949 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) + +[ 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) +Reviewed-by: Nikolay Aleksandrov +Acked-by: Jay Vosburgh +Link: https://patch.msgid.link/20260725233930.2957317-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bpf-preserve-pointer-state-for-commuted-arithmetic.patch b/queue-6.6/bpf-preserve-pointer-state-for-commuted-arithmetic.patch new file mode 100644 index 0000000000..4262284388 --- /dev/null +++ b/queue-6.6/bpf-preserve-pointer-state-for-commuted-arithmetic.patch @@ -0,0 +1,74 @@ +From 9e2aa98c292385d44b63b7726c7846dc17e68711 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 15:18:28 +0000 +Subject: bpf: Preserve pointer state for commuted arithmetic + +From: Yiyang Chen + +[ 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 +Tested-by: Daniel Wade +Acked-by: Shung-Hsi Yu +Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-2-8ee297e2346b@mails.tsinghua.edu.cn +Signed-off-by: Eduard Zingerman +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bpf-tcp-avoid-socket-skips-and-repeats-during-iterat.patch b/queue-6.6/bpf-tcp-avoid-socket-skips-and-repeats-during-iterat.patch new file mode 100644 index 0000000000..edad122222 --- /dev/null +++ b/queue-6.6/bpf-tcp-avoid-socket-skips-and-repeats-during-iterat.patch @@ -0,0 +1,240 @@ +From 0b22bcc51249d8fb83ee576a96ba6207e24619c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Jul 2025 11:09:09 -0700 +Subject: bpf: tcp: Avoid socket skips and repeats during iteration + +From: Jordan Rife + +[ 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 +Signed-off-by: Martin KaFai Lau +Acked-by: Stanislav Fomichev +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + + #include + #include +@@ -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 + diff --git a/queue-6.6/bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch b/queue-6.6/bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch new file mode 100644 index 0000000000..41dcb58014 --- /dev/null +++ b/queue-6.6/bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch @@ -0,0 +1,170 @@ +From 3d3c1423b616a0f7bd12a3f22bfb30af61e0b028 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) + +[ 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) +Reviewed-by: Kuniyuki Iwashima +Link: https://lore.kernel.org/bpf/20260730-bpf-iter-tcp-refcnt-v3-1-754b9c8a6717@linux.dev +Signed-off-by: Kumar Kartikeya Dwivedi +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bpf-tcp-get-rid-of-st_bucket_done.patch b/queue-6.6/bpf-tcp-get-rid-of-st_bucket_done.patch new file mode 100644 index 0000000000..6c52b3815d --- /dev/null +++ b/queue-6.6/bpf-tcp-get-rid-of-st_bucket_done.patch @@ -0,0 +1,82 @@ +From 2f088a79af1ab9b612219e74a6b3453d8e71ec3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Jul 2025 11:09:07 -0700 +Subject: bpf: tcp: Get rid of st_bucket_done + +From: Jordan Rife + +[ 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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Acked-by: Stanislav Fomichev +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bpf-tcp-make-mem-flags-configurable-through-bpf_iter.patch b/queue-6.6/bpf-tcp-make-mem-flags-configurable-through-bpf_iter.patch new file mode 100644 index 0000000000..88c9021e60 --- /dev/null +++ b/queue-6.6/bpf-tcp-make-mem-flags-configurable-through-bpf_iter.patch @@ -0,0 +1,64 @@ +From d92dd047190ae8e558cd84d7836e5352bebb3da0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Acked-by: Stanislav Fomichev +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bpf-tcp-make-sure-iter-batch-always-contains-a-full-.patch b/queue-6.6/bpf-tcp-make-sure-iter-batch-always-contains-a-full-.patch new file mode 100644 index 0000000000..c6b7749b38 --- /dev/null +++ b/queue-6.6/bpf-tcp-make-sure-iter-batch-always-contains-a-full-.patch @@ -0,0 +1,257 @@ +From b714bf7dc84a132dad0ed1c4341ca76bdb6436e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Acked-by: Stanislav Fomichev +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bpf-tcp-use-bpf_tcp_iter_batch_item-for-bpf_tcp_iter.patch b/queue-6.6/bpf-tcp-use-bpf_tcp_iter_batch_item-for-bpf_tcp_iter.patch new file mode 100644 index 0000000000..f0044bf56b --- /dev/null +++ b/queue-6.6/bpf-tcp-use-bpf_tcp_iter_batch_item-for-bpf_tcp_iter.patch @@ -0,0 +1,124 @@ +From 63374aa7d62904b8b764d2ab6ca4851df4b2e69a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Acked-by: Stanislav Fomichev +Stable-dep-of: e5fd3f514e27 ("bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch b/queue-6.6/btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch new file mode 100644 index 0000000000..070fcfd6c1 --- /dev/null +++ b/queue-6.6/btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch @@ -0,0 +1,96 @@ +From c3fa879a175b1840b27fee7750f538d9a4accd97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 14:53:52 +0300 +Subject: btrfs: fix memory leak in btrfs_do_encoded_write() + +From: Dmitry Antipov + +[ 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 +Signed-off-by: Dmitry Antipov +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/counter-microchip-tcb-capture-fix-dt-channel-validat.patch b/queue-6.6/counter-microchip-tcb-capture-fix-dt-channel-validat.patch new file mode 100644 index 0000000000..87406582ae --- /dev/null +++ b/queue-6.6/counter-microchip-tcb-capture-fix-dt-channel-validat.patch @@ -0,0 +1,70 @@ +From 51898a436ab6cf9ba19ddda9629df0d74d5ec913 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Jul 2026 04:29:10 +0000 +Subject: counter: microchip-tcb-capture: Fix DT channel validation + +From: Babanpreet Singh + +[ 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 +Reviewed-by: Joshua Crofts +Link: https://lore.kernel.org/r/20260714042910.7-1-bbnpreetsingh@gmail.com +Signed-off-by: William Breathitt Gray +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/devlink-fix-net-namespace-reference-leak-in-reload.patch b/queue-6.6/devlink-fix-net-namespace-reference-leak-in-reload.patch new file mode 100644 index 0000000000..60baf7e1a5 --- /dev/null +++ b/queue-6.6/devlink-fix-net-namespace-reference-leak-in-reload.patch @@ -0,0 +1,42 @@ +From 2eff8e639193246e92867212442c17878c78fc13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 11:06:00 +0300 +Subject: devlink: fix net namespace reference leak in reload + +From: Or Har-Toov + +[ 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 +Reviewed-by: Jiri Pirko +Signed-off-by: Tariq Toukan +Reviewed-by: Antoine Tenart +Link: https://patch.msgid.link/20260729080600.2427721-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/drm-bridge-ps8640-propagate-aux-transfer-register-er.patch b/queue-6.6/drm-bridge-ps8640-propagate-aux-transfer-register-er.patch new file mode 100644 index 0000000000..165f5327b2 --- /dev/null +++ b/queue-6.6/drm-bridge-ps8640-propagate-aux-transfer-register-er.patch @@ -0,0 +1,79 @@ +From 5ef9c8edfca2171a6af04795098a2e9006e3622b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jul 2026 10:38:06 +0800 +Subject: drm/bridge: ps8640: propagate AUX transfer register errors + +From: Pengpeng Hou + +[ 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 +Reviewed-by: Douglas Anderson +Signed-off-by: Douglas Anderson +Link: https://patch.msgid.link/20260723103509.2-ps8640-v2-pengpeng@iscas.ac.cn +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/hwmon-ads7828-fix-external-vref-regulator-handling.patch b/queue-6.6/hwmon-ads7828-fix-external-vref-regulator-handling.patch new file mode 100644 index 0000000000..7e038781e6 --- /dev/null +++ b/queue-6.6/hwmon-ads7828-fix-external-vref-regulator-handling.patch @@ -0,0 +1,71 @@ +From 5d033fcd110374088eeeb3fcbc4b1dfbaf9b513f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 14:16:45 +0800 +Subject: hwmon: (ads7828) Fix external VREF regulator handling + +From: Qingshuang Fu + +[ 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 +Link: https://lore.kernel.org/r/20260805061645.1331652-1-fffsqian@163.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch b/queue-6.6/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch new file mode 100644 index 0000000000..3347da145a --- /dev/null +++ b/queue-6.6/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch @@ -0,0 +1,50 @@ +From 5424e4121c1d38280f8b0800cde1bad04dedb30d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://lore.kernel.org/r/anLj9gPWRoRDbQBV@monster.localdomain +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/hwmon-lm25066-use-i2c_get_match_data.patch b/queue-6.6/hwmon-lm25066-use-i2c_get_match_data.patch new file mode 100644 index 0000000000..b6f5dc941b --- /dev/null +++ b/queue-6.6/hwmon-lm25066-use-i2c_get_match_data.patch @@ -0,0 +1,71 @@ +From 69369d1e3a5e2d2a3799d97ea3b33fee5757e0df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Nov 2023 14:57:02 -0600 +Subject: hwmon: (lm25066) Use i2c_get_match_data() + +From: Rob Herring + +[ 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 +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 +Stable-dep-of: 0dabe8a56f77 ("hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations") +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include ++#include + #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 + diff --git a/queue-6.6/hwmon-nzxt-smart2-check-return-value-of-init_device-.patch b/queue-6.6/hwmon-nzxt-smart2-check-return-value-of-init_device-.patch new file mode 100644 index 0000000000..ebd09b5fcf --- /dev/null +++ b/queue-6.6/hwmon-nzxt-smart2-check-return-value-of-init_device-.patch @@ -0,0 +1,57 @@ +From 0bd3bc90edec78af41cfba197a5b49b646c8366d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 15:48:42 +0800 +Subject: hwmon: (nzxt-smart2) Check return value of init_device() in probe + +From: Qingshuang Fu + +[ 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 +Link: https://lore.kernel.org/r/20260804074842.505923-1-fffsqian@163.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch b/queue-6.6/hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch new file mode 100644 index 0000000000..3fecba02c4 --- /dev/null +++ b/queue-6.6/hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch @@ -0,0 +1,71 @@ +From d9116982a429a72f0adbe1fe596b56a601467165 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 14:12:31 -0700 +Subject: hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations + +From: Guenter Roeck + +[ 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 +Fixes: 94ee5fcc240fe ("hwmon: (pmbus/lm25066) Support configurable sense resistor values") +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + #include + #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 + diff --git a/queue-6.6/ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch b/queue-6.6/ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch new file mode 100644 index 0000000000..6a95690792 --- /dev/null +++ b/queue-6.6/ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch @@ -0,0 +1,259 @@ +From e74bd05e1da1fbd8de57594226d1a3cfd7bcdabc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 21:35:05 +0300 +Subject: ipvs: avoid out-of-bounds write in ip_vs_nat_icmp + +From: Julian Anastasov + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/ipvs-return-the-csum-validation-for-forward-hook.patch b/queue-6.6/ipvs-return-the-csum-validation-for-forward-hook.patch new file mode 100644 index 0000000000..594f1cde67 --- /dev/null +++ b/queue-6.6/ipvs-return-the-csum-validation-for-forward-hook.patch @@ -0,0 +1,100 @@ +From 216d0c71944fb1b2bc5cc20ebeaec4c34a8208f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 21:35:06 +0300 +Subject: ipvs: return the csum validation for forward hook + +From: Julian Anastasov + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 /* for union nf_inet_addr */ + #include + #include /* for struct ipv6hdr */ +-#include + #include +-#include + #if IS_ENABLED(CONFIG_NF_CONNTRACK) + #include + #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 + diff --git a/queue-6.6/net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch b/queue-6.6/net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch new file mode 100644 index 0000000000..18efd91ef7 --- /dev/null +++ b/queue-6.6/net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch @@ -0,0 +1,81 @@ +From 4962d904a54474e882985fd09f2fb9c7bc6cc78b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 13:15:08 +0000 +Subject: net/atm: fix slab-out-of-bounds read in vcc_setsockopt() + +From: Eric Dumazet + +[ 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 +Link: https://patch.msgid.link/20260805131508.3227331-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch b/queue-6.6/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch new file mode 100644 index 0000000000..48fc62113d --- /dev/null +++ b/queue-6.6/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch @@ -0,0 +1,42 @@ +From 923e2e30e6ae64462806cc2e9535e47ce567f000 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-mlx5-fw_tracer-return-null-on-create-error.patch b/queue-6.6/net-mlx5-fw_tracer-return-null-on-create-error.patch new file mode 100644 index 0000000000..03191e90df --- /dev/null +++ b/queue-6.6/net-mlx5-fw_tracer-return-null-on-create-error.patch @@ -0,0 +1,134 @@ +From 2e456ce684daae5f535abff9cdb7525703e1bfc6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 11:04:02 +0300 +Subject: net/mlx5: fw_tracer, return NULL on create error + +From: Michael Guralnik + +[ 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 +Reviewed-by: Shay Drori +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260729080402.2427184-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.6/net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch b/queue-6.6/net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch new file mode 100644 index 0000000000..a8ee36d0b6 --- /dev/null +++ b/queue-6.6/net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch @@ -0,0 +1,100 @@ +From 8ca54dc66807bcce17a66462f3b80e06e5e1eb47 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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 + + +Fixes: 04de7dda7394 ("net/mlx5e: Infrastructure for duplicated offloading of TC flows") +Signed-off-by: Shay Drory +Reviewed-by: Cosmin Ratiu +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260728044338.2271143-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch b/queue-6.6/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch new file mode 100644 index 0000000000..8294e86e7f --- /dev/null +++ b/queue-6.6/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch @@ -0,0 +1,60 @@ +From 4bced815c3e2adf53e2ac833258c811ab8ffb06b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Henry Martin +Link: https://patch.msgid.link/20260803043618.3210301-1-bsdhenrymartin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-openvswitch-check-ethernet-header-length-in-key_.patch b/queue-6.6/net-openvswitch-check-ethernet-header-length-in-key_.patch new file mode 100644 index 0000000000..abb42b9d7c --- /dev/null +++ b/queue-6.6/net-openvswitch-check-ethernet-header-length-in-key_.patch @@ -0,0 +1,78 @@ +From a045441708444ca097bbe8358aebfc6fd7996bbd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 18:20:06 -0400 +Subject: net/openvswitch: check Ethernet header length in key_extract() + +From: Cen Zhang (Microsoft) + +[ 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 +Signed-off-by: Cen Zhang (Microsoft) +Reviewed-by: Ilya Maximets +Link: https://patch.msgid.link/20260730222006.118652-1-blbllhy@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-prestera-validate-firmware-header-length.patch b/queue-6.6/net-prestera-validate-firmware-header-length.patch new file mode 100644 index 0000000000..12dd342ccc --- /dev/null +++ b/queue-6.6/net-prestera-validate-firmware-header-length.patch @@ -0,0 +1,42 @@ +From 7e9094dca48e787324492070d823bddf0b571b43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 22:19:06 +0800 +Subject: net: prestera: validate firmware header length + +From: Pengpeng Hou + +[ 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 +Acked-by: Elad Nachman +Link: https://patch.msgid.link/20260731141500.1-prestera-v2-pengpeng@iscas.ac.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-remove-warn_on_once-from-sk_mc_loop.patch b/queue-6.6/net-remove-warn_on_once-from-sk_mc_loop.patch new file mode 100644 index 0000000000..b1ea26a038 --- /dev/null +++ b/queue-6.6/net-remove-warn_on_once-from-sk_mc_loop.patch @@ -0,0 +1,45 @@ +From 522df6435251270ad6c72cd23231abc38e59640b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 15:20:48 +0000 +Subject: net: remove WARN_ON_ONCE() from sk_mc_loop() + +From: Eric Dumazet + +[ 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 +Link: https://patch.msgid.link/20260804152048.2134341-1-edumazet@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-sched-cls_api-add-filter-counter.patch b/queue-6.6/net-sched-cls_api-add-filter-counter.patch new file mode 100644 index 0000000000..f67778b9ed --- /dev/null +++ b/queue-6.6/net-sched-cls_api-add-filter-counter.patch @@ -0,0 +1,94 @@ +From f9b2cd440597e1f6e9864e5f0d66be4080ceefd1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Reviewed-by: Marcelo Ricardo Leitner +Signed-off-by: David S. Miller +Stable-dep-of: a347304b2ca1 ("net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-sched-cls_api-add-skip_sw-counter.patch b/queue-6.6/net-sched-cls_api-add-skip_sw-counter.patch new file mode 100644 index 0000000000..e098d077ed --- /dev/null +++ b/queue-6.6/net-sched-cls_api-add-skip_sw-counter.patch @@ -0,0 +1,66 @@ +From c9b21c1888961e4ed043378d29923e3d0cfe21e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Jiri Pirko +Reviewed-by: Simon Horman +Reviewed-by: Marcelo Ricardo Leitner +Signed-off-by: David S. Miller +Stable-dep-of: a347304b2ca1 ("net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch b/queue-6.6/net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch new file mode 100644 index 0000000000..bcdf6ead0c --- /dev/null +++ b/queue-6.6/net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch @@ -0,0 +1,116 @@ +From a5018ba5e92d2c8478278db4210c7cf49590761e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Tested-by: Victor Nogueira +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260801125632.360365-1-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-sched-cls_api-fix-slab-use-after-free-in-fl_dump.patch b/queue-6.6/net-sched-cls_api-fix-slab-use-after-free-in-fl_dump.patch new file mode 100644 index 0000000000..9721f6dfbf --- /dev/null +++ b/queue-6.6/net-sched-cls_api-fix-slab-use-after-free-in-fl_dump.patch @@ -0,0 +1,198 @@ +From e76ee5f3b2c5e990e3d22ff09f1db08e2f766e9c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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 + + + 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 +Reviewed-by: Cosmin Ratiu +Tested-by: Asbjørn Sloth Tønnesen +Signed-off-by: David S. Miller +Stable-dep-of: a347304b2ca1 ("net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch b/queue-6.6/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch new file mode 100644 index 0000000000..e6ad7dd782 --- /dev/null +++ b/queue-6.6/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch @@ -0,0 +1,142 @@ +From 4c756026630c2e20dc03f88374d22f3b76e18a49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Suggested-by: Paolo Abeni +Tested-by: Victor Nogueira +Tested-by: Santosh Kalluri +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260729094411.46257-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-sched-make-skip_sw-actually-skip-software.patch b/queue-6.6/net-sched-make-skip_sw-actually-skip-software.patch new file mode 100644 index 0000000000..b29523c22f --- /dev/null +++ b/queue-6.6/net-sched-make-skip_sw-actually-skip-software.patch @@ -0,0 +1,208 @@ +From 72ece3300ede9fdedf0ab45835e4bd8e06b43e0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Reviewed-by: Marcelo Ricardo Leitner +Signed-off-by: David S. Miller +Stable-dep-of: a347304b2ca1 ("net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-sched-refine-software-bypass-handling-in-tc_run.patch b/queue-6.6/net-sched-refine-software-bypass-handling-in-tc_run.patch new file mode 100644 index 0000000000..e90f321d8d --- /dev/null +++ b/queue-6.6/net-sched-refine-software-bypass-handling-in-tc_run.patch @@ -0,0 +1,363 @@ +From d39609f033baec27a962861e40a96c44903d464c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Xin Long +Acked-by: Marcelo Ricardo Leitner +Reviewed-by: Asbjørn Sloth Tønnesen +Tested-by: Asbjørn Sloth Tønnesen +Signed-off-by: David S. Miller +Stable-dep-of: a347304b2ca1 ("net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch b/queue-6.6/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch new file mode 100644 index 0000000000..990a2f0eca --- /dev/null +++ b/queue-6.6/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch @@ -0,0 +1,50 @@ +From 72ca602caf481109c4195ebae1a34141f18a32fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reported-by: Ren Wei +Signed-off-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260729191417.45665-1-toke@toke.dk +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch b/queue-6.6/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch new file mode 100644 index 0000000000..a14dc2d24e --- /dev/null +++ b/queue-6.6/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch @@ -0,0 +1,57 @@ +From 9bb5cc8bb500be2675d14d6591f4b0c97de36de9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Hidayath Khan +Reviewed-by: Sidraya Jayagond +Reviewed-by: Dust Li +Link: https://patch.msgid.link/20260729130153.970800-1-mjambigi@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch b/queue-6.6/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch new file mode 100644 index 0000000000..9454979bb2 --- /dev/null +++ b/queue-6.6/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch @@ -0,0 +1,71 @@ +From 637bd3ade2324c39398731844bd537d8b2481390 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Sidraya Jayagond +Reviewed-by: Breno Leitao +Reviewed-by: Dust Li +Link: https://patch.msgid.link/20260803070701.126339-1-sidraya@linux.ibm.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-tcp-add-tcp-ao-config-and-structures.patch b/queue-6.6/net-tcp-add-tcp-ao-config-and-structures.patch new file mode 100644 index 0000000000..ce89c5188e --- /dev/null +++ b/queue-6.6/net-tcp-add-tcp-ao-config-and-structures.patch @@ -0,0 +1,217 @@ +From 9772224077b914196aa211675a40dc013bf3d8af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Oct 2023 20:21:54 +0100 +Subject: net/tcp: Add TCP-AO config and structures + +From: Dmitry Safonov + +[ 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 +Signed-off-by: Francesco Ruggeri +Co-developed-by: Salam Noureddine +Signed-off-by: Salam Noureddine +Signed-off-by: Dmitry Safonov +Acked-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: d0c80dbb9704 ("net/atm: fix slab-out-of-bounds read in vcc_setsockopt()") +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 + diff --git a/queue-6.6/net-tcp-prepare-tcp_md5sig_pool-for-tcp-ao.patch b/queue-6.6/net-tcp-prepare-tcp_md5sig_pool-for-tcp-ao.patch new file mode 100644 index 0000000000..374e59089b --- /dev/null +++ b/queue-6.6/net-tcp-prepare-tcp_md5sig_pool-for-tcp-ao.patch @@ -0,0 +1,1081 @@ +From 8917d63c7fb7265415692a74297683511f001bee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Oct 2023 20:21:53 +0100 +Subject: net/tcp: Prepare tcp_md5sig_pool for TCP-AO + +From: Dmitry Safonov + +[ 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 +Reviewed-by: Steen Hegelund +Acked-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: d0c80dbb9704 ("net/atm: fix slab-out-of-bounds read in vcc_setsockopt()") +Signed-off-by: Sasha Levin +--- + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 + diff --git a/queue-6.6/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch b/queue-6.6/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch new file mode 100644 index 0000000000..c0879fd8a5 --- /dev/null +++ b/queue-6.6/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch @@ -0,0 +1,117 @@ +From e4a98c4d2af4456541dca21224fa7c707150ae56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 14:38:50 +0000 +Subject: net: thunderbolt: Tear down DMA paths before stopping the rings + +From: Fan XinRan + +[ 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 +Acked-by: Mika Westerberg +Link: https://patch.msgid.link/20260803-b4-tbnet-teardown-v2-1-27de6a13ca2d@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/netfilter-ipset-switch-ext_size-to-atomic64_t.patch b/queue-6.6/netfilter-ipset-switch-ext_size-to-atomic64_t.patch new file mode 100644 index 0000000000..661d14c5e1 --- /dev/null +++ b/queue-6.6/netfilter-ipset-switch-ext_size-to-atomic64_t.patch @@ -0,0 +1,134 @@ +From 1e43c1acf9529cd4e04e08a0e3abdbe5eff64256 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 20:38:50 +0200 +Subject: netfilter: ipset: switch ext_size to atomic64_t + +From: Jozsef Kadlecsik + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/ipset/ip_set.h | 2 +- + net/netfilter/ipset/ip_set_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 + diff --git a/queue-6.6/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch b/queue-6.6/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch new file mode 100644 index 0000000000..327f98b1d0 --- /dev/null +++ b/queue-6.6/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch @@ -0,0 +1,50 @@ +From ed1bf91cdc5ba8071ddc04646dfc9256cc9ac3a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Jun 2026 14:31:00 -0400 +Subject: NFS: Pin the 'struct nfs_server' during a FREE_STATEID call + +From: Anna Schumaker + +[ 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 +Fixes: 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call") +Tested-by: Dan Aloni +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/regulator-devres-add-api-for-reference-voltage-suppl.patch b/queue-6.6/regulator-devres-add-api-for-reference-voltage-suppl.patch new file mode 100644 index 0000000000..4017b5fa63 --- /dev/null +++ b/queue-6.6/regulator-devres-add-api-for-reference-voltage-suppl.patch @@ -0,0 +1,135 @@ +From a425b1ed1110b9a585f510df8c6f7e64b67c0b86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Apr 2024 18:40:09 -0500 +Subject: regulator: devres: add API for reference voltage supplies + +From: David Lechner + +[ 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 +Link: https://lore.kernel.org/r/20240429-regulator-get-enable-get-votlage-v2-1-b1f11ab766c1@baylibre.com +Signed-off-by: Mark Brown +Stable-dep-of: fddb5ceaf901 ("hwmon: (ads7828) Fix external VREF regulator handling") +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.6/revert-net-thunderbolt-enable-end-to-end-flow-contro.patch b/queue-6.6/revert-net-thunderbolt-enable-end-to-end-flow-contro.patch new file mode 100644 index 0000000000..6122c75800 --- /dev/null +++ b/queue-6.6/revert-net-thunderbolt-enable-end-to-end-flow-contro.patch @@ -0,0 +1,104 @@ +From bcaadac1036df10f32dd5435beeeb6b500d14337 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Fan Ye +Acked-by: Mika Westerberg +Link: https://patch.msgid.link/20260727123002.25225-1-fy15309206903@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/sctp-clear-control-chunk-transport-if-it-is-being-re.patch b/queue-6.6/sctp-clear-control-chunk-transport-if-it-is-being-re.patch new file mode 100644 index 0000000000..6554cd522e --- /dev/null +++ b/queue-6.6/sctp-clear-control-chunk-transport-if-it-is-being-re.patch @@ -0,0 +1,54 @@ +From e4f48aeb9e232fbcc71ca314c1af41b44513274a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 11:18:40 -0400 +Subject: sctp: clear control chunk transport if it is being removed + +From: Xin Long + +[ 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 +Signed-off-by: Xin Long +Link: https://patch.msgid.link/7e1168cb722132152a29d47e5eafaeac4a3bf6f3.1785943120.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch b/queue-6.6/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch new file mode 100644 index 0000000000..16ee3347d4 --- /dev/null +++ b/queue-6.6/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch @@ -0,0 +1,57 @@ +From f7034fc517df12f7c7ae1c022389fce66fe6a512 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 10:55:14 +0800 +Subject: sctp: fix addip_serial increment on ASCONF_ACK allocation failure + +From: Qing Luo + +[ 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 +Acked-by: Xin Long +Link: https://patch.msgid.link/20260804025514.241767-1-l1138897701@163.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch b/queue-6.6/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch new file mode 100644 index 0000000000..bdd6117b78 --- /dev/null +++ b/queue-6.6/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch @@ -0,0 +1,88 @@ +From 5e14cad88e4ae3e56d88f7a9edde992bafd950c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 21:46:35 +0200 +Subject: selftests/ftrace: refactor eprobes test to fix argument checks + +From: Martin Kaiser + +[ 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 " 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 +Closes: https://lore.kernel.org/oe-lkp/202607151010.b68428e1-lkp@intel.com +Signed-off-by: Martin Kaiser +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + .../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 ". []":README ++# requires: dynamic_events events/syscalls/sys_enter_chdir ". []":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 + diff --git a/queue-6.6/series b/queue-6.6/series index aa60066a86..cd27521ef5 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -1,3 +1,62 @@ 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 diff --git a/queue-6.6/tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch b/queue-6.6/tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch new file mode 100644 index 0000000000..8f910142a4 --- /dev/null +++ b/queue-6.6/tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch @@ -0,0 +1,61 @@ +From 09ccb6451412337ba0de04ec60d7d161814e0e66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 20:08:06 -0700 +Subject: tcp: do not change rcv_ssthresh in tcp_measure_rcv_mss() + +From: Nathan Gao + +[ 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 +Link: https://patch.msgid.link/20260725030806.28135-1-zcgao@amazon.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch b/queue-6.6/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch new file mode 100644 index 0000000000..c45dc1dc12 --- /dev/null +++ b/queue-6.6/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch @@ -0,0 +1,72 @@ +From a46dc029eed5866bd2c1669fe423ce66a0f9f9a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 14:17:38 +0800 +Subject: tcp: fix TFO max_qlen accounting across reuseport migration + +From: Jiayuan Chen + +[ 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 +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260803061739.134737-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/tls-don-t-abort-the-connection-on-signal-interrupted.patch b/queue-6.6/tls-don-t-abort-the-connection-on-signal-interrupted.patch new file mode 100644 index 0000000000..4a530414e6 --- /dev/null +++ b/queue-6.6/tls-don-t-abort-the-connection-on-signal-interrupted.patch @@ -0,0 +1,45 @@ +From c5720e98f7248ca4fb676480759005646192cab9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 08:22:48 +0200 +Subject: tls: don't abort the connection on signal-interrupted sends + +From: Maximilian Immanuel Brandtner + +[ 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 +Link: https://patch.msgid.link/20260805063109.1772314-1-maxbr@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch b/queue-6.6/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch new file mode 100644 index 0000000000..1b517eb43b --- /dev/null +++ b/queue-6.6/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch @@ -0,0 +1,53 @@ +From 4de2cb64ae2f6d0e9c78683919829dc9c96d0e79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 17:35:54 +0800 +Subject: udp: fix potential use-after-free in tunnel segmentation + +From: Xuanqiang Luo + +[ 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 +Reviewed-by: Antoine Tenart +Link: https://patch.msgid.link/20260730093554.68127-1-xuanqiang.luo@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch b/queue-6.6/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch new file mode 100644 index 0000000000..0cd0ff5d27 --- /dev/null +++ b/queue-6.6/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch @@ -0,0 +1,56 @@ +From 9dbd818c63fb2834e3ad06811735b6e8e388cb79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 15:02:02 -0700 +Subject: vhost/vdpa: reject overflowing PA map page counts on 32-bit + +From: Yousef Alhouseen + +[ 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 +Signed-off-by: Yousef Alhouseen +Signed-off-by: Michael S. Tsirkin +Message-ID: +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/accel-amdxdna-fix-locally-exploitable-bug_on-in-amdx.patch b/queue-7.1/accel-amdxdna-fix-locally-exploitable-bug_on-in-amdx.patch new file mode 100644 index 0000000000..7922c5ec81 --- /dev/null +++ b/queue-7.1/accel-amdxdna-fix-locally-exploitable-bug_on-in-amdx.patch @@ -0,0 +1,86 @@ +From a90890f9986886308a5036e1bef64b29306dc3a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 11:59:55 -0700 +Subject: accel/amdxdna: Fix locally exploitable BUG_ON in + amdxdna_insert_pages() + +From: Lizhi Hou + +[ 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 +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260731185955.3449311-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/accel-amxdna-fix-page-insertion-errors-in-amdxdna_in.patch b/queue-7.1/accel-amxdna-fix-page-insertion-errors-in-amdxdna_in.patch new file mode 100644 index 0000000000..55da1bb76d --- /dev/null +++ b/queue-7.1/accel-amxdna-fix-page-insertion-errors-in-amdxdna_in.patch @@ -0,0 +1,88 @@ +From 06d3584193b29dd8e735c47bea538cc00b1b235b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260723074256.2435143-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/alsa-usb-audio-add-quirk_flag_mixer_get_cur_broken-f.patch b/queue-7.1/alsa-usb-audio-add-quirk_flag_mixer_get_cur_broken-f.patch new file mode 100644 index 0000000000..24ba3eca92 --- /dev/null +++ b/queue-7.1/alsa-usb-audio-add-quirk_flag_mixer_get_cur_broken-f.patch @@ -0,0 +1,54 @@ +From 62d4903edd07f2261af2eabf583bf45ffee38393 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reported-by: Brian van den Berg +Link: https://lore.kernel.org/all/370007e6-b73b-4bfc-8410-a860781c7ad7@proton.me/ +Signed-off-by: Rong Zhang +Link: https://patch.msgid.link/20260731-uac-lg-pro-x-2-ls-v1-1-268eaefe66ab@rong.moe +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/alsa-usb-audio-add-quirk_flag_mixer_get_cur_broken.patch b/queue-7.1/alsa-usb-audio-add-quirk_flag_mixer_get_cur_broken.patch new file mode 100644 index 0000000000..ca845a2e01 --- /dev/null +++ b/queue-7.1/alsa-usb-audio-add-quirk_flag_mixer_get_cur_broken.patch @@ -0,0 +1,264 @@ +From 31e783ee84c8e2a10849ab2e654f916f65a51df2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 31 May 2026 23:45:20 +0800 +Subject: ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN + +From: Rong Zhang + +[ 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 +Signed-off-by: Takashi Iwai +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 +--- + 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 + diff --git a/queue-7.1/alsa-usb-audio-fix-sticky-mixer-regressions-on-m-aud.patch b/queue-7.1/alsa-usb-audio-fix-sticky-mixer-regressions-on-m-aud.patch new file mode 100644 index 0000000000..8ea7c99fe5 --- /dev/null +++ b/queue-7.1/alsa-usb-audio-fix-sticky-mixer-regressions-on-m-aud.patch @@ -0,0 +1,48 @@ +From 6e863757289511922135720250dc384814df8d46 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch b/queue-7.1/arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch new file mode 100644 index 0000000000..c65928785f --- /dev/null +++ b/queue-7.1/arm-dts-bcm5301x-fix-pcie-controller-2-second-interr.patch @@ -0,0 +1,39 @@ +From b92154d6ef4536bac11fecaecbff73f2cf068ed6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Jul 2026 14:57:22 -0700 +Subject: ARM: dts: BCM5301X: fix PCIe controller 2 second interrupt + +From: Rosen Penev + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch b/queue-7.1/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch new file mode 100644 index 0000000000..2fd7e0ab37 --- /dev/null +++ b/queue-7.1/arm-npcm-fix-of-node-refcount-leaks-in-smp-setup.patch @@ -0,0 +1,50 @@ +From 4283322924643de464c569c760a81eabcbf02d6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 24 May 2026 23:38:46 -0400 +Subject: ARM: npcm: Fix OF node refcount leaks in SMP setup + +From: Yuho Choi + +[ 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 +Reviewed-by: Avi Fishman +Signed-off-by: Andrew Jeffery +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/arm64-dts-broadcom-bcm2712-remove-non-functional-el2.patch b/queue-7.1/arm64-dts-broadcom-bcm2712-remove-non-functional-el2.patch new file mode 100644 index 0000000000..16c52bfe44 --- /dev/null +++ b/queue-7.1/arm64-dts-broadcom-bcm2712-remove-non-functional-el2.patch @@ -0,0 +1,52 @@ +From f0284b7aa6a3f1c0df86649cb21fce578350e432 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 21:45:27 +0100 +Subject: arm64: dts: broadcom: bcm2712: Remove non-functional EL2 virtual + timer + +From: Daniel Drake + +[ 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 +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 +Link: https://lore.kernel.org/r/20260716-bcm2712-el2-v2-1-e708f7fb42fa@reactivated.net +Signed-off-by: Florian Fainelli +Signed-off-by: Sasha Levin +--- + 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)>, + , + , +- ; + }; + +-- +2.53.0 + diff --git a/queue-7.1/arm64-dts-qcom-glymur-fix-pcie-smmu-interrupts.patch b/queue-7.1/arm64-dts-qcom-glymur-fix-pcie-smmu-interrupts.patch new file mode 100644 index 0000000000..b6ca37b4c0 --- /dev/null +++ b/queue-7.1/arm64-dts-qcom-glymur-fix-pcie-smmu-interrupts.patch @@ -0,0 +1,44 @@ +From c0b042d5b01bd95be979b30180d42672779e9887 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Jun 2026 19:00:44 +0000 +Subject: arm64: dts: qcom: glymur: fix PCIe SMMU interrupts + +From: Bjorn Andersson + +[ 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 +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260611-glymur-pcie-smmu-espi-v1-1-5effbaa3e1af@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + 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 = , +- , +- ; ++ interrupts = , ++ , ++ ; + interrupt-names = "eventq", "cmdq-sync", "gerror"; + dma-coherent; + #iommu-cells = <1>; +-- +2.53.0 + diff --git a/queue-7.1/arm64-dts-qcom-glymur-fix-qup-serial-engine-irqs.patch b/queue-7.1/arm64-dts-qcom-glymur-fix-qup-serial-engine-irqs.patch new file mode 100644 index 0000000000..a2856d7191 --- /dev/null +++ b/queue-7.1/arm64-dts-qcom-glymur-fix-qup-serial-engine-irqs.patch @@ -0,0 +1,152 @@ +From 6a1e0e19ec5d51e27399651d1d965c8d070132c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Jun 2026 17:22:37 +0000 +Subject: arm64: dts: qcom: glymur: fix QUP serial engine IRQs + +From: Bjorn Andersson + +[ 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 +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260611-glymur-geni-irqs-v1-1-269428faeb6d@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + 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 = ; ++ interrupts = ; + 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 = ; ++ interrupts = ; + 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 = ; ++ interrupts = ; + 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 = ; ++ interrupts = ; + 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 = ; ++ interrupts = ; + 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 = ; ++ interrupts = ; + 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 = ; ++ interrupts = ; + 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 = ; ++ interrupts = ; + 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 = ; ++ interrupts = ; + 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 = ; ++ interrupts = ; + 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 = ; ++ interrupts = ; + 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 = ; ++ interrupts = ; + 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 = ; ++ interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS +-- +2.53.0 + diff --git a/queue-7.1/arm64-dts-qcom-monaco-add-default-gic-address-cells.patch b/queue-7.1/arm64-dts-qcom-monaco-add-default-gic-address-cells.patch new file mode 100644 index 0000000000..d491e70a6e --- /dev/null +++ b/queue-7.1/arm64-dts-qcom-monaco-add-default-gic-address-cells.patch @@ -0,0 +1,48 @@ +From e0504d42d5fd9d51b83e56ca770ab5992e5ce3d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 22:15:19 +0200 +Subject: arm64: dts: qcom: monaco: Add default GIC address cells + +From: Krzysztof Kozlowski + +[ 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 +Reviewed-by: Manivannan Sadhasivam +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260407201518.24949-2-krzysztof.kozlowski@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/arm64-dts-qcom-purwa-fix-gpu-iommu-property.patch b/queue-7.1/arm64-dts-qcom-purwa-fix-gpu-iommu-property.patch new file mode 100644 index 0000000000..3a9601e4c1 --- /dev/null +++ b/queue-7.1/arm64-dts-qcom-purwa-fix-gpu-iommu-property.patch @@ -0,0 +1,99 @@ +From b6e0397d1c682a29e784cd397d503e29e39fd1d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 02:38:51 +0530 +Subject: arm64: dts: qcom: purwa: Fix GPU IOMMU property + +From: Akhil P Oommen + +[ 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 +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260410-purwa-gpu-dt-fix-v1-1-4637892156cf@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/arm64-dts-qcom-sdm850-lenovo-yoga-c630-lower-psci-cl.patch b/queue-7.1/arm64-dts-qcom-sdm850-lenovo-yoga-c630-lower-psci-cl.patch new file mode 100644 index 0000000000..c8682ae5d9 --- /dev/null +++ b/queue-7.1/arm64-dts-qcom-sdm850-lenovo-yoga-c630-lower-psci-cl.patch @@ -0,0 +1,45 @@ +From 61d5d2864edaf2976a1476344fe9bd64599b66d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 01:27:12 +0300 +Subject: arm64: dts: qcom: sdm850-lenovo-yoga-c630: lower PSCI cluster idle + +From: Dmitry Baryshkov + +[ 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 +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260429-c630-fix-idle-v2-1-ac867dad6f21@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + 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 = , + , +-- +2.53.0 + diff --git a/queue-7.1/arm64-dts-qcom-sm8650-fix-ipa-imem-slice.patch b/queue-7.1/arm64-dts-qcom-sm8650-fix-ipa-imem-slice.patch new file mode 100644 index 0000000000..78d5c6dc81 --- /dev/null +++ b/queue-7.1/arm64-dts-qcom-sm8650-fix-ipa-imem-slice.patch @@ -0,0 +1,42 @@ +From dd5583ad318c68e3e4bb9e3856cbc71e80c86d8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 23:45:18 +0000 +Subject: arm64: dts: qcom: sm8650: Fix IPA IMEM slice + +From: Alexander Koskovich + +[ 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 +Fixes: 581fc5d5ade6 ("arm64: dts: qcom: sm8650: Explicitly describe the IPA IMEM slice") +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260415-fix-8650-ipa-modem-tables-v1-1-95f8f425e416@pm.me +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch b/queue-7.1/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch new file mode 100644 index 0000000000..43a98132cb --- /dev/null +++ b/queue-7.1/ata-pata_sl82c105-fix-bridge-revision-use-after-free.patch @@ -0,0 +1,52 @@ +From 33df9dc6ef8524fae209c4067ab1f2f7ce88c2eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Aug 2026 14:06:28 +0800 +Subject: ata: pata_sl82c105: fix bridge revision use-after-free + +From: Hongyan Xu + +[ 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 +Reviewed-by: Niklas Cassel +Signed-off-by: Damien Le Moal +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/bnge-fix-null-pointer-dereference-in-aux-device-rele.patch b/queue-7.1/bnge-fix-null-pointer-dereference-in-aux-device-rele.patch new file mode 100644 index 0000000000..a31a77439e --- /dev/null +++ b/queue-7.1/bnge-fix-null-pointer-dereference-in-aux-device-rele.patch @@ -0,0 +1,58 @@ +From 851259a955366c9e483546cef17293e050c586b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:22:59 -0700 +Subject: bnge: Fix NULL pointer dereference in aux device release + +From: Alok Tiwari + +[ 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 +Reviewed-by: Bhargava Marreddy +Link: https://patch.msgid.link/20260731192301.1427645-1-alok.a.tiwari@oracle.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/bnge-fix-resource-leak-in-bnge_init_nic-error-path.patch b/queue-7.1/bnge-fix-resource-leak-in-bnge_init_nic-error-path.patch new file mode 100644 index 0000000000..8150f57572 --- /dev/null +++ b/queue-7.1/bnge-fix-resource-leak-in-bnge_init_nic-error-path.patch @@ -0,0 +1,42 @@ +From 067e01bda598d83db5fcb4eaab0e6cfa540bf643 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 15:10:22 +0530 +Subject: bnge: Fix resource leak in bnge_init_nic() error path + +From: Bhargava Marreddy + +[ 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 +Reviewed-by: Dharmender Garg +Reviewed-by: Rajashekar Hudumula +Link: https://patch.msgid.link/20260805094022.15487-1-bhargava.marreddy@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/bnge-use-int-for-bnge_fix_rings_count-return-value.patch b/queue-7.1/bnge-use-int-for-bnge_fix_rings_count-return-value.patch new file mode 100644 index 0000000000..7bd603b23c --- /dev/null +++ b/queue-7.1/bnge-use-int-for-bnge_fix_rings_count-return-value.patch @@ -0,0 +1,44 @@ +From 4d7c07f17587437a6d726007f515d86766967ff2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 1 Aug 2026 03:09:20 -0700 +Subject: bnge: use int for bnge_fix_rings_count() return value + +From: Alok Tiwari + +[ 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 +Reviewed-by: Bhargava Marreddy +Link: https://patch.msgid.link/20260801100923.1498570-1-alok.a.tiwari@oracle.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/bnxt-fix-memory-leak-in-bnxt_queue_mem_alloc-error-c.patch b/queue-7.1/bnxt-fix-memory-leak-in-bnxt_queue_mem_alloc-error-c.patch new file mode 100644 index 0000000000..684ffeea2f --- /dev/null +++ b/queue-7.1/bnxt-fix-memory-leak-in-bnxt_queue_mem_alloc-error-c.patch @@ -0,0 +1,54 @@ +From 1200751616e5a1d1f77012aa17410aad6530e7de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 15:01:31 -0700 +Subject: bnxt: fix memory leak in bnxt_queue_mem_alloc error cases + +From: Will Chen + +[ 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 +Reviewed-by: Joe Damato +Reviewed-by: Michael Chan +Link: https://patch.msgid.link/20260729220132.1256924-1-will.chen.tty@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/bnxt_en-determine-and-store-default-rx-ring-in-vnic-.patch b/queue-7.1/bnxt_en-determine-and-store-default-rx-ring-in-vnic-.patch new file mode 100644 index 0000000000..900e305e86 --- /dev/null +++ b/queue-7.1/bnxt_en-determine-and-store-default-rx-ring-in-vnic-.patch @@ -0,0 +1,155 @@ +From 350f771fd0318644180a9243771678aa8bab9d91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:09:34 -0700 +Subject: bnxt_en: Determine and store default RX ring in vnic structure + +From: Shravya KN + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: Shravya KN +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-3-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 0b137529a899 ("bnxt_en: Refresh VNIC default ring on queue restart if needed") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch b/queue-7.1/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch new file mode 100644 index 0000000000..0f7c44e3e8 --- /dev/null +++ b/queue-7.1/bnxt_en-disable-eop-for-tpa-on-all-chips-to-prevent-.patch @@ -0,0 +1,57 @@ +From 194d0e47a3648717069a69ee40a69793a20823b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Kalesh AP +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-5-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/bnxt_en-fix-ptp-pps-setting-bug.patch b/queue-7.1/bnxt_en-fix-ptp-pps-setting-bug.patch new file mode 100644 index 0000000000..679c5e23f1 --- /dev/null +++ b/queue-7.1/bnxt_en-fix-ptp-pps-setting-bug.patch @@ -0,0 +1,54 @@ +From c983bb02d31d9dd3d292f3069a856ec5f961ec5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:09:37 -0700 +Subject: bnxt_en: Fix PTP PPS setting bug + +From: Keegan Freyhof + +[ 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 +Signed-off-by: Keegan Freyhof +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-6-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/bnxt_en-move-rss-table-fill-outside-__bnxt_hwrm_vnic.patch b/queue-7.1/bnxt_en-move-rss-table-fill-outside-__bnxt_hwrm_vnic.patch new file mode 100644 index 0000000000..6537d9dfc4 --- /dev/null +++ b/queue-7.1/bnxt_en-move-rss-table-fill-outside-__bnxt_hwrm_vnic.patch @@ -0,0 +1,75 @@ +From 8e27366cbe015e104fcd13086e80361b8f0151a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: Shravya KN +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-2-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 0b137529a899 ("bnxt_en: Refresh VNIC default ring on queue restart if needed") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/bnxt_en-refresh-vnic-default-ring-on-queue-restart-i.patch b/queue-7.1/bnxt_en-refresh-vnic-default-ring-on-queue-restart-i.patch new file mode 100644 index 0000000000..482187f752 --- /dev/null +++ b/queue-7.1/bnxt_en-refresh-vnic-default-ring-on-queue-restart-i.patch @@ -0,0 +1,46 @@ +From 2480bc4ab31d47c5b49b9e9aff79bc8cdf3bbe29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:09:35 -0700 +Subject: bnxt_en: Refresh VNIC default ring on queue restart if needed + +From: Shravya KN + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: Shravya KN +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260731190937.807270-4-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch b/queue-7.1/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch new file mode 100644 index 0000000000..8987607e9c --- /dev/null +++ b/queue-7.1/bonding-alb-re-check-primary_is_promisc-under-rtnl-i.patch @@ -0,0 +1,80 @@ +From ee79950d43091222dc6e901c19361f695a0c9afe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) + +[ 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) +Reviewed-by: Nikolay Aleksandrov +Acked-by: Jay Vosburgh +Link: https://patch.msgid.link/20260725233930.2957317-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/bpf-check-sk_state-before-sk_protocol-in-bpf_tcp_-_s.patch b/queue-7.1/bpf-check-sk_state-before-sk_protocol-in-bpf_tcp_-_s.patch new file mode 100644 index 0000000000..6b10b9f802 --- /dev/null +++ b/queue-7.1/bpf-check-sk_state-before-sk_protocol-in-bpf_tcp_-_s.patch @@ -0,0 +1,57 @@ +From a5d5175879d9f58a9de17888de75188f41ca70a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 22:29:01 +0800 +Subject: bpf: Check sk_state before sk_protocol in bpf_tcp_*_syncookie + +From: Luxiao Xu + +[ 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 +Signed-off-by: Luxiao Xu +Signed-off-by: Ren Wei +Signed-off-by: Daniel Borkmann +Reviewed-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://lore.kernel.org/bpf/6218aa3534d0d2d3f448fde70a8dc2769d7a8201.1785823138.git.rakukuip@gmail.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/bpf-fix-netns-reference-imbalance-in-conntrack-kfunc.patch b/queue-7.1/bpf-fix-netns-reference-imbalance-in-conntrack-kfunc.patch new file mode 100644 index 0000000000..b886bc2206 --- /dev/null +++ b/queue-7.1/bpf-fix-netns-reference-imbalance-in-conntrack-kfunc.patch @@ -0,0 +1,209 @@ +From 1b11dcb8a320b9256b87cc7ba103e0642aa397da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 1 Aug 2026 00:09:21 +0800 +Subject: bpf: Fix netns reference imbalance in conntrack kfuncs + +From: Chengfeng Ye + +[ 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 +Reviewed-by: Emil Tsalapatis +Link: https://lore.kernel.org/bpf/20260731160921.3245840-1-nicoyip.dev@gmail.com +Signed-off-by: Kumar Kartikeya Dwivedi +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/bpf-preserve-pointer-state-for-commuted-arithmetic.patch b/queue-7.1/bpf-preserve-pointer-state-for-commuted-arithmetic.patch new file mode 100644 index 0000000000..8bb23ee3fb --- /dev/null +++ b/queue-7.1/bpf-preserve-pointer-state-for-commuted-arithmetic.patch @@ -0,0 +1,74 @@ +From 5163f7ec698d791ab29f954522bf13e93fb6c8ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 15:18:28 +0000 +Subject: bpf: Preserve pointer state for commuted arithmetic + +From: Yiyang Chen + +[ 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 +Tested-by: Daniel Wade +Acked-by: Shung-Hsi Yu +Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-2-8ee297e2346b@mails.tsinghua.edu.cn +Signed-off-by: Eduard Zingerman +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/bpf-propagate-untrusted-pointer-state-in-commuted-ar.patch b/queue-7.1/bpf-propagate-untrusted-pointer-state-in-commuted-ar.patch new file mode 100644 index 0000000000..3881242045 --- /dev/null +++ b/queue-7.1/bpf-propagate-untrusted-pointer-state-in-commuted-ar.patch @@ -0,0 +1,59 @@ +From 2027d045fd3797c2842e48603b1cbb20f9a9d295 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 15:18:29 +0000 +Subject: bpf: Propagate untrusted pointer state in commuted arithmetic + +From: Yiyang Chen + +[ 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 +Tested-by: Daniel Wade +Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-3-8ee297e2346b@mails.tsinghua.edu.cn +Signed-off-by: Eduard Zingerman +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch b/queue-7.1/bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch new file mode 100644 index 0000000000..1136f341e1 --- /dev/null +++ b/queue-7.1/bpf-tcp-fix-use-after-free-in-bpf_iter_tcp_establish.patch @@ -0,0 +1,170 @@ +From 7ad64f3a887853151edde8d3a317b75ff5a6f51f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) + +[ 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) +Reviewed-by: Kuniyuki Iwashima +Link: https://lore.kernel.org/bpf/20260730-bpf-iter-tcp-refcnt-v3-1-754b9c8a6717@linux.dev +Signed-off-by: Kumar Kartikeya Dwivedi +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/btrfs-disable-bs-ps-support-if-no-transparent-hugepa.patch b/queue-7.1/btrfs-disable-bs-ps-support-if-no-transparent-hugepa.patch new file mode 100644 index 0000000000..5de456efd4 --- /dev/null +++ b/queue-7.1/btrfs-disable-bs-ps-support-if-no-transparent-hugepa.patch @@ -0,0 +1,67 @@ +From 57fed36c720dac94ba6dde7a0adf00a0d2babf52 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 16:37:39 +0930 +Subject: btrfs: disable bs > ps support if no transparent hugepage support + +From: Qu Wenruo + +[ 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 +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch b/queue-7.1/btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch new file mode 100644 index 0000000000..793a16fd64 --- /dev/null +++ b/queue-7.1/btrfs-fix-memory-leak-in-btrfs_do_encoded_write.patch @@ -0,0 +1,96 @@ +From b842fef77217aeecac1baa74ea1bccd2a3aff47d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 14:53:52 +0300 +Subject: btrfs: fix memory leak in btrfs_do_encoded_write() + +From: Dmitry Antipov + +[ 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 +Signed-off-by: Dmitry Antipov +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/btrfs-initialize-inode-mapping-flags-for-cached-inod.patch b/queue-7.1/btrfs-initialize-inode-mapping-flags-for-cached-inod.patch new file mode 100644 index 0000000000..a408dcc8d3 --- /dev/null +++ b/queue-7.1/btrfs-initialize-inode-mapping-flags-for-cached-inod.patch @@ -0,0 +1,127 @@ +From d4bccdeceb398dc1b1b18d5db2e7b790ecba3adb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 10:14:49 +0930 +Subject: btrfs: initialize inode mapping flags for cached inodes + +From: Qu Wenruo + +[ 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: + + 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 + + ---[ 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 +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/btrfs-lzo-add-error-message-for-invalid-headers.patch b/queue-7.1/btrfs-lzo-add-error-message-for-invalid-headers.patch new file mode 100644 index 0000000000..c7618c58de --- /dev/null +++ b/queue-7.1/btrfs-lzo-add-error-message-for-invalid-headers.patch @@ -0,0 +1,64 @@ +From 735303f7de97f12cab6ab47f21ae361672432c8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 08:23:49 +0930 +Subject: btrfs: lzo: add error message for invalid headers + +From: Qu Wenruo + +[ 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 +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Stable-dep-of: 0fa78ef637de ("btrfs: lzo: reject inline extents without valid headers") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/btrfs-lzo-reject-inline-extents-without-valid-header.patch b/queue-7.1/btrfs-lzo-reject-inline-extents-without-valid-header.patch new file mode 100644 index 0000000000..42fe2774f4 --- /dev/null +++ b/queue-7.1/btrfs-lzo-reject-inline-extents-without-valid-header.patch @@ -0,0 +1,94 @@ +From d82242b80c354beb82b569d5e1ec89bd20ed48a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Jul 2026 09:05:14 +0000 +Subject: btrfs: lzo: reject inline extents without valid headers + +From: David Lee + +[ 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: + + 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 + + +[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 +[ Rework the commit message to remove slop ] +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/btrfs-move-large-data-folios-out-of-experimental-fea.patch b/queue-7.1/btrfs-move-large-data-folios-out-of-experimental-fea.patch new file mode 100644 index 0000000000..b8a6688bba --- /dev/null +++ b/queue-7.1/btrfs-move-large-data-folios-out-of-experimental-fea.patch @@ -0,0 +1,96 @@ +From 3d8483065b9a103c8f10a57dd8638ce0f29b1dba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 10:20:25 +0930 +Subject: btrfs: move large data folios out of experimental features + +From: Qu Wenruo + +[ 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 +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Stable-dep-of: 4c375ac546ea ("btrfs: disable bs > ps support if no transparent hugepage support") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/counter-microchip-tcb-capture-fix-dt-channel-validat.patch b/queue-7.1/counter-microchip-tcb-capture-fix-dt-channel-validat.patch new file mode 100644 index 0000000000..4e66e4e690 --- /dev/null +++ b/queue-7.1/counter-microchip-tcb-capture-fix-dt-channel-validat.patch @@ -0,0 +1,70 @@ +From 9b1857ea19a74ca7e4d9eaa93dd5ff57deec855b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Jul 2026 04:29:10 +0000 +Subject: counter: microchip-tcb-capture: Fix DT channel validation + +From: Babanpreet Singh + +[ 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 +Reviewed-by: Joshua Crofts +Link: https://lore.kernel.org/r/20260714042910.7-1-bbnpreetsingh@gmail.com +Signed-off-by: William Breathitt Gray +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/devlink-fix-net-namespace-reference-leak-in-reload.patch b/queue-7.1/devlink-fix-net-namespace-reference-leak-in-reload.patch new file mode 100644 index 0000000000..065824d69a --- /dev/null +++ b/queue-7.1/devlink-fix-net-namespace-reference-leak-in-reload.patch @@ -0,0 +1,42 @@ +From 3b56739cb890e2403f7c51cc9fe8522723f23d12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 11:06:00 +0300 +Subject: devlink: fix net namespace reference leak in reload + +From: Or Har-Toov + +[ 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 +Reviewed-by: Jiri Pirko +Signed-off-by: Tariq Toukan +Reviewed-by: Antoine Tenart +Link: https://patch.msgid.link/20260729080600.2427721-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/drm-bridge-ps8640-propagate-aux-transfer-register-er.patch b/queue-7.1/drm-bridge-ps8640-propagate-aux-transfer-register-er.patch new file mode 100644 index 0000000000..de27baaa1c --- /dev/null +++ b/queue-7.1/drm-bridge-ps8640-propagate-aux-transfer-register-er.patch @@ -0,0 +1,79 @@ +From 0fee183f09573f4cc7ee0766e506ae38a1fee70e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jul 2026 10:38:06 +0800 +Subject: drm/bridge: ps8640: propagate AUX transfer register errors + +From: Pengpeng Hou + +[ 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 +Reviewed-by: Douglas Anderson +Signed-off-by: Douglas Anderson +Link: https://patch.msgid.link/20260723103509.2-ps8640-v2-pengpeng@iscas.ac.cn +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/drm-xe-fix-memory-leak-in-exec_queue_set_hang_replay.patch b/queue-7.1/drm-xe-fix-memory-leak-in-exec_queue_set_hang_replay.patch new file mode 100644 index 0000000000..df4e59146b --- /dev/null +++ b/queue-7.1/drm-xe-fix-memory-leak-in-exec_queue_set_hang_replay.patch @@ -0,0 +1,48 @@ +From 008c255d9804831110a18e6915fdd0450d17bf91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Fixes: 1026c1a73a96 ("drm/xe: Implement DRM_XE_EXEC_QUEUE_SET_HANG_REPLAY_STATE") +Reviewed-by: Matthew Brost +Link: https://patch.msgid.link/20260624111421.1258364-1-michal.winiarski@intel.com +Signed-off-by: Michał Winiarski +(cherry picked from commit f6b6cc1118bdbc4265fa8b3bdf8565b26f13e56e) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/drm-xe-uc-apply-rcs-ccs-yield-policy-to-sr-iov-vfs.patch b/queue-7.1/drm-xe-uc-apply-rcs-ccs-yield-policy-to-sr-iov-vfs.patch new file mode 100644 index 0000000000..59ec40ae44 --- /dev/null +++ b/queue-7.1/drm-xe-uc-apply-rcs-ccs-yield-policy-to-sr-iov-vfs.patch @@ -0,0 +1,63 @@ +From c16111e40bf11f32380c81c3d1068b0dd224e48c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Marcin Bernatowicz +Cc: Daniele Ceraolo Spurio +Cc: Michal Wajdeczko +Reviewed-by: Daniele Ceraolo Spurio +Link: https://patch.msgid.link/20260709075945.1337660-1-marcin.bernatowicz@linux.intel.com +Signed-off-by: Michał Winiarski +(cherry picked from commit f09360e857130f7ab7f069e2421e6b4a6e502531) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/enic-fix-tx_hang_reset-use-after-free-on-device-remo.patch b/queue-7.1/enic-fix-tx_hang_reset-use-after-free-on-device-remo.patch new file mode 100644 index 0000000000..cc03a02368 --- /dev/null +++ b/queue-7.1/enic-fix-tx_hang_reset-use-after-free-on-device-remo.patch @@ -0,0 +1,49 @@ +From 8073aba65d4ec447580482577f606c62c327bb3f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 23:26:30 -0700 +Subject: enic: fix tx_hang_reset use-after-free on device removal + +From: Satish Kharat + +[ 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 +Link: https://patch.msgid.link/20260728062730.2394873-1-satishkh@cisco.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/hwmon-ads7828-fix-external-vref-regulator-handling.patch b/queue-7.1/hwmon-ads7828-fix-external-vref-regulator-handling.patch new file mode 100644 index 0000000000..f47dcf8b34 --- /dev/null +++ b/queue-7.1/hwmon-ads7828-fix-external-vref-regulator-handling.patch @@ -0,0 +1,71 @@ +From 8c9958524684c89821eb179c37be4d4fcb30a45e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 14:16:45 +0800 +Subject: hwmon: (ads7828) Fix external VREF regulator handling + +From: Qingshuang Fu + +[ 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 +Link: https://lore.kernel.org/r/20260805061645.1331652-1-fffsqian@163.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch b/queue-7.1/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch new file mode 100644 index 0000000000..379a612e1d --- /dev/null +++ b/queue-7.1/hwmon-corsair-psu-fix-possible-out-of-bounds-access-.patch @@ -0,0 +1,50 @@ +From 6a0da1d266bd488945ea7838ee5e32f5f34a9fe1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://lore.kernel.org/r/anLj9gPWRoRDbQBV@monster.localdomain +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/hwmon-corsair-psu-serialize-debugfs-access-against-h.patch b/queue-7.1/hwmon-corsair-psu-serialize-debugfs-access-against-h.patch new file mode 100644 index 0000000000..81b449fb42 --- /dev/null +++ b/queue-7.1/hwmon-corsair-psu-serialize-debugfs-access-against-h.patch @@ -0,0 +1,71 @@ +From 3c8acb662062397d0076ba27c2a1d697dc426736 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Aug 2026 14:21:39 +0000 +Subject: hwmon: (corsair-psu) serialize debugfs access against hwmon + +From: Ali Ahmet Memis + +[ 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 +Tested-by: Wilken Gottwalt +Link: https://lore.kernel.org/r/20260806142139.168611-1-ali@iusegentoo.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/hwmon-ltc4282-avoid-overflow-in-maximum-power-calcul.patch b/queue-7.1/hwmon-ltc4282-avoid-overflow-in-maximum-power-calcul.patch new file mode 100644 index 0000000000..7712d49bff --- /dev/null +++ b/queue-7.1/hwmon-ltc4282-avoid-overflow-in-maximum-power-calcul.patch @@ -0,0 +1,105 @@ +From 45bab68cd045244b4315e082cc3391f2e00e3bb8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282") +Cc: Nuno Sa +Reviewed-by: Nuno Sá +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/hwmon-ltc4282-clamp-negative-current-limits.patch b/queue-7.1/hwmon-ltc4282-clamp-negative-current-limits.patch new file mode 100644 index 0000000000..de4d1c62ee --- /dev/null +++ b/queue-7.1/hwmon-ltc4282-clamp-negative-current-limits.patch @@ -0,0 +1,69 @@ +From 408cdd6a05775fb38cdb009b69641c8867c24498 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282") +Cc: Nuno Sa +Reviewed-by: Nuno Sá +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 + diff --git a/queue-7.1/hwmon-ltc4282-fix-parsing-adi-current-limit-sense-mi.patch b/queue-7.1/hwmon-ltc4282-fix-parsing-adi-current-limit-sense-mi.patch new file mode 100644 index 0000000000..37fc772e6b --- /dev/null +++ b/queue-7.1/hwmon-ltc4282-fix-parsing-adi-current-limit-sense-mi.patch @@ -0,0 +1,68 @@ +From ebb36540dfed859270a95ef9bd73784b91ca7b9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Fixes: cbc29538dbf7d ("hwmon: Add driver for LTC4282") +Cc: Nuno Sa +Reviewed-by: Nuno Sá +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/hwmon-nzxt-smart2-check-return-value-of-init_device-.patch b/queue-7.1/hwmon-nzxt-smart2-check-return-value-of-init_device-.patch new file mode 100644 index 0000000000..4d1f500e6f --- /dev/null +++ b/queue-7.1/hwmon-nzxt-smart2-check-return-value-of-init_device-.patch @@ -0,0 +1,57 @@ +From 6d49b2cdae7eec6bd485853063f0b04c3be3e0ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 15:48:42 +0800 +Subject: hwmon: (nzxt-smart2) Check return value of init_device() in probe + +From: Qingshuang Fu + +[ 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 +Link: https://lore.kernel.org/r/20260804074842.505923-1-fffsqian@163.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/hwmon-pmbus-core-avoid-race-condition-during-probe.patch b/queue-7.1/hwmon-pmbus-core-avoid-race-condition-during-probe.patch new file mode 100644 index 0000000000..63504e044e --- /dev/null +++ b/queue-7.1/hwmon-pmbus-core-avoid-race-condition-during-probe.patch @@ -0,0 +1,51 @@ +From 3a88d6a66279be50634c6680587234b77332b75b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 11:40:50 -0700 +Subject: hwmon: (pmbus/core) Avoid race condition during probe + +From: Guenter Roeck + +[ 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 +Fixes: 221819ca4c36e ("hwmon: (pmbus/core) Add interrupt support") +Fixes: 1e069dfd96dfe ("hwmon: (pmbus) Add debugfs for status registers") +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/hwmon-pmbus-fix-type-confusion-in-notification-logic.patch b/queue-7.1/hwmon-pmbus-fix-type-confusion-in-notification-logic.patch new file mode 100644 index 0000000000..9e9268085c --- /dev/null +++ b/queue-7.1/hwmon-pmbus-fix-type-confusion-in-notification-logic.patch @@ -0,0 +1,234 @@ +From a6a7b662b6e5bfbcc3ca78d66da230ff8e2bd035 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jul 2026 10:57:35 -0700 +Subject: hwmon: (pmbus) Fix type confusion in notification logic + +From: Guenter Roeck + +[ 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 +Tested-by: Vincent Jardin +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch b/queue-7.1/hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch new file mode 100644 index 0000000000..1157e8e9f2 --- /dev/null +++ b/queue-7.1/hwmon-pmbus-lm25066-fix-pmbus-coefficient-calculatio.patch @@ -0,0 +1,71 @@ +From 1dca2ccd6013ea578be70772580511241eadd1af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 14:12:31 -0700 +Subject: hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations + +From: Guenter Roeck + +[ 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 +Fixes: 94ee5fcc240fe ("hwmon: (pmbus/lm25066) Support configurable sense resistor values") +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + #include + #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 + diff --git a/queue-7.1/hwmon-support-guard-and-scoped_guard-for-subsystem-l.patch b/queue-7.1/hwmon-support-guard-and-scoped_guard-for-subsystem-l.patch new file mode 100644 index 0000000000..8761c21d28 --- /dev/null +++ b/queue-7.1/hwmon-support-guard-and-scoped_guard-for-subsystem-l.patch @@ -0,0 +1,62 @@ +From 768cc92123fd5d3f3d58f988224b1eef0fad0c4b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 07:14:33 -0700 +Subject: hwmon: Support guard() and scoped_guard for subsystem locks + +From: Guenter Roeck + +[ Upstream commit d1e720c7328e046049b792d03fae093d4d3a72e4 ] + +Add support for guard() and scoped_guard() for the hwmon subsystem lock +to simplify its use. + +Signed-off-by: Guenter Roeck +Stable-dep-of: 2da6050809d4 ("hwmon: (corsair-psu) serialize debugfs access against hwmon") +Signed-off-by: Sasha Levin +--- + 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 ++#include + + 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 + diff --git a/queue-7.1/ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch b/queue-7.1/ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch new file mode 100644 index 0000000000..2942ed197a --- /dev/null +++ b/queue-7.1/ipvs-avoid-out-of-bounds-write-in-ip_vs_nat_icmp.patch @@ -0,0 +1,259 @@ +From ec87973180f65d920783cd2ffa28310218446cf6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 21:35:05 +0300 +Subject: ipvs: avoid out-of-bounds write in ip_vs_nat_icmp + +From: Julian Anastasov + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/ipvs-return-the-csum-validation-for-forward-hook.patch b/queue-7.1/ipvs-return-the-csum-validation-for-forward-hook.patch new file mode 100644 index 0000000000..1c97bd5a33 --- /dev/null +++ b/queue-7.1/ipvs-return-the-csum-validation-for-forward-hook.patch @@ -0,0 +1,100 @@ +From 3ba9ebe662d19910af31d6872e54516f1b223609 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 21:35:06 +0300 +Subject: ipvs: return the csum validation for forward hook + +From: Julian Anastasov + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 /* for union nf_inet_addr */ + #include + #include /* for struct ipv6hdr */ +-#include + #include +-#include + #if IS_ENABLED(CONFIG_NF_CONNTRACK) + #include + #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 + diff --git a/queue-7.1/net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch b/queue-7.1/net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch new file mode 100644 index 0000000000..5488736a19 --- /dev/null +++ b/queue-7.1/net-atm-fix-slab-out-of-bounds-read-in-vcc_setsockop.patch @@ -0,0 +1,81 @@ +From 049a92d550a4238c596a4ed1aabf7373bb04aa4d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 13:15:08 +0000 +Subject: net/atm: fix slab-out-of-bounds read in vcc_setsockopt() + +From: Eric Dumazet + +[ 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 +Link: https://patch.msgid.link/20260805131508.3227331-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch b/queue-7.1/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch new file mode 100644 index 0000000000..7f5639c678 --- /dev/null +++ b/queue-7.1/net-hisilicon-hix5hd2_gmac-remove-redundant-napi-del.patch @@ -0,0 +1,42 @@ +From aa3622d8e3550cb1d0ca6b9290569c19e5accdf0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-hns3-fix-speed-configuration-residue-after-drive.patch b/queue-7.1/net-hns3-fix-speed-configuration-residue-after-drive.patch new file mode 100644 index 0000000000..a86ee5521f --- /dev/null +++ b/queue-7.1/net-hns3-fix-speed-configuration-residue-after-drive.patch @@ -0,0 +1,76 @@ +From 13138e0e7ccc96a785d45716599e0baabf7ea920 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 17:30:36 +0800 +Subject: net: hns3: fix speed configuration residue after driver reload + +From: Jijie Shao + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260724093036.426631-1-shaojijie@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-mlx5-fw_tracer-return-null-on-create-error.patch b/queue-7.1/net-mlx5-fw_tracer-return-null-on-create-error.patch new file mode 100644 index 0000000000..91942ae7f0 --- /dev/null +++ b/queue-7.1/net-mlx5-fw_tracer-return-null-on-create-error.patch @@ -0,0 +1,134 @@ +From 30e50e8a071d0e7283008fafb6f87a9b841fdbc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 11:04:02 +0300 +Subject: net/mlx5: fw_tracer, return NULL on create error + +From: Michael Guralnik + +[ 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 +Reviewed-by: Shay Drori +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260729080402.2427184-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-7.1/net-mlx5e-fix-bql-reset-on-sq-re-activation.patch b/queue-7.1/net-mlx5e-fix-bql-reset-on-sq-re-activation.patch new file mode 100644 index 0000000000..dad92472f1 --- /dev/null +++ b/queue-7.1/net-mlx5e-fix-bql-reset-on-sq-re-activation.patch @@ -0,0 +1,58 @@ +From ecccff705f2c3e7808414aefe779e6b5b20db02b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 16:47:29 -0700 +Subject: net/mlx5e: fix BQL reset on SQ re-activation + +From: Bobby Eshleman + +[ 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: + + 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 +Reviewed-by: Tariq Toukan +Link: https://patch.msgid.link/20260803-mlx5-bql-v3-1-a30d4c66fe1d@meta.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch b/queue-7.1/net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch new file mode 100644 index 0000000000..d8ad8bdc33 --- /dev/null +++ b/queue-7.1/net-mlx5e-tc-check-if-flow-is-peer-before-acquiring-.patch @@ -0,0 +1,100 @@ +From 169d11155baa196ab37a3cf65cd959be90365c7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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 + + +Fixes: 04de7dda7394 ("net/mlx5e: Infrastructure for duplicated offloading of TC flows") +Signed-off-by: Shay Drory +Reviewed-by: Cosmin Ratiu +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260728044338.2271143-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch b/queue-7.1/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch new file mode 100644 index 0000000000..f6d27d31db --- /dev/null +++ b/queue-7.1/net-ncsi-fix-heap-oob-read-in-ncsi_cmd_send_cmd-payl.patch @@ -0,0 +1,60 @@ +From 9749bd46332b48554dead722d8c087cff5d127c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Henry Martin +Link: https://patch.msgid.link/20260803043618.3210301-1-bsdhenrymartin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-openvswitch-check-ethernet-header-length-in-key_.patch b/queue-7.1/net-openvswitch-check-ethernet-header-length-in-key_.patch new file mode 100644 index 0000000000..6ec715c251 --- /dev/null +++ b/queue-7.1/net-openvswitch-check-ethernet-header-length-in-key_.patch @@ -0,0 +1,78 @@ +From ec5380945f2ebfe6b5877cd547217640449a3228 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 18:20:06 -0400 +Subject: net/openvswitch: check Ethernet header length in key_extract() + +From: Cen Zhang (Microsoft) + +[ 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 +Signed-off-by: Cen Zhang (Microsoft) +Reviewed-by: Ilya Maximets +Link: https://patch.msgid.link/20260730222006.118652-1-blbllhy@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-prestera-validate-firmware-header-length.patch b/queue-7.1/net-prestera-validate-firmware-header-length.patch new file mode 100644 index 0000000000..3bcc68e2b5 --- /dev/null +++ b/queue-7.1/net-prestera-validate-firmware-header-length.patch @@ -0,0 +1,42 @@ +From 4960ebb48afafc02410597756b261d6526305133 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 22:19:06 +0800 +Subject: net: prestera: validate firmware header length + +From: Pengpeng Hou + +[ 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 +Acked-by: Elad Nachman +Link: https://patch.msgid.link/20260731141500.1-prestera-v2-pengpeng@iscas.ac.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-qrtr-ns-raise-lookup-limit-to-128.patch b/queue-7.1/net-qrtr-ns-raise-lookup-limit-to-128.patch new file mode 100644 index 0000000000..36afd44b96 --- /dev/null +++ b/queue-7.1/net-qrtr-ns-raise-lookup-limit-to-128.patch @@ -0,0 +1,51 @@ +From 1eded2c917d84ec894633ae4e06fe12542acfa6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/20260804201919.1148015-1-priv.luk@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-remove-warn_on_once-from-sk_mc_loop.patch b/queue-7.1/net-remove-warn_on_once-from-sk_mc_loop.patch new file mode 100644 index 0000000000..5c364e7c50 --- /dev/null +++ b/queue-7.1/net-remove-warn_on_once-from-sk_mc_loop.patch @@ -0,0 +1,45 @@ +From 8d03a9d59e6587f199494059edf3527c1ecb4281 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 15:20:48 +0000 +Subject: net: remove WARN_ON_ONCE() from sk_mc_loop() + +From: Eric Dumazet + +[ 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 +Link: https://patch.msgid.link/20260804152048.2134341-1-edumazet@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch b/queue-7.1/net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch new file mode 100644 index 0000000000..7cab59c0df --- /dev/null +++ b/queue-7.1/net-sched-cls_api-always-acquire-rtnl_lock-when-dest.patch @@ -0,0 +1,116 @@ +From ee943a757bb754d3eec26d4d2ebe32773b706415 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Tested-by: Victor Nogueira +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260801125632.360365-1-jhs@mojatatu.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch b/queue-7.1/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch new file mode 100644 index 0000000000..8026fae565 --- /dev/null +++ b/queue-7.1/net-sched-cls_route-fix-fastmap-use-after-free-on-fi.patch @@ -0,0 +1,142 @@ +From 2259bde902cae4fac469ed19b559baf2e6509bf4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Suggested-by: Paolo Abeni +Tested-by: Victor Nogueira +Tested-by: Santosh Kalluri +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260729094411.46257-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch b/queue-7.1/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch new file mode 100644 index 0000000000..b9a6c81363 --- /dev/null +++ b/queue-7.1/net-sched-sch_cake-drop-warn_on-1-for-malformed-pack.patch @@ -0,0 +1,50 @@ +From aef9fc0afb86114783e6f60c76c7330ea59b6ec3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reported-by: Ren Wei +Signed-off-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260729191417.45665-1-toke@toke.dk +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch b/queue-7.1/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch new file mode 100644 index 0000000000..c7589a915c --- /dev/null +++ b/queue-7.1/net-smc-fix-qentry-overwrite-for-confirm_link-and-ad.patch @@ -0,0 +1,57 @@ +From a24c997bfac0ab87cf2fb25c57c2a6a350619482 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Hidayath Khan +Reviewed-by: Sidraya Jayagond +Reviewed-by: Dust Li +Link: https://patch.msgid.link/20260729130153.970800-1-mjambigi@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch b/queue-7.1/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch new file mode 100644 index 0000000000..c35f3f49f4 --- /dev/null +++ b/queue-7.1/net-smc-fix-toctou-race-between-smc_listen_out-and-l.patch @@ -0,0 +1,71 @@ +From 9b5b62d248d46973973c30491047e09b4e2c4e44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Sidraya Jayagond +Reviewed-by: Breno Leitao +Reviewed-by: Dust Li +Link: https://patch.msgid.link/20260803070701.126339-1-sidraya@linux.ibm.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-stmmac-resume-phy-before-hardware-setup-when-ope.patch b/queue-7.1/net-stmmac-resume-phy-before-hardware-setup-when-ope.patch new file mode 100644 index 0000000000..8d80b1dcf2 --- /dev/null +++ b/queue-7.1/net-stmmac-resume-phy-before-hardware-setup-when-ope.patch @@ -0,0 +1,79 @@ +From 864caafd74b5177920c7d255f952d787166475b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 11:51:56 +0200 +Subject: net: stmmac: resume PHY before hardware setup when opening the + interface + +From: Stefan Agner + +[ 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 +Signed-off-by: Stefan Agner +Tested-by: Maxime Chevallier +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260803095156.132827-1-stefan@agner.ch +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch b/queue-7.1/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch new file mode 100644 index 0000000000..abfa014345 --- /dev/null +++ b/queue-7.1/net-thunderbolt-tear-down-dma-paths-before-stopping-.patch @@ -0,0 +1,117 @@ +From f6cef5121c15efac07e50e2bc3bcdd99740bb8e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 14:38:50 +0000 +Subject: net: thunderbolt: Tear down DMA paths before stopping the rings + +From: Fan XinRan + +[ 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 +Acked-by: Mika Westerberg +Link: https://patch.msgid.link/20260803-b4-tbnet-teardown-v2-1-27de6a13ca2d@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/netfilter-ipset-switch-ext_size-to-atomic64_t.patch b/queue-7.1/netfilter-ipset-switch-ext_size-to-atomic64_t.patch new file mode 100644 index 0000000000..54e1d6586f --- /dev/null +++ b/queue-7.1/netfilter-ipset-switch-ext_size-to-atomic64_t.patch @@ -0,0 +1,134 @@ +From 2ab0a5f88709cd8032896e9952f0b3ee7b223f17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 20:38:50 +0200 +Subject: netfilter: ipset: switch ext_size to atomic64_t + +From: Jozsef Kadlecsik + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/ipset/ip_set.h | 2 +- + net/netfilter/ipset/ip_set_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 + diff --git a/queue-7.1/netfilter-nf_flow_table-drop-existing-skb-dst-before.patch b/queue-7.1/netfilter-nf_flow_table-drop-existing-skb-dst-before.patch new file mode 100644 index 0000000000..ef4a75ba06 --- /dev/null +++ b/queue-7.1/netfilter-nf_flow_table-drop-existing-skb-dst-before.patch @@ -0,0 +1,69 @@ +From b5ebd4fc676c67f1e80fe03cfcf0836179695c00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Pablo Neira Ayuso +Link: https://patch.msgid.link/20260804093328.1831847-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/nfs-decrement-refcounts-if-allocating-nfs_free_state.patch b/queue-7.1/nfs-decrement-refcounts-if-allocating-nfs_free_state.patch new file mode 100644 index 0000000000..83548b2400 --- /dev/null +++ b/queue-7.1/nfs-decrement-refcounts-if-allocating-nfs_free_state.patch @@ -0,0 +1,70 @@ +From 557122a1aabb258ed59ba1081371c35506308d86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Jun 2026 15:39:45 -0400 +Subject: NFS: Decrement refcounts if allocating nfs_free_stateid_data fails + +From: Anna Schumaker + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch b/queue-7.1/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch new file mode 100644 index 0000000000..f870c86125 --- /dev/null +++ b/queue-7.1/nfs-pin-the-struct-nfs_server-during-a-free_stateid-.patch @@ -0,0 +1,50 @@ +From f85aa6110cf116d3a602a9a605740ba8a021c012 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Jun 2026 14:31:00 -0400 +Subject: NFS: Pin the 'struct nfs_server' during a FREE_STATEID call + +From: Anna Schumaker + +[ 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 +Fixes: 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call") +Tested-by: Dan Aloni +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/ovpn-add-missing-rtnl_link_ops-get_size-callback.patch b/queue-7.1/ovpn-add-missing-rtnl_link_ops-get_size-callback.patch new file mode 100644 index 0000000000..296e981247 --- /dev/null +++ b/queue-7.1/ovpn-add-missing-rtnl_link_ops-get_size-callback.patch @@ -0,0 +1,56 @@ +From 0c7b865a1c9176fd8aa9f6d2379cc48b28cbaf5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 15:41:30 +0200 +Subject: ovpn: add missing rtnl_link_ops->get_size callback + +From: Ralf Lici + +[ 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 +Signed-off-by: Antonio Quartulli +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/ovpn-disable-ipv4-redirects-on-mp-interfaces.patch b/queue-7.1/ovpn-disable-ipv4-redirects-on-mp-interfaces.patch new file mode 100644 index 0000000000..816d2ac989 --- /dev/null +++ b/queue-7.1/ovpn-disable-ipv4-redirects-on-mp-interfaces.patch @@ -0,0 +1,130 @@ +From 82be98162c3adc0e61c050372f13cd9ac88f819a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 13:48:53 +0200 +Subject: ovpn: disable IPv4 redirects on MP interfaces + +From: Antonio Quartulli + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/ovpn-ensure-socket-is-owned-by-ovpn-before-deref-sk_.patch b/queue-7.1/ovpn-ensure-socket-is-owned-by-ovpn-before-deref-sk_.patch new file mode 100644 index 0000000000..e66d8bd049 --- /dev/null +++ b/queue-7.1/ovpn-ensure-socket-is-owned-by-ovpn-before-deref-sk_.patch @@ -0,0 +1,47 @@ +From 2bc6639f6aedc0298d99cee731f177e9d59c4842 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/ovpn-ensure-tcp-vars-are-initialized-first.patch b/queue-7.1/ovpn-ensure-tcp-vars-are-initialized-first.patch new file mode 100644 index 0000000000..777ba8afb5 --- /dev/null +++ b/queue-7.1/ovpn-ensure-tcp-vars-are-initialized-first.patch @@ -0,0 +1,52 @@ +From efa66673615423e554e6863afc30577aedeef384 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 13:48:54 +0200 +Subject: ovpn: ensure TCP vars are initialized first + +From: Antonio Quartulli + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/ovpn-fix-incorrect-use-of-rcu_access_pointer.patch b/queue-7.1/ovpn-fix-incorrect-use-of-rcu_access_pointer.patch new file mode 100644 index 0000000000..3d0f6d5f07 --- /dev/null +++ b/queue-7.1/ovpn-fix-incorrect-use-of-rcu_access_pointer.patch @@ -0,0 +1,37 @@ +From fe27bda44071c62e5cc36dceccd4924bda6029c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 09:49:26 +0800 +Subject: ovpn: fix incorrect use of rcu_access_pointer() + +From: Qingfang Deng + +[ 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 +Signed-off-by: Antonio Quartulli +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/ovpn-hash-floated-peer-by-transport-identity-only.patch b/queue-7.1/ovpn-hash-floated-peer-by-transport-identity-only.patch new file mode 100644 index 0000000000..2cf091313f --- /dev/null +++ b/queue-7.1/ovpn-hash-floated-peer-by-transport-identity-only.patch @@ -0,0 +1,94 @@ +From f00e6d56b80aa65b348f37f53a4d7f2f600cc304 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 13:48:52 +0200 +Subject: ovpn: hash floated peer by transport identity only + +From: Antonio Quartulli + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/ovpn-rehash-peer-in-by_transp_addr-table-on-cmd_peer.patch b/queue-7.1/ovpn-rehash-peer-in-by_transp_addr-table-on-cmd_peer.patch new file mode 100644 index 0000000000..b8b53ecd98 --- /dev/null +++ b/queue-7.1/ovpn-rehash-peer-in-by_transp_addr-table-on-cmd_peer.patch @@ -0,0 +1,215 @@ +From 85fef0824e3cabf31500f5a1f066ab99b08c366e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/ovpn-skip-rehash-for-peers-already-removed-from-by_i.patch b/queue-7.1/ovpn-skip-rehash-for-peers-already-removed-from-by_i.patch new file mode 100644 index 0000000000..13147f6a98 --- /dev/null +++ b/queue-7.1/ovpn-skip-rehash-for-peers-already-removed-from-by_i.patch @@ -0,0 +1,142 @@ +From aeeed7a742d1a79b21e9ac45083e673c27ab54a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 13:48:47 +0200 +Subject: ovpn: skip rehash for peers already removed from by_id + +From: Antonio Quartulli + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/ovpn-zero-initialize-sockaddr-before-learning-a-floa.patch b/queue-7.1/ovpn-zero-initialize-sockaddr-before-learning-a-floa.patch new file mode 100644 index 0000000000..796ceea451 --- /dev/null +++ b/queue-7.1/ovpn-zero-initialize-sockaddr-before-learning-a-floa.patch @@ -0,0 +1,91 @@ +From 80a4f313e8aa5bfcef0f12c1e142086e8836360a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 13:48:51 +0200 +Subject: ovpn: zero-initialize sockaddr before learning a floated endpoint + +From: Antonio Quartulli + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/pds_core-cancel-pending-pci-reset-work-on-aer-recove.patch b/queue-7.1/pds_core-cancel-pending-pci-reset-work-on-aer-recove.patch new file mode 100644 index 0000000000..bfb72118a0 --- /dev/null +++ b/queue-7.1/pds_core-cancel-pending-pci-reset-work-on-aer-recove.patch @@ -0,0 +1,54 @@ +From b462af1aa7f44fc725c572081a16bb20dee6fea8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 17:00:30 +0000 +Subject: pds_core: cancel pending PCI reset work on AER recovery + +From: Nikhil P. Rao + +[ 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 +Closes: https://sashiko.dev/#/patchset/20260714180223.1642792-2-nikhil.rao%40amd.com?part=1 +Signed-off-by: Nikhil P. Rao +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260727170030.361116-1-nikhil.rao@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/pds_core-keep-the-health-thread-stopped-during-reset.patch b/queue-7.1/pds_core-keep-the-health-thread-stopped-during-reset.patch new file mode 100644 index 0000000000..5520c95e5a --- /dev/null +++ b/queue-7.1/pds_core-keep-the-health-thread-stopped-during-reset.patch @@ -0,0 +1,87 @@ +From b0f915f0818741151987d71cf761bebb6e8c0239 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 16:45:48 +0000 +Subject: pds_core: keep the health thread stopped during reset + +From: Nikhil P. Rao + +[ 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 +Closes: https://sashiko.dev/#/patchset/20260629200358.2626129-1-nikhil.rao%40amd.com?part=2 +Signed-off-by: Nikhil P. Rao +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260727164548.359562-1-nikhil.rao@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/pinctrl-qcom-ipq806x-mark-gpio-as-a-gpio-pin-functio.patch b/queue-7.1/pinctrl-qcom-ipq806x-mark-gpio-as-a-gpio-pin-functio.patch new file mode 100644 index 0000000000..d9be45acc3 --- /dev/null +++ b/queue-7.1/pinctrl-qcom-ipq806x-mark-gpio-as-a-gpio-pin-functio.patch @@ -0,0 +1,65 @@ +From b4d17a8ada124c01cd0617551f2dd4282f78b0a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Jul 2026 15:35:59 +0200 +Subject: pinctrl: qcom: ipq806x: mark gpio as a GPIO pin function + +From: Hans Ulli Kroll + +[ 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 +Acked-by: Linus Walleij +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260719134548.8830-2-linux@ulli-kroll.de +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/pinctrl-qcom-ipq806x-mark-pci-reset-as-a-gpio-pin-fu.patch b/queue-7.1/pinctrl-qcom-ipq806x-mark-pci-reset-as-a-gpio-pin-fu.patch new file mode 100644 index 0000000000..17e7f1f981 --- /dev/null +++ b/queue-7.1/pinctrl-qcom-ipq806x-mark-pci-reset-as-a-gpio-pin-fu.patch @@ -0,0 +1,59 @@ +From 73e15c389e891e5018de4fb0f49fdfc27e0973d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Acked-by: Linus Walleij +Reviewed-by: Dmitry Baryshkov +Link: https://patch.msgid.link/20260719134548.8830-3-linux@ulli-kroll.de +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/revert-net-thunderbolt-enable-end-to-end-flow-contro.patch b/queue-7.1/revert-net-thunderbolt-enable-end-to-end-flow-contro.patch new file mode 100644 index 0000000000..1a52cfef86 --- /dev/null +++ b/queue-7.1/revert-net-thunderbolt-enable-end-to-end-flow-contro.patch @@ -0,0 +1,104 @@ +From 5b1f3dadd797ec074509336fe303b885d9ce408b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Fan Ye +Acked-by: Mika Westerberg +Link: https://patch.msgid.link/20260727123002.25225-1-fy15309206903@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/rqspinlock-reset-tail-when-preserving-queue-on-deadl.patch b/queue-7.1/rqspinlock-reset-tail-when-preserving-queue-on-deadl.patch new file mode 100644 index 0000000000..01cee3929a --- /dev/null +++ b/queue-7.1/rqspinlock-reset-tail-when-preserving-queue-on-deadl.patch @@ -0,0 +1,79 @@ +From 53d5e5122b58473e86d6f82e7025453716b89416 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 2 Aug 2026 04:17:59 +0200 +Subject: rqspinlock: Reset tail when preserving queue on deadlock + +From: Kumar Kartikeya Dwivedi + +[ 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 +Link: https://patch.msgid.link/20260802021759.1139457-1-memxor@gmail.com +Signed-off-by: Eduard Zingerman +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/s390-ism-fix-uaf-of-sba-and-ieq-during-ism_dev_exit.patch b/queue-7.1/s390-ism-fix-uaf-of-sba-and-ieq-during-ism_dev_exit.patch new file mode 100644 index 0000000000..a92a66f204 --- /dev/null +++ b/queue-7.1/s390-ism-fix-uaf-of-sba-and-ieq-during-ism_dev_exit.patch @@ -0,0 +1,91 @@ +From 23a6b7cee9620038e6028c2d6405e7551c61dfc6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/20260805131043.954639-1-wintera@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/sched_ext-don-t-enable-non-ext-tasks-in-the-sub-sche.patch b/queue-7.1/sched_ext-don-t-enable-non-ext-tasks-in-the-sub-sche.patch new file mode 100644 index 0000000000..dae3f90b2d --- /dev/null +++ b/queue-7.1/sched_ext-don-t-enable-non-ext-tasks-in-the-sub-sche.patch @@ -0,0 +1,78 @@ +From f99376625f6f292c30273fc82ce962304a0a98bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Andrea Righi +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/sched_ext-reject-setting-disallow-from-init_task-out.patch b/queue-7.1/sched_ext-reject-setting-disallow-from-init_task-out.patch new file mode 100644 index 0000000000..54dae461ec --- /dev/null +++ b/queue-7.1/sched_ext-reject-setting-disallow-from-init_task-out.patch @@ -0,0 +1,68 @@ +From e2f65dca5fd02e1bbf7843524aacc321c183a79d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Andrea Righi +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/sched_ext-skip-sub-disable-teardown-for-never-linked.patch b/queue-7.1/sched_ext-skip-sub-disable-teardown-for-never-linked.patch new file mode 100644 index 0000000000..96c651d46d --- /dev/null +++ b/queue-7.1/sched_ext-skip-sub-disable-teardown-for-never-linked.patch @@ -0,0 +1,77 @@ +From f73aa863b764f0a96a9ccb1709bb7972990be1ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 10:45:23 -1000 +Subject: sched_ext: Skip sub-disable teardown for never-linked sub-schedulers + +From: Tejun Heo + +[ 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 +Reviewed-by: Andrea Righi +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/sctp-clear-control-chunk-transport-if-it-is-being-re.patch b/queue-7.1/sctp-clear-control-chunk-transport-if-it-is-being-re.patch new file mode 100644 index 0000000000..a77d292e29 --- /dev/null +++ b/queue-7.1/sctp-clear-control-chunk-transport-if-it-is-being-re.patch @@ -0,0 +1,54 @@ +From 27081d1fb3c26192eb545857097e8b348148766d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 11:18:40 -0400 +Subject: sctp: clear control chunk transport if it is being removed + +From: Xin Long + +[ 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 +Signed-off-by: Xin Long +Link: https://patch.msgid.link/7e1168cb722132152a29d47e5eafaeac4a3bf6f3.1785943120.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch b/queue-7.1/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch new file mode 100644 index 0000000000..0b6007002b --- /dev/null +++ b/queue-7.1/sctp-fix-addip_serial-increment-on-asconf_ack-alloca.patch @@ -0,0 +1,57 @@ +From 25c5edb238d768d240ce7d4f4fb15a63b5b4f4c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 10:55:14 +0800 +Subject: sctp: fix addip_serial increment on ASCONF_ACK allocation failure + +From: Qing Luo + +[ 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 +Acked-by: Xin Long +Link: https://patch.msgid.link/20260804025514.241767-1-l1138897701@163.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch b/queue-7.1/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch new file mode 100644 index 0000000000..5802e90d88 --- /dev/null +++ b/queue-7.1/selftests-ftrace-refactor-eprobes-test-to-fix-argume.patch @@ -0,0 +1,88 @@ +From e7fb5a399860559dfdf9e848b54219e4f3db6ecd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 21:46:35 +0200 +Subject: selftests/ftrace: refactor eprobes test to fix argument checks + +From: Martin Kaiser + +[ 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 " 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 +Closes: https://lore.kernel.org/oe-lkp/202607151010.b68428e1-lkp@intel.com +Signed-off-by: Martin Kaiser +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + .../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 ". []":README ++# requires: dynamic_events events/syscalls/sys_enter_chdir ". []":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 + diff --git a/queue-7.1/selftests-sched_ext-handle-sleeping-task-affinity-ch.patch b/queue-7.1/selftests-sched_ext-handle-sleeping-task-affinity-ch.patch new file mode 100644 index 0000000000..b62b276592 --- /dev/null +++ b/queue-7.1/selftests-sched_ext-handle-sleeping-task-affinity-ch.patch @@ -0,0 +1,81 @@ +From 0ada57190ae36b4a2ed98f85d13d52fbe4c085f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jul 2026 09:59:55 +0000 +Subject: selftests/sched_ext: Handle sleeping task affinity changes in numa + test + +From: Kuba Piecuch + +[ 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 +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/series b/queue-7.1/series index e69ca3316b..3cd5226c02 100644 --- a/queue-7.1/series +++ b/queue-7.1/series @@ -4,3 +4,122 @@ selftests-bpf-add-tests-for-sleepable-tracepoint-pro.patch 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 diff --git a/queue-7.1/soc-aspeed-lpc-snoop-fix-usercopy-overflow-in-snoop_.patch b/queue-7.1/soc-aspeed-lpc-snoop-fix-usercopy-overflow-in-snoop_.patch new file mode 100644 index 0000000000..7ab45ad1dd --- /dev/null +++ b/queue-7.1/soc-aspeed-lpc-snoop-fix-usercopy-overflow-in-snoop_.patch @@ -0,0 +1,139 @@ +From 893957595ada0b0557f3cb1fde74cfe8764e6041 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 12 Jun 2026 19:07:43 +0000 +Subject: soc: aspeed: lpc-snoop: Fix usercopy overflow in snoop_file_read + +From: Karthikeyan KS + +[ 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 +Signed-off-by: Andrew Jeffery +Signed-off-by: Sasha Levin +--- + 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 ++#include + #include + #include + #include +@@ -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 + diff --git a/queue-7.1/tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch b/queue-7.1/tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch new file mode 100644 index 0000000000..4b146ccd20 --- /dev/null +++ b/queue-7.1/tcp-do-not-change-rcv_ssthresh-in-tcp_measure_rcv_ms.patch @@ -0,0 +1,61 @@ +From c0319886e76a9d831c14a9f2b602e99046babf0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 20:08:06 -0700 +Subject: tcp: do not change rcv_ssthresh in tcp_measure_rcv_mss() + +From: Nathan Gao + +[ 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 +Link: https://patch.msgid.link/20260725030806.28135-1-zcgao@amazon.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch b/queue-7.1/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch new file mode 100644 index 0000000000..57a8879cc8 --- /dev/null +++ b/queue-7.1/tcp-fix-tfo-max_qlen-accounting-across-reuseport-mig.patch @@ -0,0 +1,72 @@ +From f3ba535f5118933506bcc2198a4dc0d2286eb1a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Aug 2026 14:17:38 +0800 +Subject: tcp: fix TFO max_qlen accounting across reuseport migration + +From: Jiayuan Chen + +[ 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 +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260803061739.134737-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/tls-don-t-abort-the-connection-on-signal-interrupted.patch b/queue-7.1/tls-don-t-abort-the-connection-on-signal-interrupted.patch new file mode 100644 index 0000000000..5770e88d53 --- /dev/null +++ b/queue-7.1/tls-don-t-abort-the-connection-on-signal-interrupted.patch @@ -0,0 +1,45 @@ +From 9d0a48e0d834347f3e32ec1af19476bdf8ed47e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Aug 2026 08:22:48 +0200 +Subject: tls: don't abort the connection on signal-interrupted sends + +From: Maximilian Immanuel Brandtner + +[ 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 +Link: https://patch.msgid.link/20260805063109.1772314-1-maxbr@linux.ibm.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch b/queue-7.1/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch new file mode 100644 index 0000000000..dbab0c3b18 --- /dev/null +++ b/queue-7.1/udp-fix-potential-use-after-free-in-tunnel-segmentat.patch @@ -0,0 +1,53 @@ +From 4d887cfb549136a384554092992fa1717cca2bca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Jul 2026 17:35:54 +0800 +Subject: udp: fix potential use-after-free in tunnel segmentation + +From: Xuanqiang Luo + +[ 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 +Reviewed-by: Antoine Tenart +Link: https://patch.msgid.link/20260730093554.68127-1-xuanqiang.luo@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/vdpa-mlx5-fix-buffer-length-in-create_direct_keys.patch b/queue-7.1/vdpa-mlx5-fix-buffer-length-in-create_direct_keys.patch new file mode 100644 index 0000000000..b7d8707ca4 --- /dev/null +++ b/queue-7.1/vdpa-mlx5-fix-buffer-length-in-create_direct_keys.patch @@ -0,0 +1,61 @@ +From 50bf7bb5aae5e875c8024d78aa49378684d33244 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Jul 2026 16:15:37 +0200 +Subject: vdpa/mlx5: Fix buffer length in create_direct_keys() + +From: Christian Borntraeger + +[ 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 +Tested-by: Dragos Tatulea +Reviewed-by: Dragos Tatulea +Signed-off-by: Michael S. Tsirkin +Message-ID: <20260706141537.3510294-1-borntraeger@linux.ibm.com> +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/vhost-scsi-reject-feature-changes-after-endpoint.patch b/queue-7.1/vhost-scsi-reject-feature-changes-after-endpoint.patch new file mode 100644 index 0000000000..c73469b439 --- /dev/null +++ b/queue-7.1/vhost-scsi-reject-feature-changes-after-endpoint.patch @@ -0,0 +1,102 @@ +From 41015a3d10237e553b63a38eb14decb24534cf9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Jul 2026 22:43:14 +0800 +Subject: vhost-scsi: reject feature changes after endpoint + +From: Jia Jia + +[ 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: + + ? __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 + + + 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 +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Michael S. Tsirkin +Message-ID: <20260726144314.1652934-1-physicalmtea@gmail.com> +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/vhost-scsi-validate-t10-pi-scatterlist-counts.patch b/queue-7.1/vhost-scsi-validate-t10-pi-scatterlist-counts.patch new file mode 100644 index 0000000000..09116f4c5d --- /dev/null +++ b/queue-7.1/vhost-scsi-validate-t10-pi-scatterlist-counts.patch @@ -0,0 +1,63 @@ +From cbac41a9e7cc85a5510128b6215d867dbe6460b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 16:18:41 +0800 +Subject: vhost-scsi: Validate T10 PI scatterlist counts + +From: Linfeng Sun + +[ 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 +Signed-off-by: Jia Jia +Assisted-by: OpenAI-Codex:GPT-5 +Signed-off-by: Linfeng Sun +Message-ID: <20260727081841.923151-1-slf@hdu.edu.cn> +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch b/queue-7.1/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch new file mode 100644 index 0000000000..246b92cf37 --- /dev/null +++ b/queue-7.1/vhost-vdpa-reject-overflowing-pa-map-page-counts-on-.patch @@ -0,0 +1,56 @@ +From e7db3f64447716fe57d50db75a68cca25e533410 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 15:02:02 -0700 +Subject: vhost/vdpa: reject overflowing PA map page counts on 32-bit + +From: Yousef Alhouseen + +[ 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 +Signed-off-by: Yousef Alhouseen +Signed-off-by: Michael S. Tsirkin +Message-ID: +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/vhost_iotlb-bound-map-allocation-in-add_range.patch b/queue-7.1/vhost_iotlb-bound-map-allocation-in-add_range.patch new file mode 100644 index 0000000000..9ec0ae5747 --- /dev/null +++ b/queue-7.1/vhost_iotlb-bound-map-allocation-in-add_range.patch @@ -0,0 +1,357 @@ +From 9cf7692bd15012285dfa28e3de0a11cb858a16b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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  + +[ 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  +Message-ID: +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Sasha Levin +--- + 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 + #include ++#include + #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 + #include + #include ++#include + #include + #include + + #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 + diff --git a/queue-7.1/watchdog-at91sam9_wdt-prevent-timer-rearm-during-tea.patch b/queue-7.1/watchdog-at91sam9_wdt-prevent-timer-rearm-during-tea.patch new file mode 100644 index 0000000000..bf652c8602 --- /dev/null +++ b/queue-7.1/watchdog-at91sam9_wdt-prevent-timer-rearm-during-tea.patch @@ -0,0 +1,51 @@ +From 24a2cf6f22ea340bd70f5c98847b2c8070fe8cce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Aug 2026 14:06:13 +0800 +Subject: watchdog: at91sam9_wdt: prevent timer rearm during teardown + +From: Hongyan Xu + +[ 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 +Link: https://lore.kernel.org/r/20260806060613.1830-1-getshell@seu.edu.cn +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/watchdog-bd96801_wdt-fix-timeout-for-enabled-wdg.patch b/queue-7.1/watchdog-bd96801_wdt-fix-timeout-for-enabled-wdg.patch new file mode 100644 index 0000000000..32856962a5 --- /dev/null +++ b/queue-7.1/watchdog-bd96801_wdt-fix-timeout-for-enabled-wdg.patch @@ -0,0 +1,68 @@ +From ab60f9ce8de021d0765590fb5369b71434ee7249 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 12:36:28 +0300 +Subject: watchdog: bd96801_wdt: Fix timeout for enabled WDG + +From: Matti Vaittinen + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/xfs-handle-null-b_addr-in-xfs_buf_free.patch b/queue-7.1/xfs-handle-null-b_addr-in-xfs_buf_free.patch new file mode 100644 index 0000000000..28e72d0b5a --- /dev/null +++ b/queue-7.1/xfs-handle-null-b_addr-in-xfs_buf_free.patch @@ -0,0 +1,53 @@ +From 16669aa609ee79d30b125ceda917bb883e1bc2b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Jul 2026 23:11:24 +0800 +Subject: xfs: handle NULL b_addr in xfs_buf_free + +From: Yun Zhou + +[ 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 +Reviewed-by: Christoph Hellwig +Signed-off-by: Carlos Maiolino +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/xsk-clear-metadata-pointer-when-no-timestamp-is-requ.patch b/queue-7.1/xsk-clear-metadata-pointer-when-no-timestamp-is-requ.patch new file mode 100644 index 0000000000..92f17134c8 --- /dev/null +++ b/queue-7.1/xsk-clear-metadata-pointer-when-no-timestamp-is-requ.patch @@ -0,0 +1,88 @@ +From d010e5c4b93c31a79f22e863510710c97a6966b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 09:19:56 -0700 +Subject: xsk: clear metadata pointer when no timestamp is requested + +From: Stanislav Fomichev + +[ 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) +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20260727161959.885642-4-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/xsk-move-xsk_tx_metadata_request-to-xdp_sock_drv.h.patch b/queue-7.1/xsk-move-xsk_tx_metadata_request-to-xdp_sock_drv.h.patch new file mode 100644 index 0000000000..02aed72646 --- /dev/null +++ b/queue-7.1/xsk-move-xsk_tx_metadata_request-to-xdp_sock_drv.h.patch @@ -0,0 +1,150 @@ +From c480ba05c7db88a29cdad6d2dcbaadacdb4273aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 09:19:58 -0700 +Subject: xsk: move xsk_tx_metadata_request() to xdp_sock_drv.h + +From: Stanislav Fomichev + +[ 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) +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20260727161959.885642-6-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/xsk-pass-tx-metadata-pointer-by-reference.patch b/queue-7.1/xsk-pass-tx-metadata-pointer-by-reference.patch new file mode 100644 index 0000000000..7efb30ea24 --- /dev/null +++ b/queue-7.1/xsk-pass-tx-metadata-pointer-by-reference.patch @@ -0,0 +1,203 @@ +From 6ff3a7f0577e000c708ced304c826656f6d57191 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 09:19:55 -0700 +Subject: xsk: pass TX metadata pointer by reference + +From: Stanislav Fomichev + +[ 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) +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20260727161959.885642-3-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/xsk-require-at-least-16-bytes-of-tx-metadata.patch b/queue-7.1/xsk-require-at-least-16-bytes-of-tx-metadata.patch new file mode 100644 index 0000000000..24d5e08a31 --- /dev/null +++ b/queue-7.1/xsk-require-at-least-16-bytes-of-tx-metadata.patch @@ -0,0 +1,45 @@ +From 512627f160ca90829a046eda233e2d84d5294d77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 09:19:54 -0700 +Subject: xsk: require at least 16 bytes of TX metadata + +From: Stanislav Fomichev + +[ 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) +Link: https://lore.kernel.org/netdev/20260720155210.34229-1-blbllhy@gmail.com/ +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20260727161959.885642-2-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/xsk-validate-launch-time-metadata-size.patch b/queue-7.1/xsk-validate-launch-time-metadata-size.patch new file mode 100644 index 0000000000..95f06da1fa --- /dev/null +++ b/queue-7.1/xsk-validate-launch-time-metadata-size.patch @@ -0,0 +1,117 @@ +From 50d4fd2f97145ce38d0d8265e5a2759f070fa284 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 09:19:57 -0700 +Subject: xsk: validate launch-time metadata size + +From: Stanislav Fomichev + +[ 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) +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20260727161959.885642-5-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/xsk-validate-metadata-when-processing-requests.patch b/queue-7.1/xsk-validate-metadata-when-processing-requests.patch new file mode 100644 index 0000000000..a971398e4c --- /dev/null +++ b/queue-7.1/xsk-validate-metadata-when-processing-requests.patch @@ -0,0 +1,224 @@ +From 82be16f022eddf0677e1e3d31ffe5d518f26145c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 09:19:59 -0700 +Subject: xsk: validate metadata when processing requests + +From: Stanislav Fomichev + +[ 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) +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20260727161959.885642-7-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 +