]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.15-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 16 Jun 2026 05:41:01 +0000 (11:11 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 16 Jun 2026 05:41:01 +0000 (11:11 +0530)
added patches:
arm64-tlb-flush-walk-cache-when-unsharing-pmd-tables.patch
bluetooth-consolidate-code-around-sk_alloc-into-a-helper-function.patch
bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch
bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch
bluetooth-hci_sync-make-use-of-hci_cmd_sync_queue-set-2.patch
bluetooth-init-sk_peer_-on-bt_sock_alloc.patch
bluetooth-l2cap-use-chan-timer-to-close-channels-in-cleanup_listen.patch
bluetooth-mgmt-validate-add-extended-advertising-data-length.patch
bluetooth-serialize-accept_q-access.patch
btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch
btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch
drm-hyperv-remove-support-for-hyper-v-2008-and-2008r2-win7.patch
drm-hyperv-validate-resolution_count-and-fix-win8-fallback.patch
f2fs-fix-false-alarm-of-lockdep-on-cp_global_sem-lock.patch
f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch
fbcon-avoid-oob-font-access-if-console-rotation-fails.patch
genetlink-use-internal-flags-for-multicast-groups.patch
hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch
ice-fix-vf-queue-configuration-with-low-mtu-values.patch
iio-adc-fix-the-return-value-handle-for-platform_get_irq.patch
iio-adc-npcm-convert-to-platform-remove-callback-returning-void.patch
iio-adc-npcm-fix-unbalanced-clk_disable_unprepare.patch
iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch
iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch
iio-dac-ad5686-acquire-lock-when-doing-powerdown-control.patch
iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch
iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch
ipv6-addrconf-annotate-data-races-around-devconf-fields-ii.patch
ipv6-ioam-add-null-check-for-idev-in-ipv6_hop_ioam.patch
mm-huge_memory-update-file-pmd-counter-before-folio_put.patch
mm-hugetlb_cma-round-up-per_node-before-logging-it.patch
mptcp-do-not-drop-partial-packets.patch
mptcp-pm-add_addr-rtx-fix-potential-data-race.patch
mptcp-pm-add_addr-rtx-resched-blocked-add_addr-quicker.patch
mptcp-pm-fix-add_addr-timer-infinite-retry-on-option-space-insufficient.patch
mptcp-pm-prio-skip-closed-subflows.patch
net-hsr-defer-node-table-free-until-after-rcu-readers.patch
net-ipv4-stop-checking-crypto_ahash_alignmask.patch
net-ipv6-stop-checking-crypto_ahash_alignmask.patch
net-skbuff-fix-missing-zerocopy-reference-in-pskb_carve-helpers.patch
netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch
octeontx2-af-cgx-add-bounds-check-to-cgx_speed_mbps-index.patch
octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch
phy-tegra-xusb-disable-trk-clk-when-not-in-use.patch
phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch
pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch
qed-fix-double-free-in-qed_cxt_tables_alloc.patch
qed-use-the-bitmap-api-to-simplify-some-functions.patch
rdma-move-dma-block-iterator-logic-into-dedicated-files.patch
rdma-umem-fix-kernel-doc-warnings.patch
rdma-umem-fix-truncation-for-block-sizes-4g.patch
scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch
scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch
selftests-mptcp-drop-nanoseconds-width-specifier.patch
serial-altera_jtaguart-handle-uart_add_one_port-failures.patch
serial-altera_jtaguart-use-platform_get_irq_optional-to-get-the-interrupt.patch
serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch
serial-samsung_tty-use-port-lock-wrappers.patch
smb-client-require-net-admin-for-cifs-swn-netlink.patch
smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch
smb-client-validate-dacloffset-before-building-dacl-pointers.patch
smb-client-validate-the-whole-dacl-before-rewriting-it-in-cifsacl.patch
spi-lantiq-ssc-fix-controller-deregistration.patch
spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch
spi-qup-switch-to-use-modern-name.patch
spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch
spi-st-ssc4-fix-controller-deregistration.patch
spi-sun4i-fix-controller-deregistration.patch
spi-sun6i-fix-controller-deregistration.patch
spi-syncuacer-fix-controller-deregistration.patch
spi-tegra114-fix-controller-deregistration.patch
spi-tegra20-sflash-fix-controller-deregistration.patch
spi-ti-qspi-fix-controller-deregistration.patch
spi-topcliff-pch-convert-to-platform-remove-callback-returning-void.patch
spi-topcliff-pch-fix-controller-deregistration.patch
spi-uniphier-fix-controller-deregistration.patch
spi-zynq-qspi-fix-controller-deregistration.patch
thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch
tracing-probes-limit-size-of-event-probe-to-3k.patch
tty-serial-qcom-geni-serial-align-define-values.patch
tty-serial-qcom-geni-serial-remove-unused-symbols.patch
tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch
tty-serial-samsung-use-u32-for-register-interactions.patch
usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch
usb-dwc3-move-guid-programming-after-phy-initialization.patch
usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch
usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch
usb-gadget-f_hid-tidy-error-handling-in-hidg_alloc.patch
usb-typec-tcpm-reset-internal-port-states-on-soft-reset-ams.patch
usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch
use-less-confusing-names-for-iov_iter-direction-initializers.patch
wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch
xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch
xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch

98 files changed:
queue-5.15/arm64-tlb-flush-walk-cache-when-unsharing-pmd-tables.patch [new file with mode: 0644]
queue-5.15/bluetooth-consolidate-code-around-sk_alloc-into-a-helper-function.patch [new file with mode: 0644]
queue-5.15/bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch [new file with mode: 0644]
queue-5.15/bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch [new file with mode: 0644]
queue-5.15/bluetooth-hci_sync-make-use-of-hci_cmd_sync_queue-set-2.patch [new file with mode: 0644]
queue-5.15/bluetooth-init-sk_peer_-on-bt_sock_alloc.patch [new file with mode: 0644]
queue-5.15/bluetooth-l2cap-use-chan-timer-to-close-channels-in-cleanup_listen.patch [new file with mode: 0644]
queue-5.15/bluetooth-mgmt-validate-add-extended-advertising-data-length.patch [new file with mode: 0644]
queue-5.15/bluetooth-serialize-accept_q-access.patch [new file with mode: 0644]
queue-5.15/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch [new file with mode: 0644]
queue-5.15/btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch [new file with mode: 0644]
queue-5.15/drm-hyperv-remove-support-for-hyper-v-2008-and-2008r2-win7.patch [new file with mode: 0644]
queue-5.15/drm-hyperv-validate-resolution_count-and-fix-win8-fallback.patch [new file with mode: 0644]
queue-5.15/f2fs-fix-false-alarm-of-lockdep-on-cp_global_sem-lock.patch [new file with mode: 0644]
queue-5.15/f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch [new file with mode: 0644]
queue-5.15/fbcon-avoid-oob-font-access-if-console-rotation-fails.patch [new file with mode: 0644]
queue-5.15/genetlink-use-internal-flags-for-multicast-groups.patch [new file with mode: 0644]
queue-5.15/hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch [new file with mode: 0644]
queue-5.15/ice-fix-vf-queue-configuration-with-low-mtu-values.patch [new file with mode: 0644]
queue-5.15/iio-adc-fix-the-return-value-handle-for-platform_get_irq.patch [new file with mode: 0644]
queue-5.15/iio-adc-npcm-convert-to-platform-remove-callback-returning-void.patch [new file with mode: 0644]
queue-5.15/iio-adc-npcm-fix-unbalanced-clk_disable_unprepare.patch [new file with mode: 0644]
queue-5.15/iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch [new file with mode: 0644]
queue-5.15/iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch [new file with mode: 0644]
queue-5.15/iio-dac-ad5686-acquire-lock-when-doing-powerdown-control.patch [new file with mode: 0644]
queue-5.15/iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch [new file with mode: 0644]
queue-5.15/iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch [new file with mode: 0644]
queue-5.15/ipv6-addrconf-annotate-data-races-around-devconf-fields-ii.patch [new file with mode: 0644]
queue-5.15/ipv6-ioam-add-null-check-for-idev-in-ipv6_hop_ioam.patch [new file with mode: 0644]
queue-5.15/mm-huge_memory-update-file-pmd-counter-before-folio_put.patch [new file with mode: 0644]
queue-5.15/mm-hugetlb_cma-round-up-per_node-before-logging-it.patch [new file with mode: 0644]
queue-5.15/mptcp-do-not-drop-partial-packets.patch [new file with mode: 0644]
queue-5.15/mptcp-pm-add_addr-rtx-fix-potential-data-race.patch [new file with mode: 0644]
queue-5.15/mptcp-pm-add_addr-rtx-resched-blocked-add_addr-quicker.patch [new file with mode: 0644]
queue-5.15/mptcp-pm-fix-add_addr-timer-infinite-retry-on-option-space-insufficient.patch [new file with mode: 0644]
queue-5.15/mptcp-pm-prio-skip-closed-subflows.patch [new file with mode: 0644]
queue-5.15/mtd-docg3-convert-to-platform-remove-callback-returning-void.patch [deleted file]
queue-5.15/mtd-docg3-fix-use-after-free-in-docg3_release.patch [deleted file]
queue-5.15/net-hsr-defer-node-table-free-until-after-rcu-readers.patch [new file with mode: 0644]
queue-5.15/net-ipv4-stop-checking-crypto_ahash_alignmask.patch [new file with mode: 0644]
queue-5.15/net-ipv6-stop-checking-crypto_ahash_alignmask.patch [new file with mode: 0644]
queue-5.15/net-skbuff-fix-missing-zerocopy-reference-in-pskb_carve-helpers.patch [new file with mode: 0644]
queue-5.15/netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch [new file with mode: 0644]
queue-5.15/octeontx2-af-cgx-add-bounds-check-to-cgx_speed_mbps-index.patch [new file with mode: 0644]
queue-5.15/octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch [new file with mode: 0644]
queue-5.15/phy-tegra-xusb-disable-trk-clk-when-not-in-use.patch [new file with mode: 0644]
queue-5.15/phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch [new file with mode: 0644]
queue-5.15/pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch [new file with mode: 0644]
queue-5.15/qed-fix-double-free-in-qed_cxt_tables_alloc.patch [new file with mode: 0644]
queue-5.15/qed-use-the-bitmap-api-to-simplify-some-functions.patch [new file with mode: 0644]
queue-5.15/rdma-move-dma-block-iterator-logic-into-dedicated-files.patch [new file with mode: 0644]
queue-5.15/rdma-umem-fix-kernel-doc-warnings.patch [new file with mode: 0644]
queue-5.15/rdma-umem-fix-truncation-for-block-sizes-4g.patch [new file with mode: 0644]
queue-5.15/rxrpc-fix-conn-level-packet-handling-to-unshare-response-packets.patch [deleted file]
queue-5.15/scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch [new file with mode: 0644]
queue-5.15/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch [new file with mode: 0644]
queue-5.15/selftests-mptcp-drop-nanoseconds-width-specifier.patch [new file with mode: 0644]
queue-5.15/serial-altera_jtaguart-handle-uart_add_one_port-failures.patch [new file with mode: 0644]
queue-5.15/serial-altera_jtaguart-use-platform_get_irq_optional-to-get-the-interrupt.patch [new file with mode: 0644]
queue-5.15/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch [new file with mode: 0644]
queue-5.15/serial-samsung_tty-use-port-lock-wrappers.patch [new file with mode: 0644]
queue-5.15/series
queue-5.15/smb-client-require-net-admin-for-cifs-swn-netlink.patch [new file with mode: 0644]
queue-5.15/smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch [new file with mode: 0644]
queue-5.15/smb-client-validate-dacloffset-before-building-dacl-pointers.patch [new file with mode: 0644]
queue-5.15/smb-client-validate-the-whole-dacl-before-rewriting-it-in-cifsacl.patch [new file with mode: 0644]
queue-5.15/spi-lantiq-ssc-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.15/spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch [new file with mode: 0644]
queue-5.15/spi-qup-switch-to-use-modern-name.patch [new file with mode: 0644]
queue-5.15/spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch [new file with mode: 0644]
queue-5.15/spi-st-ssc4-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.15/spi-sun4i-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.15/spi-sun6i-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.15/spi-syncuacer-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.15/spi-tegra114-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.15/spi-tegra20-sflash-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.15/spi-ti-qspi-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.15/spi-topcliff-pch-convert-to-platform-remove-callback-returning-void.patch [new file with mode: 0644]
queue-5.15/spi-topcliff-pch-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.15/spi-uniphier-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.15/spi-zynq-qspi-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.15/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch [new file with mode: 0644]
queue-5.15/tracing-probes-limit-size-of-event-probe-to-3k.patch [new file with mode: 0644]
queue-5.15/tty-serial-qcom-geni-serial-align-define-values.patch [new file with mode: 0644]
queue-5.15/tty-serial-qcom-geni-serial-remove-unused-symbols.patch [new file with mode: 0644]
queue-5.15/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch [new file with mode: 0644]
queue-5.15/tty-serial-samsung-use-u32-for-register-interactions.patch [new file with mode: 0644]
queue-5.15/usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch [new file with mode: 0644]
queue-5.15/usb-dwc3-move-guid-programming-after-phy-initialization.patch [new file with mode: 0644]
queue-5.15/usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch [new file with mode: 0644]
queue-5.15/usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch [new file with mode: 0644]
queue-5.15/usb-gadget-f_hid-tidy-error-handling-in-hidg_alloc.patch [new file with mode: 0644]
queue-5.15/usb-typec-tcpm-reset-internal-port-states-on-soft-reset-ams.patch [new file with mode: 0644]
queue-5.15/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch [new file with mode: 0644]
queue-5.15/use-less-confusing-names-for-iov_iter-direction-initializers.patch [new file with mode: 0644]
queue-5.15/wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch [new file with mode: 0644]
queue-5.15/xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch [new file with mode: 0644]
queue-5.15/xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch [new file with mode: 0644]

diff --git a/queue-5.15/arm64-tlb-flush-walk-cache-when-unsharing-pmd-tables.patch b/queue-5.15/arm64-tlb-flush-walk-cache-when-unsharing-pmd-tables.patch
new file mode 100644 (file)
index 0000000..bfa3c73
--- /dev/null
@@ -0,0 +1,55 @@
+From stable+bounces-259522-greg=kroah.com@vger.kernel.org Mon Jun  1 16:21:23 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon,  1 Jun 2026 06:51:16 -0400
+Subject: arm64: tlb: Flush walk cache when unsharing PMD tables
+To: stable@vger.kernel.org
+Cc: Zeng Heng <zengheng4@huawei.com>, Catalin Marinas <catalin.marinas@arm.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260601105116.381170-1-sashal@kernel.org>
+
+From: Zeng Heng <zengheng4@huawei.com>
+
+[ Upstream commit c2ff4764e03e7a8d758352f4aceb8fe1be6ac971 ]
+
+When huge_pmd_unshare() is called to unshare a PMD table, the
+tlb_unshare_pmd_ptdesc() function sets tlb->unshared_tables=true
+but the aarch64 tlb_flush() only checked tlb->freed_tables to
+determine whether to use TLBF_NONE (vae1is, invalidates walk
+cache) or TLBF_NOWALKCACHE (vale1is, leaf-only).
+
+This caused the stale PMD page table entry to remain in the walk cache
+after unshare, potentially leading to incorrect page table walks.
+
+Fix by including unshared_tables in the check, so that when
+unsharing tables, TLBF_NONE is used and the walk cache is properly
+invalidated.
+
+Here is the detailed distinction between vae1is and vale1is:
+
+| Instruction Combination  | Actual Invalidation Scope                         |
+| ------------------------ | --------------------------------------------------|
+| `VAE1IS`  + TTL=`0`      | All entries at all levels (full invalidation)     |
+| `VAE1IS`  + TTL=`2` (L2) | Non-leaf at Level 0/1 + leaf at Level 2           |
+| `VALE1IS` + TTL=`0`      | Leaf entries at all levels (non-leaf not cleared) |
+| `VALE1IS` + TTL=`2` (L2) | Leaf entry at Level 2 only                        |
+
+Signed-off-by: Zeng Heng <zengheng4@huawei.com>
+Fixes: 8ce720d5bd91 ("mm/hugetlb: fix excessive IPI broadcasts when unsharing PMD tables using mmu_gather")
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm64/include/asm/tlb.h |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm64/include/asm/tlb.h
++++ b/arch/arm64/include/asm/tlb.h
+@@ -53,7 +53,7 @@ static inline int tlb_get_level(struct m
+ static inline void tlb_flush(struct mmu_gather *tlb)
+ {
+       struct vm_area_struct vma = TLB_FLUSH_VMA(tlb->mm, 0);
+-      bool last_level = !tlb->freed_tables;
++      bool last_level = !(tlb->freed_tables || tlb->unshared_tables);
+       unsigned long stride = tlb_get_unmap_size(tlb);
+       int tlb_level = tlb_get_level(tlb);
diff --git a/queue-5.15/bluetooth-consolidate-code-around-sk_alloc-into-a-helper-function.patch b/queue-5.15/bluetooth-consolidate-code-around-sk_alloc-into-a-helper-function.patch
new file mode 100644 (file)
index 0000000..00727c1
--- /dev/null
@@ -0,0 +1,204 @@
+From stable+bounces-256822-greg=kroah.com@vger.kernel.org Sat May 30 05:13:46 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 19:38:24 -0400
+Subject: Bluetooth: Consolidate code around sk_alloc into a helper function
+To: stable@vger.kernel.org
+Cc: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529233826.1908632-1-sashal@kernel.org>
+
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+
+[ Upstream commit 6bfa273e533d7b25eee3d74e28a7fe8e6a8e7a93 ]
+
+This consolidates code around sk_alloc into bt_sock_alloc which does
+take care of common initialization.
+
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Stable-dep-of: e83f5e24da74 ("Bluetooth: serialize accept_q access")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/bluetooth/bluetooth.h |    2 ++
+ net/bluetooth/af_bluetooth.c      |   21 +++++++++++++++++++++
+ net/bluetooth/bnep/sock.c         |   10 +---------
+ net/bluetooth/hci_sock.c          |   10 ++--------
+ net/bluetooth/l2cap_sock.c        |   10 +---------
+ net/bluetooth/rfcomm/sock.c       |   13 +++----------
+ net/bluetooth/sco.c               |   10 +---------
+ 7 files changed, 31 insertions(+), 45 deletions(-)
+
+--- a/include/net/bluetooth/bluetooth.h
++++ b/include/net/bluetooth/bluetooth.h
+@@ -315,6 +315,8 @@ void bt_sock_unregister(int proto);
+ void bt_sock_link(struct bt_sock_list *l, struct sock *s);
+ void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
+ bool bt_sock_linked(struct bt_sock_list *l, struct sock *s);
++struct sock *bt_sock_alloc(struct net *net, struct socket *sock,
++                         struct proto *prot, int proto, gfp_t prio, int kern);
+ int  bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
+                    int flags);
+ int  bt_sock_stream_recvmsg(struct socket *sock, struct msghdr *msg,
+--- a/net/bluetooth/af_bluetooth.c
++++ b/net/bluetooth/af_bluetooth.c
+@@ -138,6 +138,27 @@ static int bt_sock_create(struct net *ne
+       return err;
+ }
++struct sock *bt_sock_alloc(struct net *net, struct socket *sock,
++                         struct proto *prot, int proto, gfp_t prio, int kern)
++{
++      struct sock *sk;
++
++      sk = sk_alloc(net, PF_BLUETOOTH, prio, prot, kern);
++      if (!sk)
++              return NULL;
++
++      sock_init_data(sock, sk);
++      INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
++
++      sock_reset_flag(sk, SOCK_ZAPPED);
++
++      sk->sk_protocol = proto;
++      sk->sk_state    = BT_OPEN;
++
++      return sk;
++}
++EXPORT_SYMBOL(bt_sock_alloc);
++
+ void bt_sock_link(struct bt_sock_list *l, struct sock *sk)
+ {
+       write_lock(&l->lock);
+--- a/net/bluetooth/bnep/sock.c
++++ b/net/bluetooth/bnep/sock.c
+@@ -204,21 +204,13 @@ static int bnep_sock_create(struct net *
+       if (sock->type != SOCK_RAW)
+               return -ESOCKTNOSUPPORT;
+-      sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto, kern);
++      sk = bt_sock_alloc(net, sock, &bnep_proto, protocol, GFP_ATOMIC, kern);
+       if (!sk)
+               return -ENOMEM;
+-      sock_init_data(sock, sk);
+-
+       sock->ops = &bnep_sock_ops;
+-
+       sock->state = SS_UNCONNECTED;
+-      sock_reset_flag(sk, SOCK_ZAPPED);
+-
+-      sk->sk_protocol = protocol;
+-      sk->sk_state    = BT_OPEN;
+-
+       bt_sock_link(&bnep_sk_list, sk);
+       return 0;
+ }
+--- a/net/bluetooth/hci_sock.c
++++ b/net/bluetooth/hci_sock.c
+@@ -2091,18 +2091,12 @@ static int hci_sock_create(struct net *n
+       sock->ops = &hci_sock_ops;
+-      sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto, kern);
++      sk = bt_sock_alloc(net, sock, &hci_sk_proto, protocol, GFP_ATOMIC,
++                         kern);
+       if (!sk)
+               return -ENOMEM;
+-      sock_init_data(sock, sk);
+-
+-      sock_reset_flag(sk, SOCK_ZAPPED);
+-
+-      sk->sk_protocol = protocol;
+-
+       sock->state = SS_UNCONNECTED;
+-      sk->sk_state = BT_OPEN;
+       sk->sk_destruct = hci_sock_destruct;
+       bt_sock_link(&hci_sk_list, sk);
+--- a/net/bluetooth/l2cap_sock.c
++++ b/net/bluetooth/l2cap_sock.c
+@@ -1913,21 +1913,13 @@ static struct sock *l2cap_sock_alloc(str
+       struct sock *sk;
+       struct l2cap_chan *chan;
+-      sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto, kern);
++      sk = bt_sock_alloc(net, sock, &l2cap_proto, proto, prio, kern);
+       if (!sk)
+               return NULL;
+-      sock_init_data(sock, sk);
+-      INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
+-
+       sk->sk_destruct = l2cap_sock_destruct;
+       sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;
+-      sock_reset_flag(sk, SOCK_ZAPPED);
+-
+-      sk->sk_protocol = proto;
+-      sk->sk_state = BT_OPEN;
+-
+       chan = l2cap_chan_create();
+       if (!chan) {
+               sk_free(sk);
+--- a/net/bluetooth/rfcomm/sock.c
++++ b/net/bluetooth/rfcomm/sock.c
+@@ -280,18 +280,16 @@ static struct proto rfcomm_proto = {
+       .obj_size       = sizeof(struct rfcomm_pinfo)
+ };
+-static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio, int kern)
++static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock,
++                                    int proto, gfp_t prio, int kern)
+ {
+       struct rfcomm_dlc *d;
+       struct sock *sk;
+-      sk = sk_alloc(net, PF_BLUETOOTH, prio, &rfcomm_proto, kern);
++      sk = bt_sock_alloc(net, sock, &rfcomm_proto, proto, prio, kern);
+       if (!sk)
+               return NULL;
+-      sock_init_data(sock, sk);
+-      INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
+-
+       d = rfcomm_dlc_alloc(prio);
+       if (!d) {
+               sk_free(sk);
+@@ -310,11 +308,6 @@ static struct sock *rfcomm_sock_alloc(st
+       sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+       sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+-      sock_reset_flag(sk, SOCK_ZAPPED);
+-
+-      sk->sk_protocol = proto;
+-      sk->sk_state    = BT_OPEN;
+-
+       bt_sock_link(&rfcomm_sk_list, sk);
+       BT_DBG("sk %p", sk);
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -501,21 +501,13 @@ static struct sock *sco_sock_alloc(struc
+ {
+       struct sock *sk;
+-      sk = sk_alloc(net, PF_BLUETOOTH, prio, &sco_proto, kern);
++      sk = bt_sock_alloc(net, sock, &sco_proto, proto, prio, kern);
+       if (!sk)
+               return NULL;
+-      sock_init_data(sock, sk);
+-      INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
+-
+       sk->sk_destruct = sco_sock_destruct;
+       sk->sk_sndtimeo = SCO_CONN_TIMEOUT;
+-      sock_reset_flag(sk, SOCK_ZAPPED);
+-
+-      sk->sk_protocol = proto;
+-      sk->sk_state    = BT_OPEN;
+-
+       sco_pi(sk)->setting = BT_VOICE_CVSD_16BIT;
+       bt_sock_link(&sco_sk_list, sk);
diff --git a/queue-5.15/bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch b/queue-5.15/bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch
new file mode 100644 (file)
index 0000000..0130543
--- /dev/null
@@ -0,0 +1,210 @@
+From stable+bounces-256726-greg=kroah.com@vger.kernel.org Sat May 30 00:38:46 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 15:08:13 -0400
+Subject: Bluetooth: fix UAF in l2cap_sock_cleanup_listen() vs l2cap_conn_del()
+To: stable@vger.kernel.org
+Cc: "Safa KarakuÅŸ" <safa.karakus@secunnix.com>, "Siwei Zhang" <oss@fourdim.xyz>, "Luiz Augusto von Dentz" <luiz.von.dentz@intel.com>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260529190813.1682934-1-sashal@kernel.org>
+
+From: Safa KarakuÅŸ <safa.karakus@secunnix.com>
+
+[ Upstream commit ab1513597c6cf17cd1ad2a21e3b045421b48e022 ]
+
+bt_accept_dequeue() unlinks a not-yet-accepted child from the parent
+accept queue and release_sock()s it before returning, so the returned
+sk has no caller reference and is unlocked.
+
+l2cap_sock_cleanup_listen() walks these children on listening-socket
+close.  A concurrent HCI disconnect drives hci_rx_work ->
+l2cap_conn_del() which runs l2cap_chan_del() + l2cap_sock_kill() and
+frees the child sk and its l2cap_chan; cleanup_listen() then uses both:
+
+  BUG: KASAN: slab-use-after-free in l2cap_sock_kill
+    l2cap_sock_kill / l2cap_sock_cleanup_listen / __x64_sys_close
+  Freed by: l2cap_conn_del -> l2cap_sock_close_cb -> l2cap_sock_kill
+
+This is distinct from the two fixes already in this area: commit
+e83f5e24da741 ("Bluetooth: serialize accept_q access") serialises the
+accept_q list/poll and takes temporary refs inside bt_accept_dequeue(),
+and CVE-2025-39860 serialises the userspace close()/accept() race by
+calling cleanup_listen() under lock_sock() in l2cap_sock_release().
+Neither covers l2cap_conn_del() running from hci_rx_work, so this UAF
+still reproduces on current bluetooth/master.
+
+Take the reference at the source: bt_accept_dequeue() does sock_hold()
+while sk is still locked, before release_sock(); callers sock_put().
+cleanup_listen() pins the chan with l2cap_chan_hold_unless_zero() under
+a brief child sk lock (serialising vs l2cap_sock_teardown_cb()), drops
+it before l2cap_chan_lock(), and skips a duplicate l2cap_sock_kill() on
+SOCK_DEAD.  conn->lock is not taken here: cleanup_listen() runs under
+the parent sk lock and that would invert
+conn->lock -> chan->lock -> sk_lock (lockdep).
+
+KASAN/SMP: an unprivileged listen/close vs HCI-disconnect race produced
+12 use-after-free reports per run before this change; 0, and no lockdep
+report, over 1600+ raced iterations after it on bluetooth/master.
+
+Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode")
+Cc: stable@vger.kernel.org
+Reported-by: Siwei Zhang <oss@fourdim.xyz>
+Reviewed-by: Siwei Zhang <oss@fourdim.xyz>
+Signed-off-by: Safa KarakuÅŸ <safa.karakus@secunnix.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/af_bluetooth.c |   10 ++++++++
+ net/bluetooth/l2cap_sock.c   |   51 +++++++++++++++++++++++++++++++++++++------
+ net/bluetooth/rfcomm/sock.c  |    9 ++++++-
+ net/bluetooth/sco.c          |    9 ++++++-
+ 4 files changed, 70 insertions(+), 9 deletions(-)
+
+--- a/net/bluetooth/af_bluetooth.c
++++ b/net/bluetooth/af_bluetooth.c
+@@ -259,6 +259,16 @@ restart:
+                       if (newsock)
+                               sock_graft(sk, newsock);
++                      /* Hand the caller a reference taken while sk is
++                       * still locked.  bt_accept_unlink() just dropped
++                       * the accept-queue reference; without this hold a
++                       * concurrent teardown (e.g. l2cap_conn_del() ->
++                       * l2cap_sock_kill()) could free sk between
++                       * release_sock() and the caller using it.  Every
++                       * caller drops this with sock_put() when done.
++                       */
++                      sock_hold(sk);
++
+                       release_sock(sk);
+                       return sk;
+               }
+--- a/net/bluetooth/l2cap_sock.c
++++ b/net/bluetooth/l2cap_sock.c
+@@ -366,8 +366,13 @@ static int l2cap_sock_accept(struct sock
+               }
+               nsk = bt_accept_dequeue(sk, newsock);
+-              if (nsk)
++              if (nsk) {
++                      /* Drop the bridging ref from bt_accept_dequeue();
++                       * the grafted socket keeps nsk alive from here.
++                       */
++                      sock_put(nsk);
+                       break;
++              }
+               if (!timeo) {
+                       err = -EAGAIN;
+@@ -1444,22 +1449,54 @@ static void l2cap_sock_cleanup_listen(st
+       BT_DBG("parent %p state %s", parent,
+              state_to_string(parent->sk_state));
+-      /* Close not yet accepted channels */
++      /* Close not yet accepted channels.
++       *
++       * bt_accept_dequeue() now returns sk with an extra reference held
++       * (taken while sk was still locked) so a concurrent l2cap_conn_del()
++       * -> l2cap_sock_kill() cannot free sk under us.
++       *
++       * cleanup_listen() runs under the parent sk lock, so unlike
++       * l2cap_sock_shutdown() we must NOT take conn->lock here: that would
++       * establish sk_lock -> conn->lock and invert the established
++       * conn->lock -> chan->lock -> sk_lock order (lockdep deadlock).
++       *
++       * Instead, briefly take the child sk lock to fetch and pin its chan.
++       * l2cap_conn_del() reaches the chan free only via
++       * l2cap_chan_del() -> l2cap_sock_teardown_cb(), which itself takes
++       * the child sk lock; holding it across l2cap_chan_hold_unless_zero()
++       * therefore guarantees the chan cannot be freed while we read and
++       * pin it (hold_unless_zero() additionally skips a chan already past
++       * its last reference).  We then drop the sk lock before taking
++       * chan->lock, so sk and chan locks are never held together.
++       */
+       while ((sk = bt_accept_dequeue(parent, NULL))) {
+-              struct l2cap_chan *chan = l2cap_pi(sk)->chan;
++              struct l2cap_chan *chan;
++
++              lock_sock_nested(sk, L2CAP_NESTING_NORMAL);
++              chan = l2cap_chan_hold_unless_zero(l2cap_pi(sk)->chan);
++              release_sock(sk);
++              if (!chan) {
++                      /* l2cap_conn_del() already tearing this child down */
++                      sock_put(sk);
++                      continue;
++              }
+               BT_DBG("child chan %p state %s", chan,
+                      state_to_string(chan->state));
+-              l2cap_chan_hold(chan);
+               l2cap_chan_lock(chan);
+-
+               __clear_chan_timer(chan);
+               l2cap_chan_close(chan, ECONNRESET);
+-              l2cap_sock_kill(sk);
+-
++              /* l2cap_conn_del() may already have killed this socket
++               * (it sets SOCK_DEAD); skip the duplicate to avoid a
++               * double sock_put()/l2cap_chan_put().
++               */
++              if (!sock_flag(sk, SOCK_DEAD))
++                      l2cap_sock_kill(sk);
+               l2cap_chan_unlock(chan);
++
+               l2cap_chan_put(chan);
++              sock_put(sk);
+       }
+ }
+--- a/net/bluetooth/rfcomm/sock.c
++++ b/net/bluetooth/rfcomm/sock.c
+@@ -190,6 +190,8 @@ static void rfcomm_sock_cleanup_listen(s
+       while ((sk = bt_accept_dequeue(parent, NULL))) {
+               rfcomm_sock_close(sk);
+               rfcomm_sock_kill(sk);
++              /* Drop the reference handed back by bt_accept_dequeue(). */
++              sock_put(sk);
+       }
+       parent->sk_state  = BT_CLOSED;
+@@ -513,8 +515,13 @@ static int rfcomm_sock_accept(struct soc
+               }
+               nsk = bt_accept_dequeue(sk, newsock);
+-              if (nsk)
++              if (nsk) {
++                      /* Drop the bridging ref from bt_accept_dequeue();
++                       * the grafted socket keeps nsk alive from here.
++                       */
++                      sock_put(nsk);
+                       break;
++              }
+               if (!timeo) {
+                       err = -EAGAIN;
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -394,6 +394,8 @@ static void sco_sock_cleanup_listen(stru
+       while ((sk = bt_accept_dequeue(parent, NULL))) {
+               sco_sock_close(sk);
+               sco_sock_kill(sk);
++              /* Drop the reference handed back by bt_accept_dequeue(). */
++              sock_put(sk);
+       }
+       parent->sk_state  = BT_CLOSED;
+@@ -687,8 +689,13 @@ static int sco_sock_accept(struct socket
+               }
+               ch = bt_accept_dequeue(sk, newsock);
+-              if (ch)
++              if (ch) {
++                      /* Drop the bridging ref from bt_accept_dequeue();
++                       * the grafted socket keeps ch alive from here.
++                       */
++                      sock_put(ch);
+                       break;
++              }
+               if (!timeo) {
+                       err = -EAGAIN;
diff --git a/queue-5.15/bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch b/queue-5.15/bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch
new file mode 100644 (file)
index 0000000..cd67fc1
--- /dev/null
@@ -0,0 +1,155 @@
+From stable+bounces-256793-greg=kroah.com@vger.kernel.org Sat May 30 03:18:53 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 17:48:45 -0400
+Subject: Bluetooth: hci_qca: Convert timeout from jiffies to ms
+To: stable@vger.kernel.org
+Cc: Shuai Zhang <shuai.zhang@oss.qualcomm.com>, Paul Menzel <pmenzel@molgen.mpg.de>, Bartosz Golaszewski <bartosz.golaszewski@linaro.org>, Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529214845.1804717-1-sashal@kernel.org>
+
+From: Shuai Zhang <shuai.zhang@oss.qualcomm.com>
+
+[ Upstream commit 375ba7484132662a4a8c7547d088fb6275c00282 ]
+
+Since the timer uses jiffies as its unit rather than ms, the timeout value
+must be converted from ms to jiffies when configuring the timer. Otherwise,
+the intended 8s timeout is incorrectly set to approximately 33s.
+
+To improve readability, embed msecs_to_jiffies() directly in the macro
+definitions and drop the _MS suffix from macros that now yield jiffies
+values: MEMDUMP_TIMEOUT, FW_DOWNLOAD_TIMEOUT, IBS_DISABLE_SSR_TIMEOUT,
+CMD_TRANS_TIMEOUT, and IBS_BTSOC_TX_IDLE_TIMEOUT.
+
+IBS_WAKE_RETRANS_TIMEOUT_MS and IBS_HOST_TX_IDLE_TIMEOUT_MS are
+intentionally left unchanged. Their values are stored in the struct fields
+wake_retrans and tx_idle_delay, which hold ms values at runtime and can be
+modified via debugfs. The msecs_to_jiffies() conversion happens at each
+call site against the field value, so it cannot be embedded in the macro.
+
+Wake timer depends on commit c347ca17d62a
+
+Cc: stable@vger.kernel.org
+Fixes: d841502c79e3 ("Bluetooth: hci_qca: Collect controller memory dump during SSR")
+Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
+Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Shuai Zhang <shuai.zhang@oss.qualcomm.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+[ adapted to `vmalloc`-based memdump path and older `qca_serdev_shutdown(struct device *dev)` signature ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/bluetooth/hci_qca.c |   33 ++++++++++++++++-----------------
+ 1 file changed, 16 insertions(+), 17 deletions(-)
+
+--- a/drivers/bluetooth/hci_qca.c
++++ b/drivers/bluetooth/hci_qca.c
+@@ -46,13 +46,12 @@
+ #define HCI_MAX_IBS_SIZE      10
+ #define IBS_WAKE_RETRANS_TIMEOUT_MS   100
+-#define IBS_BTSOC_TX_IDLE_TIMEOUT_MS  200
++#define IBS_BTSOC_TX_IDLE_TIMEOUT     msecs_to_jiffies(200)
+ #define IBS_HOST_TX_IDLE_TIMEOUT_MS   2000
+-#define CMD_TRANS_TIMEOUT_MS          100
+-#define MEMDUMP_TIMEOUT_MS            8000
+-#define IBS_DISABLE_SSR_TIMEOUT_MS \
+-      (MEMDUMP_TIMEOUT_MS + FW_DOWNLOAD_TIMEOUT_MS)
+-#define FW_DOWNLOAD_TIMEOUT_MS                3000
++#define CMD_TRANS_TIMEOUT             msecs_to_jiffies(100)
++#define MEMDUMP_TIMEOUT                       msecs_to_jiffies(8000)
++#define FW_DOWNLOAD_TIMEOUT           msecs_to_jiffies(3000)
++#define IBS_DISABLE_SSR_TIMEOUT               (MEMDUMP_TIMEOUT + FW_DOWNLOAD_TIMEOUT)
+ /* susclk rate */
+ #define SUSCLK_RATE_32KHZ     32768
+@@ -1058,7 +1057,7 @@ static void qca_controller_memdump(struc
+                                   dump_size);
+                       queue_delayed_work(qca->workqueue,
+                                          &qca->ctrl_memdump_timeout,
+-                                         msecs_to_jiffies(MEMDUMP_TIMEOUT_MS)
++                                         MEMDUMP_TIMEOUT
+                                         );
+                       skb_pull(skb, sizeof(dump_size));
+@@ -1326,7 +1325,7 @@ static int qca_set_baudrate(struct hci_d
+       if (hu->serdev)
+               serdev_device_wait_until_sent(hu->serdev,
+-                    msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS));
++                    CMD_TRANS_TIMEOUT);
+       /* Give the controller time to process the request */
+       switch (qca_soc_type(hu)) {
+@@ -1356,8 +1355,8 @@ static inline void host_set_baudrate(str
+ static int qca_send_power_pulse(struct hci_uart *hu, bool on)
+ {
++      int timeout = CMD_TRANS_TIMEOUT;
+       int ret;
+-      int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS);
+       u8 cmd = on ? QCA_WCN3990_POWERON_PULSE : QCA_WCN3990_POWEROFF_PULSE;
+       /* These power pulses are single byte command which are sent
+@@ -1556,7 +1555,7 @@ static void qca_wait_for_dump_collection
+       struct qca_data *qca = hu->priv;
+       wait_on_bit_timeout(&qca->flags, QCA_MEMDUMP_COLLECTION,
+-                          TASK_UNINTERRUPTIBLE, MEMDUMP_TIMEOUT_MS);
++                          TASK_UNINTERRUPTIBLE, MEMDUMP_TIMEOUT);
+       clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
+ }
+@@ -2345,7 +2344,7 @@ static void qca_serdev_remove(struct ser
+ static void qca_serdev_shutdown(struct device *dev)
+ {
+       int ret;
+-      int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS);
++      int timeout = CMD_TRANS_TIMEOUT;
+       struct serdev_device *serdev = to_serdev_device(dev);
+       struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
+       struct hci_uart *hu = &qcadev->serdev_hu;
+@@ -2403,7 +2402,7 @@ static int __maybe_unused qca_suspend(st
+       bool tx_pending = false;
+       int ret = 0;
+       u8 cmd;
+-      u32 wait_timeout = 0;
++      unsigned long wait_timeout = 0;
+       set_bit(QCA_SUSPENDING, &qca->flags);
+@@ -2424,15 +2423,15 @@ static int __maybe_unused qca_suspend(st
+       if (test_bit(QCA_IBS_DISABLED, &qca->flags) ||
+           test_bit(QCA_SSR_TRIGGERED, &qca->flags)) {
+               wait_timeout = test_bit(QCA_SSR_TRIGGERED, &qca->flags) ?
+-                                      IBS_DISABLE_SSR_TIMEOUT_MS :
+-                                      FW_DOWNLOAD_TIMEOUT_MS;
++                                      IBS_DISABLE_SSR_TIMEOUT :
++                                      FW_DOWNLOAD_TIMEOUT;
+               /* QCA_IBS_DISABLED flag is set to true, During FW download
+                * and during memory dump collection. It is reset to false,
+                * After FW download complete.
+                */
+               wait_on_bit_timeout(&qca->flags, QCA_IBS_DISABLED,
+-                          TASK_UNINTERRUPTIBLE, msecs_to_jiffies(wait_timeout));
++                          TASK_UNINTERRUPTIBLE, wait_timeout);
+               if (test_bit(QCA_IBS_DISABLED, &qca->flags)) {
+                       bt_dev_err(hu->hdev, "SSR or FW download time out");
+@@ -2484,7 +2483,7 @@ static int __maybe_unused qca_suspend(st
+       if (tx_pending) {
+               serdev_device_wait_until_sent(hu->serdev,
+-                                            msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS));
++                                            CMD_TRANS_TIMEOUT);
+               serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
+       }
+@@ -2493,7 +2492,7 @@ static int __maybe_unused qca_suspend(st
+        */
+       ret = wait_event_interruptible_timeout(qca->suspend_wait_q,
+                       qca->rx_ibs_state == HCI_IBS_RX_ASLEEP,
+-                      msecs_to_jiffies(IBS_BTSOC_TX_IDLE_TIMEOUT_MS));
++                      IBS_BTSOC_TX_IDLE_TIMEOUT);
+       if (ret == 0) {
+               ret = -ETIMEDOUT;
+               goto error;
diff --git a/queue-5.15/bluetooth-hci_sync-make-use-of-hci_cmd_sync_queue-set-2.patch b/queue-5.15/bluetooth-hci_sync-make-use-of-hci_cmd_sync_queue-set-2.patch
new file mode 100644 (file)
index 0000000..638dc34
--- /dev/null
@@ -0,0 +1,130 @@
+From stable+bounces-256805-greg=kroah.com@vger.kernel.org Sat May 30 04:54:04 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 19:22:03 -0400
+Subject: Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 2
+To: stable@vger.kernel.org
+Cc: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Marcel Holtmann <marcel@holtmann.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529232204.1873991-1-sashal@kernel.org>
+
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+
+[ Upstream commit cba6b758711cab946c787f7c15be92cc749b8e1f ]
+
+This make use of hci_cmd_sync_queue for the following MGMT commands:
+
+Add Advertising
+Remove Advertising
+Add Extended Advertising Parameters
+Add Extended Advertising Data
+
+mgmt-tester -s "Add Advertising"
+
+Test Summary
+------------
+Add Advertising - Failure: LE off                    Passed
+Add Advertising - Invalid Params 1 (AD too long)     Passed
+Add Advertising - Invalid Params 2 (Malformed len)   Passed
+Add Advertising - Invalid Params 3 (Malformed len)   Passed
+Add Advertising - Invalid Params 4 (Malformed len)   Passed
+Add Advertising - Invalid Params 5 (AD too long)     Passed
+Add Advertising - Invalid Params 6 (ScRsp too long)  Passed
+Add Advertising - Invalid Params 7 (Malformed len)   Passed
+Add Advertising - Invalid Params 8 (Malformed len)   Passed
+Add Advertising - Invalid Params 9 (Malformed len)   Passed
+Add Advertising - Invalid Params 10 (ScRsp too long) Passed
+Add Advertising - Rejected (Timeout, !Powered)       Passed
+Add Advertising - Success 1 (Powered, Add Adv Inst)  Passed
+Add Advertising - Success 2 (!Powered, Add Adv Inst) Passed
+Add Advertising - Success 3 (!Powered, Adv Enable)   Passed
+Add Advertising - Success 4 (Set Adv on override)    Passed
+Add Advertising - Success 5 (Set Adv off override)   Passed
+Add Advertising - Success 6 (Scan Rsp Dta, Adv ok)   Passed
+Add Advertising - Success 7 (Scan Rsp Dta, Scan ok)  Passed
+Add Advertising - Success 8 (Connectable Flag)       Passed
+Add Advertising - Success 9 (General Discov Flag)    Passed
+Add Advertising - Success 10 (Limited Discov Flag)   Passed
+Add Advertising - Success 11 (Managed Flags)         Passed
+Add Advertising - Success 12 (TX Power Flag)         Passed
+Add Advertising - Success 13 (ADV_SCAN_IND)          Passed
+Add Advertising - Success 14 (ADV_NONCONN_IND)       Passed
+Add Advertising - Success 15 (ADV_IND)               Passed
+Add Advertising - Success 16 (Connectable -> on)     Passed
+Add Advertising - Success 17 (Connectable -> off)    Passed
+Add Advertising - Success 18 (Power -> off, Remove)  Passed
+Add Advertising - Success 19 (Power -> off, Keep)    Passed
+Add Advertising - Success 20 (Add Adv override)      Passed
+Add Advertising - Success 21 (Timeout expires)       Passed
+Add Advertising - Success 22 (LE -> off, Remove)     Passed
+Add Advertising - Success (Empty ScRsp)              Passed
+Add Advertising - Success (ScRsp only)               Passed
+Add Advertising - Invalid Params (ScRsp too long)    Passed
+Add Advertising - Success (ScRsp appear)             Passed
+Add Advertising - Invalid Params (ScRsp appear long) Passed
+Add Advertising - Success (Appear is null)           Passed
+Add Advertising - Success (Name is null)             Passed
+Add Advertising - Success (Complete name)            Passed
+Add Advertising - Success (Shortened name)           Passed
+Add Advertising - Success (Short name)               Passed
+Add Advertising - Success (Name + data)              Passed
+Add Advertising - Invalid Params (Name + data)       Passed
+Add Advertising - Success (Name+data+appear)         Passed
+Total: 47, Passed: 47 (100.0%), Failed: 0, Not Run: 0
+Overall execution time: 2.17 seconds
+
+mgmt-tester -s "Remove Advertising"
+
+Test Summary
+------------
+Remove Advertising - Invalid Params 1                Passed
+Remove Advertising - Success 1                       Passed
+Remove Advertising - Success 2                       Passed
+Total: 3, Passed: 3 (100.0%), Failed: 0, Not Run: 0
+Overall execution time: 0.0585 seconds
+
+mgmt-tester -s "Ext Adv MGMT Params"
+
+Test Summary:
+------------
+Ext Adv MGMT Params - Unpowered                      Passed
+Ext Adv MGMT Params - Invalid parameters             Passed
+Ext Adv MGMT Params - Success                        Passed
+Ext Adv MGMT Params - (5.0) Success                  Passed
+Total: 4, Passed: 4 (100.0%), Failed: 0, Not Run: 0
+Overall execution time: 0.0746 seconds
+
+mgmt-tester -s "Ext Adv MGMT -"
+
+Test Summary
+------------
+Ext Adv MGMT - Data set without Params               Passed
+Ext Adv MGMT - AD Data (5.0) Invalid parameters      Passed
+Ext Adv MGMT - AD Data (5.0) Success                 Passed
+Ext Adv MGMT - AD Scan Response (5.0) Success        Passed
+Total: 4, Passed: 4 (100.0%), Failed: 0, Not Run: 0
+Overall execution time: 0.0805 seconds
+
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+Stable-dep-of: d3f7d17960ed ("Bluetooth: MGMT: validate Add Extended Advertising Data length")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/mgmt.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -8078,12 +8078,12 @@ static int add_ext_adv_data(struct sock
+ {
+       struct mgmt_cp_add_ext_adv_data *cp = data;
+       struct mgmt_rp_add_ext_adv_data rp;
++      struct hci_request req;
+       u8 schedule_instance = 0;
+       struct adv_info *next_instance;
+       struct adv_info *adv_instance;
+       int err = 0;
+       struct mgmt_pending_cmd *cmd;
+-      struct hci_request req;
+       BT_DBG("%s", hdev->name);
diff --git a/queue-5.15/bluetooth-init-sk_peer_-on-bt_sock_alloc.patch b/queue-5.15/bluetooth-init-sk_peer_-on-bt_sock_alloc.patch
new file mode 100644 (file)
index 0000000..2bcaa4b
--- /dev/null
@@ -0,0 +1,139 @@
+From stable+bounces-256823-greg=kroah.com@vger.kernel.org Sat May 30 05:13:59 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 19:38:25 -0400
+Subject: Bluetooth: Init sk_peer_* on bt_sock_alloc
+To: stable@vger.kernel.org
+Cc: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529233826.1908632-2-sashal@kernel.org>
+
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+
+[ Upstream commit 464c702fb9374ff8f3f816f24fb7ac719dd20e1e ]
+
+This makes sure peer information is always available via sock when using
+bt_sock_alloc.
+
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Stable-dep-of: e83f5e24da74 ("Bluetooth: serialize accept_q access")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/af_bluetooth.c |   24 ++++++++++++++++++++++++
+ net/bluetooth/hidp/sock.c    |   10 +---------
+ net/bluetooth/l2cap_sock.c   |   19 -------------------
+ 3 files changed, 25 insertions(+), 28 deletions(-)
+
+--- a/net/bluetooth/af_bluetooth.c
++++ b/net/bluetooth/af_bluetooth.c
+@@ -155,6 +155,14 @@ struct sock *bt_sock_alloc(struct net *n
+       sk->sk_protocol = proto;
+       sk->sk_state    = BT_OPEN;
++      /* Init peer information so it can be properly monitored */
++      if (!kern) {
++              spin_lock(&sk->sk_peer_lock);
++              sk->sk_peer_pid  = get_pid(task_tgid(current));
++              sk->sk_peer_cred = get_current_cred();
++              spin_unlock(&sk->sk_peer_lock);
++      }
++
+       return sk;
+ }
+ EXPORT_SYMBOL(bt_sock_alloc);
+@@ -199,6 +207,9 @@ EXPORT_SYMBOL(bt_sock_linked);
+ void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh)
+ {
++      const struct cred *old_cred;
++      struct pid *old_pid;
++
+       BT_DBG("parent %p, sk %p", parent, sk);
+       sock_hold(sk);
+@@ -211,6 +222,19 @@ void bt_accept_enqueue(struct sock *pare
+       list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q);
+       bt_sk(sk)->parent = parent;
++      /* Copy credentials from parent since for incoming connections the
++       * socket is allocated by the kernel.
++       */
++      spin_lock(&sk->sk_peer_lock);
++      old_pid = sk->sk_peer_pid;
++      old_cred = sk->sk_peer_cred;
++      sk->sk_peer_pid = get_pid(parent->sk_peer_pid);
++      sk->sk_peer_cred = get_cred(parent->sk_peer_cred);
++      spin_unlock(&sk->sk_peer_lock);
++
++      put_pid(old_pid);
++      put_cred(old_cred);
++
+       if (bh)
+               bh_unlock_sock(sk);
+       else
+--- a/net/bluetooth/hidp/sock.c
++++ b/net/bluetooth/hidp/sock.c
+@@ -255,21 +255,13 @@ static int hidp_sock_create(struct net *
+       if (sock->type != SOCK_RAW)
+               return -ESOCKTNOSUPPORT;
+-      sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, kern);
++      sk = bt_sock_alloc(net, sock, &hidp_proto, protocol, GFP_ATOMIC, kern);
+       if (!sk)
+               return -ENOMEM;
+-      sock_init_data(sock, sk);
+-
+       sock->ops = &hidp_sock_ops;
+-
+       sock->state = SS_UNCONNECTED;
+-      sock_reset_flag(sk, SOCK_ZAPPED);
+-
+-      sk->sk_protocol = protocol;
+-      sk->sk_state    = BT_OPEN;
+-
+       bt_sock_link(&hidp_sk_list, sk);
+       return 0;
+--- a/net/bluetooth/l2cap_sock.c
++++ b/net/bluetooth/l2cap_sock.c
+@@ -177,21 +177,6 @@ done:
+       return err;
+ }
+-static void l2cap_sock_init_pid(struct sock *sk)
+-{
+-      struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+-
+-      /* Only L2CAP_MODE_EXT_FLOWCTL ever need to access the PID in order to
+-       * group the channels being requested.
+-       */
+-      if (chan->mode != L2CAP_MODE_EXT_FLOWCTL)
+-              return;
+-
+-      spin_lock(&sk->sk_peer_lock);
+-      sk->sk_peer_pid = get_pid(task_tgid(current));
+-      spin_unlock(&sk->sk_peer_lock);
+-}
+-
+ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
+                             int alen, int flags)
+ {
+@@ -267,8 +252,6 @@ static int l2cap_sock_connect(struct soc
+           chan->mode != L2CAP_MODE_EXT_FLOWCTL)
+               chan->mode = L2CAP_MODE_LE_FLOWCTL;
+-      l2cap_sock_init_pid(sk);
+-
+       err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid),
+                                &la.l2_bdaddr, la.l2_bdaddr_type);
+       if (err)
+@@ -324,8 +307,6 @@ static int l2cap_sock_listen(struct sock
+               goto done;
+       }
+-      l2cap_sock_init_pid(sk);
+-
+       sk->sk_max_ack_backlog = backlog;
+       sk->sk_ack_backlog = 0;
diff --git a/queue-5.15/bluetooth-l2cap-use-chan-timer-to-close-channels-in-cleanup_listen.patch b/queue-5.15/bluetooth-l2cap-use-chan-timer-to-close-channels-in-cleanup_listen.patch
new file mode 100644 (file)
index 0000000..17e6c31
--- /dev/null
@@ -0,0 +1,73 @@
+From stable+bounces-260494-greg=kroah.com@vger.kernel.org Thu Jun  4 19:23:54 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu,  4 Jun 2026 09:37:26 -0400
+Subject: Bluetooth: L2CAP: use chan timer to close channels in cleanup_listen()
+To: stable@vger.kernel.org
+Cc: Siwei Zhang <oss@fourdim.xyz>, Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260604133726.3434716-2-sashal@kernel.org>
+
+From: Siwei Zhang <oss@fourdim.xyz>
+
+[ Upstream commit 8c8e620467a7b51562dbcefbd1f09f288d7d710d ]
+
+l2cap_chan_close() removes the channel from conn->chan_l, which
+must be done under conn->lock.  cleanup_listen() runs under the
+parent sk_lock, so acquiring conn->lock would invert the
+established conn->lock -> chan->lock -> sk_lock order.
+
+Instead of calling l2cap_chan_close() directly, schedule
+l2cap_chan_timeout with delay 0 to close the channel
+asynchronously.  The timeout handler already acquires conn->lock
+and chan->lock in the correct order.
+
+The timer is only armed when chan->conn is still set: if it is
+already NULL, l2cap_conn_del() has already processed this channel
+(l2cap_chan_del + l2cap_sock_teardown_cb + l2cap_sock_close_cb),
+so there is nothing left to do.  If l2cap_conn_del() races in
+after the timer is armed, __clear_chan_timer() inside
+l2cap_chan_del() cancels it; if the timer has already fired, the
+handler returns harmlessly because chan->conn was cleared.
+
+Fixes: 3df91ea20e74 ("Bluetooth: Revert to mutexes from RCU list")
+Cc: <stable@vger.kernel.org> # 0b58004: Bluetooth: fix UAF in l2cap_sock_cleanup_listen() vs l2cap_conn_del()
+Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/l2cap_sock.c |   16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+--- a/net/bluetooth/l2cap_sock.c
++++ b/net/bluetooth/l2cap_sock.c
+@@ -1449,6 +1449,10 @@ static void l2cap_sock_cleanup_listen(st
+        * pin it (hold_unless_zero() additionally skips a chan already past
+        * its last reference).  We then drop the sk lock before taking
+        * chan->lock, so sk and chan locks are never held together.
++       *
++       * Since we cannot call l2cap_chan_close() without conn->lock,
++       * schedule l2cap_chan_timeout to close the channel; it already
++       * acquires conn->lock -> chan->lock in the correct order.
+        */
+       while ((sk = bt_accept_dequeue(parent, NULL))) {
+               struct l2cap_chan *chan;
+@@ -1466,14 +1470,12 @@ static void l2cap_sock_cleanup_listen(st
+                      state_to_string(chan->state));
+               l2cap_chan_lock(chan);
+-              __clear_chan_timer(chan);
+-              l2cap_chan_close(chan, ECONNRESET);
+-              /* l2cap_conn_del() may already have killed this socket
+-               * (it sets SOCK_DEAD); skip the duplicate to avoid a
+-               * double sock_put()/l2cap_chan_put().
++              /* Since we cannot call l2cap_chan_close() without
++               * conn->lock, schedule its timer to trigger the close
++               * and cleanup of this channel.
+                */
+-              if (!sock_flag(sk, SOCK_DEAD))
+-                      l2cap_sock_kill(sk);
++              if (chan->conn)
++                      __set_chan_timer(chan, 0);
+               l2cap_chan_unlock(chan);
+               l2cap_chan_put(chan);
diff --git a/queue-5.15/bluetooth-mgmt-validate-add-extended-advertising-data-length.patch b/queue-5.15/bluetooth-mgmt-validate-add-extended-advertising-data-length.patch
new file mode 100644 (file)
index 0000000..6e390bf
--- /dev/null
@@ -0,0 +1,58 @@
+From stable+bounces-256806-greg=kroah.com@vger.kernel.org Sat May 30 04:54:05 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 19:22:04 -0400
+Subject: Bluetooth: MGMT: validate Add Extended Advertising Data length
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529232204.1873991-2-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit d3f7d17960ed50df3a6709c5158caff989c8c905 ]
+
+MGMT_OP_ADD_EXT_ADV_DATA is registered as a variable-length command,
+with MGMT_ADD_EXT_ADV_DATA_SIZE as the fixed header size.  The handler
+then uses cp->adv_data_len and cp->scan_rsp_len to validate and copy
+cp->data, but it never checks that those bytes are part of the mgmt
+command payload.
+
+A short command can therefore make add_ext_adv_data() pass an
+out-of-bounds pointer into tlv_data_is_valid().  If the bytes beyond
+the command buffer are addressable, they can also be copied into the
+advertising instance as scan response data, where the caller can read
+them back via MGMT_OP_GET_ADV_INSTANCE.  The trigger requires
+CAP_NET_ADMIN in the initial user namespace; KASAN reports an 8-byte
+slab-out-of-bounds read.
+
+Reject commands whose length does not match the fixed header plus both
+advertising data lengths before parsing cp->data.
+
+Fixes: 12410572833a ("Bluetooth: Break add adv into two mgmt commands")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/mgmt.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -8084,9 +8084,15 @@ static int add_ext_adv_data(struct sock
+       struct adv_info *adv_instance;
+       int err = 0;
+       struct mgmt_pending_cmd *cmd;
++      u16 expected_len;
+       BT_DBG("%s", hdev->name);
++      expected_len = struct_size(cp, data, cp->adv_data_len + cp->scan_rsp_len);
++      if (expected_len != data_len)
++              return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
++                                     MGMT_STATUS_INVALID_PARAMS);
++
+       hci_dev_lock(hdev);
+       adv_instance = hci_find_adv_instance(hdev, cp->instance);
diff --git a/queue-5.15/bluetooth-serialize-accept_q-access.patch b/queue-5.15/bluetooth-serialize-accept_q-access.patch
new file mode 100644 (file)
index 0000000..e53c682
--- /dev/null
@@ -0,0 +1,222 @@
+From stable+bounces-256824-greg=kroah.com@vger.kernel.org Sat May 30 05:08:35 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 19:38:26 -0400
+Subject: Bluetooth: serialize accept_q access
+To: stable@vger.kernel.org
+Cc: Jiexun Wang <wangjiexun2025@gmail.com>, Jann Horn <jannh@google.com>, Yuan Tan <yuantan098@gmail.com>, Yifan Wu <yifanwucs@gmail.com>, Juefei Pu <tomapufckgml@gmail.com>, Xin Liu <bird@lzu.edu.cn>, Ren Wei <n05ec@lzu.edu.cn>, Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529233826.1908632-3-sashal@kernel.org>
+
+From: Jiexun Wang <wangjiexun2025@gmail.com>
+
+[ Upstream commit e83f5e24da741fa9405aeeff00b08c5ee7c37b88 ]
+
+bt_sock_poll() walks the accept queue without synchronization, while
+child teardown can unlink the same socket and drop its last reference.
+The unsynchronized accept queue walk has existed since the initial
+Bluetooth import.
+
+Protect accept_q with a dedicated lock for queue updates and polling.
+Also rework bt_accept_dequeue() to take temporary child references under
+the queue lock before dropping it and locking the child socket.
+
+Fixes: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 ("Linux-2.6.12-rc2")
+Cc: stable@vger.kernel.org
+Reported-by: Jann Horn <jannh@google.com>
+Reported-by: Yuan Tan <yuantan098@gmail.com>
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Reported-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Jiexun Wang <wangjiexun2025@gmail.com>
+Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
+Signed-off-by: Jiexun Wang <wangjiexun2025@gmail.com>
+Reviewed-by: Jann Horn <jannh@google.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/bluetooth/bluetooth.h |    1 
+ net/bluetooth/af_bluetooth.c      |   87 ++++++++++++++++++++++++++++----------
+ 2 files changed, 66 insertions(+), 22 deletions(-)
+
+--- a/include/net/bluetooth/bluetooth.h
++++ b/include/net/bluetooth/bluetooth.h
+@@ -291,6 +291,7 @@ void baswap(bdaddr_t *dst, const bdaddr_
+ struct bt_sock {
+       struct sock sk;
+       struct list_head accept_q;
++      spinlock_t accept_q_lock; /* protects accept_q */
+       struct sock *parent;
+       unsigned long flags;
+       void (*skb_msg_name)(struct sk_buff *, void *, int *);
+--- a/net/bluetooth/af_bluetooth.c
++++ b/net/bluetooth/af_bluetooth.c
+@@ -149,6 +149,7 @@ struct sock *bt_sock_alloc(struct net *n
+       sock_init_data(sock, sk);
+       INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
++      spin_lock_init(&bt_sk(sk)->accept_q_lock);
+       sock_reset_flag(sk, SOCK_ZAPPED);
+@@ -209,6 +210,7 @@ void bt_accept_enqueue(struct sock *pare
+ {
+       const struct cred *old_cred;
+       struct pid *old_pid;
++      struct bt_sock *par = bt_sk(parent);
+       BT_DBG("parent %p, sk %p", parent, sk);
+@@ -219,9 +221,13 @@ void bt_accept_enqueue(struct sock *pare
+       else
+               lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
+-      list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q);
+       bt_sk(sk)->parent = parent;
++      spin_lock_bh(&par->accept_q_lock);
++      list_add_tail(&bt_sk(sk)->accept_q, &par->accept_q);
++      sk_acceptq_added(parent);
++      spin_unlock_bh(&par->accept_q_lock);
++
+       /* Copy credentials from parent since for incoming connections the
+        * socket is allocated by the kernel.
+        */
+@@ -239,8 +245,6 @@ void bt_accept_enqueue(struct sock *pare
+               bh_unlock_sock(sk);
+       else
+               release_sock(sk);
+-
+-      sk_acceptq_added(parent);
+ }
+ EXPORT_SYMBOL(bt_accept_enqueue);
+@@ -249,45 +253,72 @@ EXPORT_SYMBOL(bt_accept_enqueue);
+  */
+ void bt_accept_unlink(struct sock *sk)
+ {
++      struct sock *parent = bt_sk(sk)->parent;
++
+       BT_DBG("sk %p state %d", sk, sk->sk_state);
++      spin_lock_bh(&bt_sk(parent)->accept_q_lock);
+       list_del_init(&bt_sk(sk)->accept_q);
+-      sk_acceptq_removed(bt_sk(sk)->parent);
++      sk_acceptq_removed(parent);
++      spin_unlock_bh(&bt_sk(parent)->accept_q_lock);
+       bt_sk(sk)->parent = NULL;
+       sock_put(sk);
+ }
+ EXPORT_SYMBOL(bt_accept_unlink);
++static struct sock *bt_accept_get(struct sock *parent, struct sock *sk)
++{
++      struct bt_sock *bt = bt_sk(parent);
++      struct sock *next = NULL;
++
++      /* accept_q is modified from child teardown paths too, so take a
++       * temporary reference before dropping the queue lock.
++       */
++      spin_lock_bh(&bt->accept_q_lock);
++
++      if (sk) {
++              if (bt_sk(sk)->parent != parent)
++                      goto out;
++
++              if (!list_is_last(&bt_sk(sk)->accept_q, &bt->accept_q)) {
++                      next = &list_next_entry(bt_sk(sk), accept_q)->sk;
++                      sock_hold(next);
++              }
++      } else if (!list_empty(&bt->accept_q)) {
++              next = &list_first_entry(&bt->accept_q,
++                                       struct bt_sock, accept_q)->sk;
++              sock_hold(next);
++      }
++
++out:
++      spin_unlock_bh(&bt->accept_q_lock);
++      return next;
++}
++
+ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
+ {
+-      struct bt_sock *s, *n;
+-      struct sock *sk;
++      struct sock *sk, *next;
+       BT_DBG("parent %p", parent);
+ restart:
+-      list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) {
+-              sk = (struct sock *)s;
+-
++      for (sk = bt_accept_get(parent, NULL); sk; sk = next) {
+               /* Prevent early freeing of sk due to unlink and sock_kill */
+-              sock_hold(sk);
+               lock_sock(sk);
+               /* Check sk has not already been unlinked via
+                * bt_accept_unlink() due to serialisation caused by sk locking
+                */
+-              if (!bt_sk(sk)->parent) {
++              if (bt_sk(sk)->parent != parent) {
+                       BT_DBG("sk %p, already unlinked", sk);
+                       release_sock(sk);
+                       sock_put(sk);
+-                      /* Restart the loop as sk is no longer in the list
+-                       * and also avoid a potential infinite loop because
+-                       * list_for_each_entry_safe() is not thread safe.
+-                       */
+                       goto restart;
+               }
++              next = bt_accept_get(parent, sk);
++
+               /* sk is safely in the parent list so reduce reference count */
+               sock_put(sk);
+@@ -315,6 +346,8 @@ restart:
+                       sock_hold(sk);
+                       release_sock(sk);
++                      if (next)
++                              sock_put(next);
+                       return sk;
+               }
+@@ -513,18 +546,28 @@ EXPORT_SYMBOL(bt_sock_stream_recvmsg);
+ static inline __poll_t bt_accept_poll(struct sock *parent)
+ {
+-      struct bt_sock *s, *n;
++      struct bt_sock *bt = bt_sk(parent);
++      struct bt_sock *s;
+       struct sock *sk;
++      __poll_t mask = 0;
++
++      spin_lock_bh(&bt->accept_q_lock);
++      list_for_each_entry(s, &bt->accept_q, accept_q) {
++              int state;
+-      list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) {
+               sk = (struct sock *)s;
+-              if (sk->sk_state == BT_CONNECTED ||
+-                  (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags) &&
+-                   sk->sk_state == BT_CONNECT2))
+-                      return EPOLLIN | EPOLLRDNORM;
++              state = READ_ONCE(sk->sk_state);
++
++              if (state == BT_CONNECTED ||
++                  (test_bit(BT_SK_DEFER_SETUP, &bt->flags) &&
++                   state == BT_CONNECT2)) {
++                      mask = EPOLLIN | EPOLLRDNORM;
++                      break;
++              }
+       }
++      spin_unlock_bh(&bt->accept_q_lock);
+-      return 0;
++      return mask;
+ }
+ __poll_t bt_sock_poll(struct file *file, struct socket *sock,
diff --git a/queue-5.15/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch b/queue-5.15/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch
new file mode 100644 (file)
index 0000000..9e084b7
--- /dev/null
@@ -0,0 +1,59 @@
+From stable+bounces-247798-greg=kroah.com@vger.kernel.org Fri May 15 20:20:56 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 May 2026 10:48:27 -0400
+Subject: btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak
+To: stable@vger.kernel.org
+Cc: Yochai Eisenrich <yochaie@sweet.security>, Yochai Eisenrich <echelonh@gmail.com>, David Sterba <dsterba@suse.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260515144827.3249028-1-sashal@kernel.org>
+
+From: Yochai Eisenrich <yochaie@sweet.security>
+
+[ Upstream commit 973e57c726c1f8e77259d1c8e519519f1e9aea77 ]
+
+btrfs_ioctl_space_info() has a TOCTOU race between two passes over the
+block group RAID type lists. The first pass counts entries to determine
+the allocation size, then the second pass fills the buffer. The
+groups_sem rwlock is released between passes, allowing concurrent block
+group removal to reduce the entry count.
+
+When the second pass fills fewer entries than the first pass counted,
+copy_to_user() copies the full alloc_size bytes including trailing
+uninitialized kmalloc bytes to userspace.
+
+Fix by copying only total_spaces entries (the actually-filled count from
+the second pass) instead of alloc_size bytes, and switch to kzalloc so
+any future copy size mismatch cannot leak heap data.
+
+Fixes: 7fde62bffb57 ("Btrfs: buffer results in the space_info ioctl")
+CC: stable@vger.kernel.org # 3.0
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[ adapted upstream's `return -EFAULT;` to stable's `ret = -EFAULT;` fall-through to existing `out:` cleanup label ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/ioctl.c |    5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -3612,7 +3612,7 @@ static long btrfs_ioctl_space_info(struc
+               return -ENOMEM;
+       space_args.total_spaces = 0;
+-      dest = kmalloc(alloc_size, GFP_KERNEL);
++      dest = kzalloc(alloc_size, GFP_KERNEL);
+       if (!dest)
+               return -ENOMEM;
+       dest_orig = dest;
+@@ -3668,7 +3668,8 @@ static long btrfs_ioctl_space_info(struc
+       user_dest = (struct btrfs_ioctl_space_info __user *)
+               (arg + sizeof(struct btrfs_ioctl_space_args));
+-      if (copy_to_user(user_dest, dest_orig, alloc_size))
++      if (copy_to_user(user_dest, dest_orig,
++               space_args.total_spaces * sizeof(*dest_orig)))
+               ret = -EFAULT;
+       kfree(dest_orig);
diff --git a/queue-5.15/btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch b/queue-5.15/btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch
new file mode 100644 (file)
index 0000000..78798f7
--- /dev/null
@@ -0,0 +1,224 @@
+From stable+bounces-249151-greg=kroah.com@vger.kernel.org Mon May 18 04:35:06 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 17 May 2026 19:04:56 -0400
+Subject: btrfs: fix missing last_unlink_trans update when removing a directory
+To: stable@vger.kernel.org
+Cc: Filipe Manana <fdmanana@suse.com>, Slava0135 <slava.kovalevskiy.2014@gmail.com>, David Sterba <dsterba@suse.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260517230456.408419-1-sashal@kernel.org>
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit 999757231c49376cd1a37308d2c8c4c9932571e1 ]
+
+When removing a directory we are not updating its last_unlink_trans field,
+which can result in incorrect fsync behaviour in case some one fsyncs the
+directory after it was removed because it's holding a file descriptor on
+it.
+
+Example scenario:
+
+   mkdir /mnt/dir1
+   mkdir /mnt/dir1/dir2
+   mkdir /mnt/dir3
+
+   sync -f /mnt
+
+   # Do some change to the directory and fsync it.
+   chmod 700 /mnt/dir1
+   xfs_io -c fsync /mnt/dir1
+
+   # Move dir2 out of dir1 so that dir1 becomes empty.
+   mv /mnt/dir1/dir2 /mnt/dir3/
+
+   open fd on /mnt/dir1
+   call rmdir(2) on path "/mnt/dir1"
+   fsync fd
+
+   <trigger power failure>
+
+When attempting to mount the filesystem, the log replay will fail with
+an -EIO error and dmesg/syslog has the following:
+
+   [445771.626482] BTRFS info (device dm-0): first mount of filesystem 0368bbea-6c5e-44b5-b409-09abe496e650
+   [445771.626486] BTRFS info (device dm-0): using crc32c checksum algorithm
+   [445771.627912] BTRFS info (device dm-0): start tree-log replay
+   [445771.628335] page: refcount:2 mapcount:0 mapping:0000000061443ddc index:0x1d00 pfn:0x7072a5
+   [445771.629453] memcg:ffff89f400351b00
+   [445771.629892] aops:btree_aops [btrfs] ino:1
+   [445771.630737] flags: 0x17fffc00000402a(uptodate|lru|private|writeback|node=0|zone=2|lastcpupid=0x1ffff)
+   [445771.632359] raw: 017fffc00000402a fffff47284d950c8 fffff472907b7c08 ffff89f458e412b8
+   [445771.633713] raw: 0000000000001d00 ffff89f6c51d1a90 00000002ffffffff ffff89f400351b00
+   [445771.635029] page dumped because: eb page dump
+   [445771.635825] BTRFS critical (device dm-0): corrupt leaf: root=5 block=30408704 slot=10 ino=258, invalid nlink: has 2 expect no more than 1 for dir
+   [445771.638088] BTRFS info (device dm-0): leaf 30408704 gen 10 total ptrs 17 free space 14878 owner 5
+   [445771.638091] BTRFS info (device dm-0): refs 4 lock_owner 0 current 3581087
+   [445771.638094]     item 0 key (256 INODE_ITEM 0) itemoff 16123 itemsize 160
+   [445771.638097]             inode generation 3 transid 9 size 16 nbytes 16384
+   [445771.638098]             block group 0 mode 40755 links 1 uid 0 gid 0
+   [445771.638100]             rdev 0 sequence 2 flags 0x0
+   [445771.638102]             atime 1775744884.0
+   [445771.660056]             ctime 1775744885.645502983
+   [445771.660058]             mtime 1775744885.645502983
+   [445771.660060]             otime 1775744884.0
+   [445771.660062]     item 1 key (256 INODE_REF 256) itemoff 16111 itemsize 12
+   [445771.660064]             index 0 name_len 2
+   [445771.660066]     item 2 key (256 DIR_ITEM 1843588421) itemoff 16077 itemsize 34
+   [445771.660068]             location key (259 1 0) type 2
+   [445771.660070]             transid 9 data_len 0 name_len 4
+   [445771.660075]     item 3 key (256 DIR_ITEM 2363071922) itemoff 16043 itemsize 34
+   [445771.660076]             location key (257 1 0) type 2
+   [445771.660077]             transid 9 data_len 0 name_len 4
+   [445771.660078]     item 4 key (256 DIR_INDEX 2) itemoff 16009 itemsize 34
+   [445771.660079]             location key (257 1 0) type 2
+   [445771.660080]             transid 9 data_len 0 name_len 4
+   [445771.660081]     item 5 key (256 DIR_INDEX 3) itemoff 15975 itemsize 34
+   [445771.660082]             location key (259 1 0) type 2
+   [445771.660083]             transid 9 data_len 0 name_len 4
+   [445771.660084]     item 6 key (257 INODE_ITEM 0) itemoff 15815 itemsize 160
+   [445771.660086]             inode generation 9 transid 9 size 8 nbytes 0
+   [445771.660087]             block group 0 mode 40777 links 1 uid 0 gid 0
+   [445771.660088]             rdev 0 sequence 2 flags 0x0
+   [445771.660089]             atime 1775744885.641174097
+   [445771.660090]             ctime 1775744885.645502983
+   [445771.660091]             mtime 1775744885.645502983
+   [445771.660105]             otime 1775744885.641174097
+   [445771.660106]     item 7 key (257 INODE_REF 256) itemoff 15801 itemsize 14
+   [445771.660107]             index 2 name_len 4
+   [445771.660108]     item 8 key (257 DIR_ITEM 2676584006) itemoff 15767 itemsize 34
+   [445771.660109]             location key (258 1 0) type 2
+   [445771.660110]             transid 9 data_len 0 name_len 4
+   [445771.660111]     item 9 key (257 DIR_INDEX 2) itemoff 15733 itemsize 34
+   [445771.660112]             location key (258 1 0) type 2
+   [445771.660113]             transid 9 data_len 0 name_len 4
+   [445771.660114]     item 10 key (258 INODE_ITEM 0) itemoff 15573 itemsize 160
+   [445771.660115]             inode generation 9 transid 10 size 0 nbytes 0
+   [445771.660116]             block group 0 mode 40755 links 2 uid 0 gid 0
+   [445771.660117]             rdev 0 sequence 0 flags 0x0
+   [445771.660118]             atime 1775744885.645502983
+   [445771.660119]             ctime 1775744885.645502983
+   [445771.660120]             mtime 1775744885.645502983
+   [445771.660121]             otime 1775744885.645502983
+   [445771.660122]     item 11 key (258 INODE_REF 257) itemoff 15559 itemsize 14
+   [445771.660123]             index 2 name_len 4
+   [445771.660124]     item 12 key (258 INODE_REF 259) itemoff 15545 itemsize 14
+   [445771.660125]             index 2 name_len 4
+   [445771.660126]     item 13 key (259 INODE_ITEM 0) itemoff 15385 itemsize 160
+   [445771.660127]             inode generation 9 transid 10 size 8 nbytes 0
+   [445771.660128]             block group 0 mode 40755 links 1 uid 0 gid 0
+   [445771.660129]             rdev 0 sequence 1 flags 0x0
+   [445771.660130]             atime 1775744885.645502983
+   [445771.660130]             ctime 1775744885.645502983
+   [445771.660131]             mtime 1775744885.645502983
+   [445771.660132]             otime 1775744885.645502983
+   [445771.660133]     item 14 key (259 INODE_REF 256) itemoff 15371 itemsize 14
+   [445771.660134]             index 3 name_len 4
+   [445771.660135]     item 15 key (259 DIR_ITEM 2676584006) itemoff 15337 itemsize 34
+   [445771.660136]             location key (258 1 0) type 2
+   [445771.660137]             transid 10 data_len 0 name_len 4
+   [445771.660138]     item 16 key (259 DIR_INDEX 2) itemoff 15303 itemsize 34
+   [445771.660139]             location key (258 1 0) type 2
+   [445771.660140]             transid 10 data_len 0 name_len 4
+   [445771.660144] BTRFS error (device dm-0): block=30408704 write time tree block corruption detected
+   [445771.661650] ------------[ cut here ]------------
+   [445771.662358] WARNING: fs/btrfs/disk-io.c:326 at btree_csum_one_bio+0x217/0x230 [btrfs], CPU#8: mount/3581087
+   [445771.663588] Modules linked in: btrfs f2fs xfs (...)
+   [445771.671229] CPU: 8 UID: 0 PID: 3581087 Comm: mount Tainted: G        W           7.0.0-rc6-btrfs-next-230+ #2 PREEMPT(full)
+   [445771.672575] Tainted: [W]=WARN
+   [445771.672987] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014
+   [445771.674460] RIP: 0010:btree_csum_one_bio+0x217/0x230 [btrfs]
+   [445771.675222] Code: 89 44 24 (...)
+   [445771.677364] RSP: 0018:ffffd23882247660 EFLAGS: 00010246
+   [445771.678029] RAX: 0000000000000000 RBX: ffff89f6c51d1a90 RCX: 0000000000000000
+   [445771.678975] RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff89f406020000
+   [445771.679983] RBP: ffff89f821204000 R08: 0000000000000000 R09: 00000000ffefffff
+   [445771.680905] R10: ffffd23882247448 R11: 0000000000000003 R12: ffffd23882247668
+   [445771.681978] R13: ffff89f458e40fc0 R14: ffff89f737f4f500 R15: ffff89f737f4f500
+   [445771.682912] FS:  00007f0447a98840(0000) GS:ffff89fb9771d000(0000) knlGS:0000000000000000
+   [445771.684393] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+   [445771.685230] CR2: 00007f0447bf1330 CR3: 000000017cb02002 CR4: 0000000000370ef0
+   [445771.686273] Call Trace:
+   [445771.686646]  <TASK>
+   [445771.686969]  btrfs_submit_bbio+0x83f/0x860 [btrfs]
+   [445771.687750]  ? write_one_eb+0x28f/0x340 [btrfs]
+   [445771.688428]  btree_writepages+0x2e3/0x550 [btrfs]
+   [445771.689180]  ? kmem_cache_alloc_noprof+0x12a/0x490
+   [445771.689963]  ? alloc_extent_state+0x19/0x120 [btrfs]
+   [445771.690801]  ? kmem_cache_free+0x135/0x380
+   [445771.691328]  ? preempt_count_add+0x69/0xa0
+   [445771.691831]  ? set_extent_bit+0x252/0x8e0 [btrfs]
+   [445771.692468]  ? xas_load+0x9/0xc0
+   [445771.692873]  ? xas_find+0x14d/0x1a0
+   [445771.693304]  do_writepages+0xc6/0x160
+   [445771.693756]  filemap_writeback+0xb8/0xe0
+   [445771.694274]  btrfs_write_marked_extents+0x61/0x170 [btrfs]
+   [445771.694999]  btrfs_write_and_wait_transaction+0x4e/0xc0 [btrfs]
+   [445771.695818]  btrfs_commit_transaction+0x5c8/0xd10 [btrfs]
+   [445771.696530]  ? kmem_cache_free+0x135/0x380
+   [445771.697120]  ? release_extent_buffer+0x34/0x160 [btrfs]
+   [445771.697786]  btrfs_recover_log_trees+0x7be/0x7e0 [btrfs]
+   [445771.698525]  ? __pfx_replay_one_buffer+0x10/0x10 [btrfs]
+   [445771.699206]  open_ctree+0x11e5/0x1810 [btrfs]
+   [445771.699776]  btrfs_get_tree.cold+0xb/0x162 [btrfs]
+   [445771.700463]  ? fscontext_read+0x165/0x180
+   [445771.701146]  ? rw_verify_area+0x50/0x180
+   [445771.701866]  vfs_get_tree+0x25/0xd0
+   [445771.702491]  vfs_cmd_create+0x59/0xe0
+   [445771.703125]  __do_sys_fsconfig+0x303/0x610
+   [445771.703603]  do_syscall_64+0xe9/0xf20
+   [445771.703974]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
+   [445771.704700] RIP: 0033:0x7f0447cbd4aa
+   [445771.705108] Code: 73 01 c3 (...)
+   [445771.707263] RSP: 002b:00007ffc4e528318 EFLAGS: 00000246 ORIG_RAX: 00000000000001af
+   [445771.708107] RAX: ffffffffffffffda RBX: 00005561585d8c20 RCX: 00007f0447cbd4aa
+   [445771.708931] RDX: 0000000000000000 RSI: 0000000000000006 RDI: 0000000000000003
+   [445771.709744] RBP: 00005561585d9120 R08: 0000000000000000 R09: 0000000000000000
+   [445771.710674] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+   [445771.711477] R13: 00007f0447e4f580 R14: 00007f0447e5126c R15: 00007f0447e36a23
+   [445771.712277]  </TASK>
+   [445771.712541] ---[ end trace 0000000000000000 ]---
+   [445771.713382] BTRFS error (device dm-0): error while writing out transaction: -5
+   [445771.714679] BTRFS warning (device dm-0): Skipping commit of aborted transaction.
+   [445771.715562] BTRFS error (device dm-0 state A): Transaction aborted (error -5)
+   [445771.716459] BTRFS: error (device dm-0 state A) in cleanup_transaction:2068: errno=-5 IO failure
+   [445771.717936] BTRFS error (device dm-0 state EA): failed to recover log trees with error: -5
+   [445771.719681] BTRFS error (device dm-0 state EA): open_ctree failed: -5
+
+The problem is that such a fsync should have result in a fallback to a
+transaction commit, but that did not happen because through the
+btrfs_rmdir() we never update the directory's last_unlink_trans field.
+Any inode that had a link removed must have its last_unlink_trans updated
+to the ID of transaction used for the operation, otherwise fsync and log
+replay will not work correctly.
+
+btrfs_rmdir() calls btrfs_unlink_inode() and through that call chain we
+never call btrfs_record_unlink_dir() in order to update last_unlink_trans.
+However btrfs_unlink(), which is used for unlinking regular files, calls
+btrfs_record_unlink_dir() and then calls btrfs_unlink_inode(). So fix
+this by moving the call to btrfs_record_unlink_dir() from btrfs_unlink()
+to btrfs_unlink_inode().
+
+A test case for fstests will follow soon.
+
+Reported-by: Slava0135 <slava.kovalevskiy.2014@gmail.com>
+Link: https://lore.kernel.org/linux-btrfs/CAAJYhww5ov62Hm+n+tmhcL-e_4cBobg+OWogKjOJxVUXivC=MQ@mail.gmail.com/
+CC: stable@vger.kernel.org
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[ wrapped dir and inode arguments with BTRFS_I() since 6.1 btrfs_rmdir() uses struct inode * instead of struct btrfs_inode * ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/inode.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -4691,6 +4691,8 @@ static int btrfs_rmdir(struct inode *dir
+       if (err)
+               goto out;
++      btrfs_record_unlink_dir(trans, BTRFS_I(dir), BTRFS_I(inode), false);
++
+       /* now the directory is empty */
+       err = btrfs_unlink_inode(trans, BTRFS_I(dir),
+                       BTRFS_I(d_inode(dentry)), dentry->d_name.name,
diff --git a/queue-5.15/drm-hyperv-remove-support-for-hyper-v-2008-and-2008r2-win7.patch b/queue-5.15/drm-hyperv-remove-support-for-hyper-v-2008-and-2008r2-win7.patch
new file mode 100644 (file)
index 0000000..1098ab6
--- /dev/null
@@ -0,0 +1,93 @@
+From stable+bounces-260841-greg=kroah.com@vger.kernel.org Sat Jun  6 07:49:19 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 22:19:00 -0400
+Subject: drm/hyperv: Remove support for Hyper-V 2008 and 2008R2/Win7
+To: stable@vger.kernel.org
+Cc: Michael Kelley <mikelley@microsoft.com>, Deepak Rawat <drawat.floss@gmail.com>, "Andrea Parri (Microsoft)" <parri.andrea@gmail.com>, Wei Liu <wei.liu@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606021901.2488724-1-sashal@kernel.org>
+
+From: Michael Kelley <mikelley@microsoft.com>
+
+[ Upstream commit ac6811a9b36f3ceb549d8b84bd8aeedf6026df02 ]
+
+The DRM Hyper-V driver has special case code for running on the first
+released versions of Hyper-V: 2008 and 2008 R2/Windows 7.  These versions
+are now out of support (except for extended security updates) and lack
+support for performance features that are needed for effective production
+usage of Linux guests.
+
+The negotiation of the VMbus protocol versions required by these old
+Hyper-V versions has been removed from the VMbus driver.  So now remove
+the handling of these VMbus protocol versions from the DRM Hyper-V
+driver.
+
+Signed-off-by: Michael Kelley <mikelley@microsoft.com>
+Reviewed-by: Deepak Rawat <drawat.floss@gmail.com>
+Reviewed-by: Andrea Parri (Microsoft) <parri.andrea@gmail.com>
+Link: https://lore.kernel.org/r/1651509391-2058-5-git-send-email-mikelley@microsoft.com
+Signed-off-by: Wei Liu <wei.liu@kernel.org>
+Stable-dep-of: 13d33b9ef670 ("drm/hyperv: validate resolution_count and fix WIN8 fallback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/hyperv/hyperv_drm_proto.c |   23 +++++++----------------
+ 1 file changed, 7 insertions(+), 16 deletions(-)
+
+--- a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
++++ b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
+@@ -18,16 +18,16 @@
+ #define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
+ #define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x0000ffff)
+ #define SYNTHVID_VER_GET_MINOR(ver) ((ver & 0xffff0000) >> 16)
++
++/* Support for VERSION_WIN7 is removed. #define is retained for reference. */
+ #define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
+ #define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
+ #define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
+-#define SYNTHVID_DEPTH_WIN7 16
+ #define SYNTHVID_DEPTH_WIN8 32
+-#define SYNTHVID_FB_SIZE_WIN7 (4 * 1024 * 1024)
++#define SYNTHVID_WIDTH_WIN8 1600
++#define SYNTHVID_HEIGHT_WIN8 1200
+ #define SYNTHVID_FB_SIZE_WIN8 (8 * 1024 * 1024)
+-#define SYNTHVID_WIDTH_MAX_WIN7 1600
+-#define SYNTHVID_HEIGHT_MAX_WIN7 1200
+ enum pipe_msg_type {
+       PIPE_MSG_INVALID,
+@@ -570,12 +570,6 @@ int hyperv_connect_vsp(struct hv_device
+       case VERSION_WIN8:
+       case VERSION_WIN8_1:
+               ret = hyperv_negotiate_version(hdev, SYNTHVID_VERSION_WIN8);
+-              if (!ret)
+-                      break;
+-              fallthrough;
+-      case VERSION_WS2008:
+-      case VERSION_WIN7:
+-              ret = hyperv_negotiate_version(hdev, SYNTHVID_VERSION_WIN7);
+               break;
+       default:
+               ret = hyperv_negotiate_version(hdev, SYNTHVID_VERSION_WIN10);
+@@ -587,18 +581,15 @@ int hyperv_connect_vsp(struct hv_device
+               goto error;
+       }
+-      if (hv->synthvid_version == SYNTHVID_VERSION_WIN7)
+-              hv->screen_depth = SYNTHVID_DEPTH_WIN7;
+-      else
+-              hv->screen_depth = SYNTHVID_DEPTH_WIN8;
++      hv->screen_depth = SYNTHVID_DEPTH_WIN8;
+       if (hyperv_version_ge(hv->synthvid_version, SYNTHVID_VERSION_WIN10)) {
+               ret = hyperv_get_supported_resolution(hdev);
+               if (ret)
+                       drm_err(dev, "Failed to get supported resolution from host, use default\n");
+       } else {
+-              hv->screen_width_max = SYNTHVID_WIDTH_MAX_WIN7;
+-              hv->screen_height_max = SYNTHVID_HEIGHT_MAX_WIN7;
++              hv->screen_width_max = SYNTHVID_WIDTH_WIN8;
++              hv->screen_height_max = SYNTHVID_HEIGHT_WIN8;
+       }
+       hv->mmio_megabytes = hdev->channel->offermsg.offer.mmio_megabytes;
diff --git a/queue-5.15/drm-hyperv-validate-resolution_count-and-fix-win8-fallback.patch b/queue-5.15/drm-hyperv-validate-resolution_count-and-fix-win8-fallback.patch
new file mode 100644 (file)
index 0000000..f41a831
--- /dev/null
@@ -0,0 +1,71 @@
+From stable+bounces-260842-greg=kroah.com@vger.kernel.org Sat Jun  6 07:49:28 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 22:19:01 -0400
+Subject: drm/hyperv: validate resolution_count and fix WIN8 fallback
+To: stable@vger.kernel.org
+Cc: Berkant Koc <me@berkoc.com>, Michael Kelley <mhklinux@outlook.com>, Hamza Mahfooz <hamzamahfooz@linux.microsoft.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606021901.2488724-2-sashal@kernel.org>
+
+From: Berkant Koc <me@berkoc.com>
+
+[ Upstream commit 13d33b9ef67066c77c84273fac5a1d3fde3533d1 ]
+
+A SYNTHVID_RESOLUTION_RESPONSE with resolution_count > 64 walks past
+the supported_resolution[SYNTHVID_MAX_RESOLUTION_COUNT] array in the
+parse loop. Bound resolution_count against the array size, folded
+into the existing zero-check.
+
+When the WIN10 resolution probe fails, the caller in
+hyperv_connect_vsp() left hv->screen_*_max / preferred_* unpopulated,
+which sets mode_config.max_width / max_height to 0 and makes
+drm_internal_framebuffer_create() reject every userspace framebuffer
+with -EINVAL. The pre-WIN10 branch had the same gap for
+preferred_width / preferred_height. Use a single post-probe fallback
+guarded by screen_width_max == 0 so both paths converge on the WIN8
+defaults.
+
+Signed-off-by: Berkant Koc <me@berkoc.com>
+Assisted-by: Claude:claude-opus-4-7 berkoc-pipeline
+Fixes: 76c56a5affeb ("drm/hyperv: Add DRM driver for hyperv synthetic video device")
+Cc: stable@vger.kernel.org # 5.14+
+Reviewed-by: Michael Kelley <mhklinux@outlook.com>
+Tested-by: Michael Kelley <mhklinux@outlook.com>
+Signed-off-by: Hamza Mahfooz <hamzamahfooz@linux.microsoft.com>
+Link: https://patch.msgid.link/6945b22419c7d404b4954a113de2ac9c900dba93.1779542874.git.me@berkoc.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/hyperv/hyperv_drm_proto.c |   13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
++++ b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
+@@ -396,8 +396,11 @@ static int hyperv_get_supported_resoluti
+               return -ETIMEDOUT;
+       }
+-      if (msg->resolution_resp.resolution_count == 0) {
+-              drm_err(dev, "No supported resolutions\n");
++      if (msg->resolution_resp.resolution_count == 0 ||
++          msg->resolution_resp.resolution_count >
++          SYNTHVID_MAX_RESOLUTION_COUNT) {
++              drm_err(dev, "Invalid resolution count: %d\n",
++                      msg->resolution_resp.resolution_count);
+               return -ENODEV;
+       }
+@@ -587,9 +590,13 @@ int hyperv_connect_vsp(struct hv_device
+               ret = hyperv_get_supported_resolution(hdev);
+               if (ret)
+                       drm_err(dev, "Failed to get supported resolution from host, use default\n");
+-      } else {
++      }
++
++      if (!hv->screen_width_max) {
+               hv->screen_width_max = SYNTHVID_WIDTH_WIN8;
+               hv->screen_height_max = SYNTHVID_HEIGHT_WIN8;
++              hv->preferred_width = SYNTHVID_WIDTH_WIN8;
++              hv->preferred_height = SYNTHVID_HEIGHT_WIN8;
+       }
+       hv->mmio_megabytes = hdev->channel->offermsg.offer.mmio_megabytes;
diff --git a/queue-5.15/f2fs-fix-false-alarm-of-lockdep-on-cp_global_sem-lock.patch b/queue-5.15/f2fs-fix-false-alarm-of-lockdep-on-cp_global_sem-lock.patch
new file mode 100644 (file)
index 0000000..33ebbdd
--- /dev/null
@@ -0,0 +1,102 @@
+From stable+bounces-249897-greg=kroah.com@vger.kernel.org Wed May 20 17:21:50 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 20 May 2026 07:49:07 -0400
+Subject: f2fs: fix false alarm of lockdep on cp_global_sem lock
+To: stable@vger.kernel.org
+Cc: Chao Yu <chao@kernel.org>, stable@kernel.org, Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260520114907.3473814-1-sashal@kernel.org>
+
+From: Chao Yu <chao@kernel.org>
+
+[ Upstream commit 6a5e3de9c2bb0b691d16789a5d19e9276a09b308 ]
+
+lockdep reported a potential deadlock:
+
+a) TCMU device removal context:
+ - call del_gendisk() to get q->q_usage_counter
+ - call start_flush_work() to get work_completion of wb->dwork
+b) f2fs writeback context:
+ - in wb_workfn(), which holds work_completion of wb->dwork
+ - call f2fs_balance_fs() to get sbi->gc_lock
+c) f2fs vfs_write context:
+ - call f2fs_gc() to get sbi->gc_lock
+ - call f2fs_write_checkpoint() to get sbi->cp_global_sem
+d) f2fs mount context:
+ - call recover_fsync_data() to get sbi->cp_global_sem
+ - call f2fs_check_and_fix_write_pointer() to call blkdev_report_zones()
+   that goes down to blk_mq_alloc_request and get q->q_usage_counter
+
+Original callstack is in Closes tag.
+
+However, I think this is a false alarm due to before mount returns
+successfully (context d), we can not access file therein via vfs_write
+(context c).
+
+Let's introduce per-sb cp_global_sem_key, and assign the key for
+cp_global_sem, so that lockdep can recognize cp_global_sem from
+different super block correctly.
+
+A lot of work are done by Shin'ichiro Kawasaki, thanks a lot for
+the work.
+
+Fixes: c426d99127b1 ("f2fs: Check write pointer consistency of open zones")
+Cc: stable@kernel.org
+Reported-and-tested-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Closes: https://lore.kernel.org/linux-f2fs-devel/20260218125237.3340441-1-shinichiro.kawasaki@wdc.com
+Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Signed-off-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[ adapted to plain `struct rw_semaphore` (no `f2fs_rwsem` wrapper) and moved success-path `lockdep_unregister_key` from `kill_f2fs_super` to `f2fs_put_super` where sbi is actually freed ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/f2fs.h  |    3 +++
+ fs/f2fs/super.c |   11 +++++++++++
+ 2 files changed, 14 insertions(+)
+
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -1798,6 +1798,9 @@ struct f2fs_sb_info {
+       spinlock_t iostat_lat_lock;
+       struct iostat_lat_info *iostat_io_lat;
+ #endif
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++      struct lock_class_key cp_global_sem_key;
++#endif
+ };
+ struct f2fs_private_dio {
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1668,6 +1668,9 @@ static void f2fs_put_super(struct super_
+ #ifdef CONFIG_UNICODE
+       utf8_unload(sb->s_encoding);
+ #endif
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++      lockdep_unregister_key(&sbi->cp_global_sem_key);
++#endif
+       kfree(sbi);
+ }
+@@ -4123,6 +4126,11 @@ try_onemore:
+       init_rwsem(&sbi->gc_lock);
+       mutex_init(&sbi->writepages);
+       init_rwsem(&sbi->cp_global_sem);
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++      lockdep_register_key(&sbi->cp_global_sem_key);
++      lockdep_set_class(&sbi->cp_global_sem,
++                                      &sbi->cp_global_sem_key);
++#endif
+       init_rwsem(&sbi->node_write);
+       init_rwsem(&sbi->node_change);
+@@ -4524,6 +4532,9 @@ free_sb_buf:
+ free_sbi:
+       if (sbi->s_chksum_driver)
+               crypto_free_shash(sbi->s_chksum_driver);
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++      lockdep_unregister_key(&sbi->cp_global_sem_key);
++#endif
+       kfree(sbi);
+       /* give only one another chance */
diff --git a/queue-5.15/f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch b/queue-5.15/f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch
new file mode 100644 (file)
index 0000000..aaf9ea6
--- /dev/null
@@ -0,0 +1,68 @@
+From stable+bounces-249887-greg=kroah.com@vger.kernel.org Wed May 20 17:13:11 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 20 May 2026 07:29:13 -0400
+Subject: f2fs: fix incorrect file address mapping when inline inode is unwritten
+To: stable@vger.kernel.org
+Cc: Yongpeng Yang <yangyongpeng@xiaomi.com>, stable@kernel.org, Chao Yu <chao@kernel.org>, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260520112913.3439673-1-sashal@kernel.org>
+
+From: Yongpeng Yang <yangyongpeng@xiaomi.com>
+
+[ Upstream commit 68a0178981a0f493295afa29f8880246e561494c ]
+
+When `fileinfo->fi_flags` does not have the `FIEMAP_FLAG_SYNC` bit set
+and inline data has not been persisted yet, the physical address of the
+extent is calculated incorrectly for unwritten inline inodes.
+
+root@vm:/mnt/f2fs# dd if=/dev/zero of=data.3k bs=3k count=1
+root@vm:/mnt/f2fs# f2fs_io fiemap 0 100 data.3k
+Fiemap: offset = 0 len = 100
+       logical addr.    physical addr.   length           flags
+0      0000000000000000 00000ffffffff16c 0000000000000c00 00000301
+
+This patch fixes the issue by checking if the inode's address is valid.
+If the inline inode is unwritten, set the physical address to 0 and
+mark the extent with `FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_DELALLOC`
+flags.
+
+Cc: stable@kernel.org
+Fixes: 67f8cf3cee6f ("f2fs: support fiemap for inline_data")
+Signed-off-by: Yongpeng Yang <yangyongpeng@xiaomi.com>
+Reviewed-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[ renamed `ifolio` to `ipage` in `inline_data_addr()` and `F2FS_INODE()` calls ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/inline.c |   13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/fs/f2fs/inline.c
++++ b/fs/f2fs/inline.c
+@@ -771,7 +771,7 @@ int f2fs_read_inline_dir(struct file *fi
+ int f2fs_inline_data_fiemap(struct inode *inode,
+               struct fiemap_extent_info *fieinfo, __u64 start, __u64 len)
+ {
+-      __u64 byteaddr, ilen;
++      __u64 byteaddr = 0, ilen;
+       __u32 flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_NOT_ALIGNED |
+               FIEMAP_EXTENT_LAST;
+       struct node_info ni;
+@@ -804,9 +804,14 @@ int f2fs_inline_data_fiemap(struct inode
+       if (err)
+               goto out;
+-      byteaddr = (__u64)ni.blk_addr << inode->i_sb->s_blocksize_bits;
+-      byteaddr += (char *)inline_data_addr(inode, ipage) -
+-                                      (char *)F2FS_INODE(ipage);
++      if (__is_valid_data_blkaddr(ni.blk_addr)) {
++              byteaddr = (__u64)ni.blk_addr << inode->i_sb->s_blocksize_bits;
++              byteaddr += (char *)inline_data_addr(inode, ipage) -
++                                              (char *)F2FS_INODE(ipage);
++      } else {
++              f2fs_bug_on(F2FS_I_SB(inode), ni.blk_addr != NEW_ADDR);
++              flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN;
++      }
+       err = fiemap_fill_next_extent(fieinfo, start, byteaddr, ilen, flags);
+       trace_f2fs_fiemap(inode, start, byteaddr, ilen, flags, err);
+ out:
diff --git a/queue-5.15/fbcon-avoid-oob-font-access-if-console-rotation-fails.patch b/queue-5.15/fbcon-avoid-oob-font-access-if-console-rotation-fails.patch
new file mode 100644 (file)
index 0000000..6dbd631
--- /dev/null
@@ -0,0 +1,56 @@
+From stable+bounces-247682-greg=kroah.com@vger.kernel.org Fri May 15 17:52:20 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 May 2026 07:45:20 -0400
+Subject: fbcon: Avoid OOB font access if console rotation fails
+To: stable@vger.kernel.org
+Cc: Thomas Zimmermann <tzimmermann@suse.de>, Helge Deller <deller@gmx.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260515114520.3021992-1-sashal@kernel.org>
+
+From: Thomas Zimmermann <tzimmermann@suse.de>
+
+[ Upstream commit e4ef723d8975a2694cc90733a6b888a5e2841842 ]
+
+Clear the font buffer if the reallocation during console rotation fails
+in fbcon_rotate_font(). The putcs implementations for the rotated buffer
+will return early in this case. See [1] for an example.
+
+Currently, fbcon_rotate_font() keeps the old buffer, which is too small
+for the rotated font. Printing to the rotated console with a high-enough
+character code will overflow the font buffer.
+
+v2:
+- fix typos in commit message
+
+Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
+Fixes: 6cc50e1c5b57 ("[PATCH] fbcon: Console Rotation - Add support to rotate font bitmap")
+Cc: stable@vger.kernel.org # v2.6.15+
+Link: https://elixir.bootlin.com/linux/v6.19/source/drivers/video/fbdev/core/fbcon_ccw.c#L144 # [1]
+Signed-off-by: Helge Deller <deller@gmx.de>
+[ renamed `par` to `ops` to match the 6.12 local pointer name ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/video/fbdev/core/fbcon_rotate.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/video/fbdev/core/fbcon_rotate.c
++++ b/drivers/video/fbdev/core/fbcon_rotate.c
+@@ -46,6 +46,10 @@ static int fbcon_rotate_font(struct fb_i
+               info->fbops->fb_sync(info);
+       if (ops->fd_size < d_cellsize * len) {
++              kfree(ops->fontbuffer);
++              ops->fontbuffer = NULL;
++              ops->fd_size = 0;
++
+               dst = kmalloc_array(len, d_cellsize, GFP_KERNEL);
+               if (dst == NULL) {
+@@ -54,7 +58,6 @@ static int fbcon_rotate_font(struct fb_i
+               }
+               ops->fd_size = d_cellsize * len;
+-              kfree(ops->fontbuffer);
+               ops->fontbuffer = dst;
+       }
diff --git a/queue-5.15/genetlink-use-internal-flags-for-multicast-groups.patch b/queue-5.15/genetlink-use-internal-flags-for-multicast-groups.patch
new file mode 100644 (file)
index 0000000..7f5163e
--- /dev/null
@@ -0,0 +1,116 @@
+From stable+bounces-256670-greg=kroah.com@vger.kernel.org Fri May 29 22:58:06 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 13:21:52 -0400
+Subject: genetlink: Use internal flags for multicast groups
+To: stable@vger.kernel.org
+Cc: Ido Schimmel <idosch@nvidia.com>, Mat Martineau <martineau@kernel.org>, Andy Shevchenko <andriy.shevchenko@linux.intel.com>, "David S. Miller" <davem@davemloft.net>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529172153.1318415-1-sashal@kernel.org>
+
+From: Ido Schimmel <idosch@nvidia.com>
+
+[ Upstream commit cd4d7263d58ab98fd4dee876776e4da6c328faa3 ]
+
+As explained in commit e03781879a0d ("drop_monitor: Require
+'CAP_SYS_ADMIN' when joining "events" group"), the "flags" field in the
+multicast group structure reuses uAPI flags despite the field not being
+exposed to user space. This makes it impossible to extend its use
+without adding new uAPI flags, which is inappropriate for internal
+kernel checks.
+
+Solve this by adding internal flags (i.e., "GENL_MCAST_*") and convert
+the existing users to use them instead of the uAPI flags.
+
+Tested using the reproducers in commit 44ec98ea5ea9 ("psample: Require
+'CAP_NET_ADMIN' when joining "packets" group") and commit e03781879a0d
+("drop_monitor: Require 'CAP_SYS_ADMIN' when joining "events" group").
+
+No functional changes intended.
+
+Signed-off-by: Ido Schimmel <idosch@nvidia.com>
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: d1ebfce2c1d1 ("smb: client: require net admin for CIFS SWN netlink")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/genetlink.h |    9 ++++++---
+ net/core/drop_monitor.c |    2 +-
+ net/mptcp/pm_netlink.c  |    2 +-
+ net/netlink/genetlink.c |    4 ++--
+ net/psample/psample.c   |    2 +-
+ 5 files changed, 11 insertions(+), 8 deletions(-)
+
+--- a/include/net/genetlink.h
++++ b/include/net/genetlink.h
+@@ -8,16 +8,19 @@
+ #define GENLMSG_DEFAULT_SIZE (NLMSG_DEFAULT_SIZE - GENL_HDRLEN)
++/* Binding to multicast group requires %CAP_NET_ADMIN */
++#define GENL_MCAST_CAP_NET_ADMIN      BIT(0)
++/* Binding to multicast group requires %CAP_SYS_ADMIN */
++#define GENL_MCAST_CAP_SYS_ADMIN      BIT(1)
++
+ /**
+  * struct genl_multicast_group - generic netlink multicast group
+  * @name: name of the multicast group, names are per-family
+- * @flags: GENL_* flags (%GENL_ADMIN_PERM or %GENL_UNS_ADMIN_PERM)
+- * @cap_sys_admin: whether %CAP_SYS_ADMIN is required for binding
++ * @flags: GENL_MCAST_* flags
+  */
+ struct genl_multicast_group {
+       char                    name[GENL_NAMSIZ];
+       u8                      flags;
+-      u8                      cap_sys_admin:1;
+ };
+ struct genl_ops;
+--- a/net/core/drop_monitor.c
++++ b/net/core/drop_monitor.c
+@@ -184,7 +184,7 @@ out:
+ }
+ static const struct genl_multicast_group dropmon_mcgrps[] = {
+-      { .name = "events", .cap_sys_admin = 1 },
++      { .name = "events", .flags = GENL_MCAST_CAP_SYS_ADMIN, },
+ };
+ static void send_dm_alert(struct work_struct *work)
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -1207,7 +1207,7 @@ void mptcp_pm_nl_data_init(struct mptcp_
+ static const struct genl_multicast_group mptcp_pm_mcgrps[] = {
+       [MPTCP_PM_CMD_GRP_OFFSET]       = { .name = MPTCP_PM_CMD_GRP_NAME, },
+       [MPTCP_PM_EV_GRP_OFFSET]        = { .name = MPTCP_PM_EV_GRP_NAME,
+-                                          .flags = GENL_UNS_ADMIN_PERM,
++                                          .flags = GENL_MCAST_CAP_NET_ADMIN,
+                                         },
+ };
+--- a/net/netlink/genetlink.c
++++ b/net/netlink/genetlink.c
+@@ -1372,10 +1372,10 @@ static int genl_bind(struct net *net, in
+                       continue;
+               grp = &family->mcgrps[i];
+-              if ((grp->flags & GENL_UNS_ADMIN_PERM) &&
++              if ((grp->flags & GENL_MCAST_CAP_NET_ADMIN) &&
+                   !ns_capable(net->user_ns, CAP_NET_ADMIN))
+                       ret = -EPERM;
+-              if (grp->cap_sys_admin &&
++              if ((grp->flags & GENL_MCAST_CAP_SYS_ADMIN) &&
+                   !ns_capable(net->user_ns, CAP_SYS_ADMIN))
+                       ret = -EPERM;
+--- a/net/psample/psample.c
++++ b/net/psample/psample.c
+@@ -32,7 +32,7 @@ enum psample_nl_multicast_groups {
+ static const struct genl_multicast_group psample_nl_mcgrps[] = {
+       [PSAMPLE_NL_MCGRP_CONFIG] = { .name = PSAMPLE_NL_MCGRP_CONFIG_NAME },
+       [PSAMPLE_NL_MCGRP_SAMPLE] = { .name = PSAMPLE_NL_MCGRP_SAMPLE_NAME,
+-                                    .flags = GENL_UNS_ADMIN_PERM },
++                                    .flags = GENL_MCAST_CAP_NET_ADMIN, },
+ };
+ static struct genl_family psample_nl_family __ro_after_init;
diff --git a/queue-5.15/hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch b/queue-5.15/hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch
new file mode 100644 (file)
index 0000000..ee94ac8
--- /dev/null
@@ -0,0 +1,92 @@
+From stable+bounces-263428-greg=kroah.com@vger.kernel.org Mon Jun 15 23:47:06 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Jun 2026 14:16:57 -0400
+Subject: hv_netvsc: use kmap_local_page in netvsc_copy_to_send_buf
+To: stable@vger.kernel.org
+Cc: Anton Leontev <leontyevantony@gmail.com>, Paolo Abeni <pabeni@redhat.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260615181657.2320366-1-sashal@kernel.org>
+
+From: Anton Leontev <leontyevantony@gmail.com>
+
+[ Upstream commit 004e9ecfe6c5384f9e0b2f6f6389d42ec22789af ]
+
+netvsc_copy_to_send_buf() copies page buffer entries into the VMBus
+send buffer using phys_to_virt() on the entry PFN. Entries for the
+RNDIS header and the skb linear data come from kmalloc'd memory and
+are always in the kernel direct map, but entries for skb fragments
+reference page cache or user pages, which on 32-bit x86 with
+CONFIG_HIGHMEM=y can live above the LOWMEM boundary. For such a page
+phys_to_virt() returns an address outside the direct map and the
+subsequent memcpy() faults on the transmit softirq path, which is
+fatal.
+
+Map the pages with kmap_local_page() instead, handling two properties
+of the page buffer entries:
+
+ - pb[i].pfn is a Hyper-V PFN at HV_HYP_PAGE_SIZE (4K) granularity,
+   not a native PFN. Reconstruct the physical address first and derive
+   the native page from it, so the mapping stays correct where
+   PAGE_SIZE > HV_HYP_PAGE_SIZE (e.g. arm64 with 64K pages).
+
+ - Since commit 41a6328b2c55 ("hv_netvsc: Preserve contiguous PFN
+   grouping in the page buffer array"), an entry describes a full
+   physically contiguous fragment and pb[i].len can exceed PAGE_SIZE,
+   while kmap_local_page() maps a single page. Copy page by page,
+   splitting at native page boundaries.
+
+The copy path only handles packets smaller than the send section size
+(6144 bytes by default); larger packets take the cp_partial path where
+only the RNDIS header is copied. So entries here are bounded by the
+section size and a copy is split at most once on 4K-page systems. On
+!CONFIG_HIGHMEM configs kmap_local_page() folds to page_address() and
+no mapping work is added.
+
+Fixes: c25aaf814a63 ("hyperv: Enable sendbuf mechanism on the send path")
+Cc: stable@vger.kernel.org
+Signed-off-by: Anton Leontev <leontyevantony@gmail.com>
+Link: https://patch.msgid.link/20260604165938.32033-1-leontyevantony@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[ adapted `phys_to_page(paddr)` to `pfn_to_page(PHYS_PFN(paddr))` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/hyperv/netvsc.c |   19 +++++++++++++++----
+ 1 file changed, 15 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/hyperv/netvsc.c
++++ b/drivers/net/hyperv/netvsc.c
+@@ -12,6 +12,7 @@
+ #include <linux/sched.h>
+ #include <linux/wait.h>
+ #include <linux/mm.h>
++#include <linux/highmem.h>
+ #include <linux/delay.h>
+ #include <linux/io.h>
+ #include <linux/slab.h>
+@@ -956,12 +957,22 @@ static void netvsc_copy_to_send_buf(stru
+       }
+       for (i = 0; i < page_count; i++) {
+-              char *src = phys_to_virt(pb[i].pfn << HV_HYP_PAGE_SHIFT);
+-              u32 offset = pb[i].offset;
++              phys_addr_t paddr = (pb[i].pfn << HV_HYP_PAGE_SHIFT) +
++                                  pb[i].offset;
+               u32 len = pb[i].len;
+-              memcpy(dest, (src + offset), len);
+-              dest += len;
++              while (len) {
++                      struct page *page = pfn_to_page(PHYS_PFN(paddr));
++                      u32 off = offset_in_page(paddr);
++                      u32 chunk = min_t(u32, len, PAGE_SIZE - off);
++                      char *src = kmap_local_page(page);
++
++                      memcpy(dest, src + off, chunk);
++                      kunmap_local(src);
++                      dest += chunk;
++                      paddr += chunk;
++                      len -= chunk;
++              }
+       }
+       if (padding)
diff --git a/queue-5.15/ice-fix-vf-queue-configuration-with-low-mtu-values.patch b/queue-5.15/ice-fix-vf-queue-configuration-with-low-mtu-values.patch
new file mode 100644 (file)
index 0000000..9721a52
--- /dev/null
@@ -0,0 +1,62 @@
+From stable+bounces-256870-greg=kroah.com@vger.kernel.org Sat May 30 17:09:06 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 07:38:58 -0400
+Subject: ice: fix VF queue configuration with low MTU values
+To: stable@vger.kernel.org
+Cc: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>, Jacob Keller <jacob.e.keller@intel.com>, Michal Swiatkowski <michal.swiatkowski@linux.intel.com>, Paul Menzel <pmenzel@molgen.mpg.de>, Rafal Romanowski <rafal.romanowski@intel.com>, Tony Nguyen <anthony.l.nguyen@intel.com>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530113858.1937093-1-sashal@kernel.org>
+
+From: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
+
+[ Upstream commit 3ba4dd024d26372733d1c02e13e076c6016e3320 ]
+
+The ice driver's VF queue configuration validation rejects
+databuffer_size values below 1024 bytes, which prevents VFs from
+using MTU values below 871 bytes.
+
+The iavf driver calculates databuffer_size based on the MTU using:
+  databuffer_size = ALIGN(MTU + LIBETH_RX_LL_LEN, 128)
+
+where LIBETH_RX_LL_LEN = 26 (ETH_HLEN + 2*VLAN_HLEN + ETH_FCS_LEN).
+
+For MTU values below 871:
+  MTU 870: 870 + 26 = 896, aligned to 128 = 896 (< 1024, rejected)
+  MTU 871: 871 + 26 = 897, aligned to 128 = 1024 (>= 1024, accepted)
+
+The 1024-byte minimum seems unnecessarily restrictive, because the hardware
+supports databuffer_size as low as 128 bytes (the alignment boundary),
+which should allow MTU values down to the standard minimum of 68 bytes.
+
+I haven't found the reason why the limit was configured in the commit
+9c7dd7566d18 ("ice: add validation in OP_CONFIG_VSI_QUEUES VF message"), so
+with no more information and since it is working, change the minimum
+databuffer_size validation from 1024 to 128 bytes to allow standard low
+MTU values while still preventing invalid configurations.
+
+Fixes: 9c7dd7566d18 ("ice: add validation in OP_CONFIG_VSI_QUEUES VF message")
+cc: stable@vger.kernel.org
+Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
+Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
+Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Link: https://patch.msgid.link/20260515182419.1597859-3-anthony.l.nguyen@intel.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
++++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
+@@ -3585,7 +3585,7 @@ static int ice_vc_cfg_qs_msg(struct ice_
+                       if (qpi->rxq.databuffer_size != 0 &&
+                           (qpi->rxq.databuffer_size > ((16 * 1024) - 128) ||
+-                           qpi->rxq.databuffer_size < 1024)) {
++                           qpi->rxq.databuffer_size < 128)) {
+                               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+                               goto error_param;
+                       }
diff --git a/queue-5.15/iio-adc-fix-the-return-value-handle-for-platform_get_irq.patch b/queue-5.15/iio-adc-fix-the-return-value-handle-for-platform_get_irq.patch
new file mode 100644 (file)
index 0000000..c10676a
--- /dev/null
@@ -0,0 +1,81 @@
+From stable+bounces-260514-greg=kroah.com@vger.kernel.org Thu Jun  4 20:15:22 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu,  4 Jun 2026 10:30:29 -0400
+Subject: iio: adc: fix the return value handle for platform_get_irq()
+To: stable@vger.kernel.org
+Cc: Ruan Jinjie <ruanjinjie@huawei.com>, Jonathan Cameron <Jonathan.Cameron@huawei.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260604143031.3608772-1-sashal@kernel.org>
+
+From: Ruan Jinjie <ruanjinjie@huawei.com>
+
+[ Upstream commit c09ddcdd4dd32ee9768dc233ead4b3d726f26d38 ]
+
+There is no possible for platform_get_irq() to return 0
+and the return value of platform_get_irq() is more sensible
+to show the error reason.
+
+Signed-off-by: Ruan Jinjie <ruanjinjie@huawei.com>
+Link: https://lore.kernel.org/r/20230727131607.2897937-1-ruanjinjie@huawei.com
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Stable-dep-of: 0d42e2c0bd6c ("iio: adc: npcm: fix unbalanced clk_disable_unprepare()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iio/adc/bcm_iproc_adc.c |    4 ++--
+ drivers/iio/adc/lpc32xx_adc.c   |    4 ++--
+ drivers/iio/adc/npcm_adc.c      |    4 ++--
+ drivers/iio/adc/spear_adc.c     |    4 ++--
+ 4 files changed, 8 insertions(+), 8 deletions(-)
+
+--- a/drivers/iio/adc/bcm_iproc_adc.c
++++ b/drivers/iio/adc/bcm_iproc_adc.c
+@@ -540,8 +540,8 @@ static int iproc_adc_probe(struct platfo
+       }
+       adc_priv->irqno = platform_get_irq(pdev, 0);
+-      if (adc_priv->irqno <= 0)
+-              return -ENODEV;
++      if (adc_priv->irqno < 0)
++              return adc_priv->irqno;
+       ret = regmap_update_bits(adc_priv->regmap, IPROC_REGCTL2,
+                               IPROC_ADC_AUXIN_SCAN_ENA, 0);
+--- a/drivers/iio/adc/lpc32xx_adc.c
++++ b/drivers/iio/adc/lpc32xx_adc.c
+@@ -173,8 +173,8 @@ static int lpc32xx_adc_probe(struct plat
+       }
+       irq = platform_get_irq(pdev, 0);
+-      if (irq <= 0)
+-              return -ENXIO;
++      if (irq < 0)
++              return irq;
+       retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0,
+                                 LPC32XXAD_NAME, st);
+--- a/drivers/iio/adc/npcm_adc.c
++++ b/drivers/iio/adc/npcm_adc.c
+@@ -221,8 +221,8 @@ static int npcm_adc_probe(struct platfor
+       info->adc_sample_hz = clk_get_rate(info->adc_clk) / ((div + 1) * 2);
+       irq = platform_get_irq(pdev, 0);
+-      if (irq <= 0) {
+-              ret = -EINVAL;
++      if (irq < 0) {
++              ret = irq;
+               goto err_disable_clk;
+       }
+--- a/drivers/iio/adc/spear_adc.c
++++ b/drivers/iio/adc/spear_adc.c
+@@ -311,8 +311,8 @@ static int spear_adc_probe(struct platfo
+       }
+       irq = platform_get_irq(pdev, 0);
+-      if (irq <= 0) {
+-              ret = -EINVAL;
++      if (irq < 0) {
++              ret = irq;
+               goto errout2;
+       }
diff --git a/queue-5.15/iio-adc-npcm-convert-to-platform-remove-callback-returning-void.patch b/queue-5.15/iio-adc-npcm-convert-to-platform-remove-callback-returning-void.patch
new file mode 100644 (file)
index 0000000..f536ea1
--- /dev/null
@@ -0,0 +1,60 @@
+From stable+bounces-260515-greg=kroah.com@vger.kernel.org Thu Jun  4 20:15:24 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu,  4 Jun 2026 10:30:30 -0400
+Subject: iio: adc: npcm: Convert to platform remove callback returning void
+To: stable@vger.kernel.org
+Cc: "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>, "Jonathan Cameron" <Jonathan.Cameron@huawei.com>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260604143031.3608772-2-sashal@kernel.org>
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit 5253a5cc7709688b9a000f7928bfaa3366d0af98 ]
+
+The .remove() callback for a platform driver returns an int which makes
+many driver authors wrongly assume it's possible to do error handling by
+returning an error code. However the value returned is ignored (apart
+from emitting a warning) and this typically results in resource leaks.
+To improve here there is a quest to make the remove callback return
+void. In the first step of this quest all drivers are converted to
+.remove_new() which already returns void. Eventually after all drivers
+are converted, .remove_new() will be renamed to .remove().
+
+Trivially convert this driver from always returning zero in the remove
+callback to the void returning variant.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Link: https://lore.kernel.org/r/20230919174931.1417681-18-u.kleine-koenig@pengutronix.de
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Stable-dep-of: 0d42e2c0bd6c ("iio: adc: npcm: fix unbalanced clk_disable_unprepare()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iio/adc/npcm_adc.c |    6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/drivers/iio/adc/npcm_adc.c
++++ b/drivers/iio/adc/npcm_adc.c
+@@ -297,7 +297,7 @@ err_disable_clk:
+       return ret;
+ }
+-static int npcm_adc_remove(struct platform_device *pdev)
++static void npcm_adc_remove(struct platform_device *pdev)
+ {
+       struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+       struct npcm_adc *info = iio_priv(indio_dev);
+@@ -310,13 +310,11 @@ static int npcm_adc_remove(struct platfo
+       if (!IS_ERR(info->vref))
+               regulator_disable(info->vref);
+       clk_disable_unprepare(info->adc_clk);
+-
+-      return 0;
+ }
+ static struct platform_driver npcm_adc_driver = {
+       .probe          = npcm_adc_probe,
+-      .remove         = npcm_adc_remove,
++      .remove_new     = npcm_adc_remove,
+       .driver         = {
+               .name   = "npcm_adc",
+               .of_match_table = npcm_adc_match,
diff --git a/queue-5.15/iio-adc-npcm-fix-unbalanced-clk_disable_unprepare.patch b/queue-5.15/iio-adc-npcm-fix-unbalanced-clk_disable_unprepare.patch
new file mode 100644 (file)
index 0000000..08ec350
--- /dev/null
@@ -0,0 +1,112 @@
+From stable+bounces-260516-greg=kroah.com@vger.kernel.org Thu Jun  4 20:15:25 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu,  4 Jun 2026 10:30:31 -0400
+Subject: iio: adc: npcm: fix unbalanced clk_disable_unprepare()
+To: stable@vger.kernel.org
+Cc: David Carlier <devnexen@gmail.com>, Andy Shevchenko <andriy.shevchenko@intel.com>, Stable@vger.kernel.org, Jonathan Cameron <jic23@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260604143031.3608772-3-sashal@kernel.org>
+
+From: David Carlier <devnexen@gmail.com>
+
+[ Upstream commit 0d42e2c0bd6ceb89e44c6e065f9bdf9b1df3ef0c ]
+
+The driver acquired the ADC clock with devm_clk_get() and read its
+rate, but never called clk_prepare_enable(). The probe error path and
+npcm_adc_remove() both called clk_disable_unprepare() unconditionally,
+causing the clk framework's enable/prepare counts to underflow on
+probe failure or module unbind.
+
+The issue went unnoticed because NPCM BMC firmware leaves the ADC
+clock enabled at boot, so the driver happened to work in practice.
+
+Switch to devm_clk_get_enabled() so the clock is properly enabled
+during probe and automatically released by the device-managed
+cleanup, and drop the now-redundant clk_disable_unprepare() from
+both the probe error path and remove().
+
+While at it, drop the duplicate error message on devm_request_irq()
+failure since the IRQ core already logs it.
+
+Fixes: 9bf85fbc9d8f ("iio: adc: add NPCM ADC driver")
+Signed-off-by: David Carlier <devnexen@gmail.com>
+Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
+Cc: <Stable@vger.kernel.org>
+Signed-off-by: Jonathan Cameron <jic23@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iio/adc/npcm_adc.c |   25 ++++++++-----------------
+ 1 file changed, 8 insertions(+), 17 deletions(-)
+
+--- a/drivers/iio/adc/npcm_adc.c
++++ b/drivers/iio/adc/npcm_adc.c
+@@ -208,7 +208,7 @@ static int npcm_adc_probe(struct platfor
+       if (IS_ERR(info->reset))
+               return PTR_ERR(info->reset);
+-      info->adc_clk = devm_clk_get(&pdev->dev, NULL);
++      info->adc_clk = devm_clk_get_enabled(&pdev->dev, NULL);
+       if (IS_ERR(info->adc_clk)) {
+               dev_warn(&pdev->dev, "ADC clock failed: can't read clk\n");
+               return PTR_ERR(info->adc_clk);
+@@ -221,17 +221,13 @@ static int npcm_adc_probe(struct platfor
+       info->adc_sample_hz = clk_get_rate(info->adc_clk) / ((div + 1) * 2);
+       irq = platform_get_irq(pdev, 0);
+-      if (irq < 0) {
+-              ret = irq;
+-              goto err_disable_clk;
+-      }
++      if (irq < 0)
++              return irq;
+       ret = devm_request_irq(&pdev->dev, irq, npcm_adc_isr, 0,
+                              "NPCM_ADC", indio_dev);
+-      if (ret < 0) {
+-              dev_err(dev, "failed requesting interrupt\n");
+-              goto err_disable_clk;
+-      }
++      if (ret < 0)
++              return ret;
+       reg_con = ioread32(info->regs + NPCM_ADCCON);
+       info->vref = devm_regulator_get_optional(&pdev->dev, "vref");
+@@ -239,7 +235,7 @@ static int npcm_adc_probe(struct platfor
+               ret = regulator_enable(info->vref);
+               if (ret) {
+                       dev_err(&pdev->dev, "Can't enable ADC reference voltage\n");
+-                      goto err_disable_clk;
++                      return ret;
+               }
+               iowrite32(reg_con & ~NPCM_ADCCON_REFSEL,
+@@ -249,10 +245,8 @@ static int npcm_adc_probe(struct platfor
+                * Any error which is not ENODEV indicates the regulator
+                * has been specified and so is a failure case.
+                */
+-              if (PTR_ERR(info->vref) != -ENODEV) {
+-                      ret = PTR_ERR(info->vref);
+-                      goto err_disable_clk;
+-              }
++              if (PTR_ERR(info->vref) != -ENODEV)
++                      return PTR_ERR(info->vref);
+               /* Use internal reference */
+               iowrite32(reg_con | NPCM_ADCCON_REFSEL,
+@@ -291,8 +285,6 @@ err_iio_register:
+       iowrite32(reg_con & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON);
+       if (!IS_ERR(info->vref))
+               regulator_disable(info->vref);
+-err_disable_clk:
+-      clk_disable_unprepare(info->adc_clk);
+       return ret;
+ }
+@@ -309,7 +301,6 @@ static void npcm_adc_remove(struct platf
+       iowrite32(regtemp & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON);
+       if (!IS_ERR(info->vref))
+               regulator_disable(info->vref);
+-      clk_disable_unprepare(info->adc_clk);
+ }
+ static struct platform_driver npcm_adc_driver = {
diff --git a/queue-5.15/iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch b/queue-5.15/iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch
new file mode 100644 (file)
index 0000000..bbbdef6
--- /dev/null
@@ -0,0 +1,38 @@
+From stable+bounces-260571-greg=kroah.com@vger.kernel.org Fri Jun  5 01:13:30 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu,  4 Jun 2026 15:40:17 -0400
+Subject: iio: chemical: scd30: fix division by zero in write_raw
+To: stable@vger.kernel.org
+Cc: Antoniu Miclaus <antoniu.miclaus@analog.com>, Stable@vger.kernel.org, Jonathan Cameron <jic23@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260604194017.889785-2-sashal@kernel.org>
+
+From: Antoniu Miclaus <antoniu.miclaus@analog.com>
+
+[ Upstream commit 5aba4f94b225617a55fed442a70329b2ee19c0a5 ]
+
+Add a zero check for val2 before using it as a divisor when setting the
+sampling frequency. A user writing a zero fractional part to the
+sampling_frequency sysfs attribute triggers a division by zero in the
+kernel.
+
+Fixes: 64b3d8b1b0f5 ("iio: chemical: scd30: add core driver")
+Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
+Cc: <Stable@vger.kernel.org>
+Signed-off-by: Jonathan Cameron <jic23@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iio/chemical/scd30_core.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/iio/chemical/scd30_core.c
++++ b/drivers/iio/chemical/scd30_core.c
+@@ -257,7 +257,7 @@ static int scd30_write_raw(struct iio_de
+       guard(mutex)(&state->lock);
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+-              if (val)
++              if (val || !val2)
+                       return -EINVAL;
+               val = 1000000000 / val2;
diff --git a/queue-5.15/iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch b/queue-5.15/iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch
new file mode 100644 (file)
index 0000000..1e37f44
--- /dev/null
@@ -0,0 +1,178 @@
+From stable+bounces-260570-greg=kroah.com@vger.kernel.org Fri Jun  5 01:13:23 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu,  4 Jun 2026 15:40:16 -0400
+Subject: iio: chemical: scd30: Use guard(mutex) to allow early returns
+To: stable@vger.kernel.org
+Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>, David Lechner <dlechner@baylibre.com>, Tomasz Duszynski <tomasz.duszynski@octakon.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260604194017.889785-1-sashal@kernel.org>
+
+From: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+
+[ Upstream commit 5feb5532870fbced5d6f450b8061a33f461b88ca ]
+
+Auto cleanup based release of the lock allows for simpler code flow in a
+few functions with large multiplexing style switch statements and no
+common operations following the switch.
+
+Suggested-by: David Lechner <dlechner@baylibre.com>
+Cc: Tomasz Duszynski <tomasz.duszynski@octakon.com>
+Reviewed-by: David Lechner <dlechner@baylibre.com>
+Link: https://patch.msgid.link/20250209180624.701140-3-jic23@kernel.org
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Stable-dep-of: 5aba4f94b225 ("iio: chemical: scd30: fix division by zero in write_raw")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iio/chemical/scd30_core.c |   63 ++++++++++++++++----------------------
+ 1 file changed, 28 insertions(+), 35 deletions(-)
+
+--- a/drivers/iio/chemical/scd30_core.c
++++ b/drivers/iio/chemical/scd30_core.c
+@@ -5,6 +5,7 @@
+  * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com>
+  */
+ #include <linux/bits.h>
++#include <linux/cleanup.h>
+ #include <linux/completion.h>
+ #include <linux/delay.h>
+ #include <linux/device.h>
+@@ -198,112 +199,104 @@ static int scd30_read_raw(struct iio_dev
+                         int *val, int *val2, long mask)
+ {
+       struct scd30_state *state = iio_priv(indio_dev);
+-      int ret = -EINVAL;
++      int ret;
+       u16 tmp;
+-      mutex_lock(&state->lock);
++      guard(mutex)(&state->lock);
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+       case IIO_CHAN_INFO_PROCESSED:
+               if (chan->output) {
+                       *val = state->pressure_comp;
+-                      ret = IIO_VAL_INT;
+-                      break;
++                      return IIO_VAL_INT;
+               }
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+-                      break;
++                      return ret;
+               ret = scd30_read(state);
+               if (ret) {
+                       iio_device_release_direct_mode(indio_dev);
+-                      break;
++                      return ret;
+               }
+               *val = state->meas[chan->address];
+               iio_device_release_direct_mode(indio_dev);
+-              ret = IIO_VAL_INT;
+-              break;
++              return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               *val = 0;
+               *val2 = 1;
+-              ret = IIO_VAL_INT_PLUS_MICRO;
+-              break;
++              return IIO_VAL_INT_PLUS_MICRO;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               ret = scd30_command_read(state, CMD_MEAS_INTERVAL, &tmp);
+               if (ret)
+-                      break;
++                      return ret;
+               *val = 0;
+               *val2 = 1000000000 / tmp;
+-              ret = IIO_VAL_INT_PLUS_NANO;
+-              break;
++              return IIO_VAL_INT_PLUS_NANO;
+       case IIO_CHAN_INFO_CALIBBIAS:
+               ret = scd30_command_read(state, CMD_TEMP_OFFSET, &tmp);
+               if (ret)
+-                      break;
++                      return ret;
+               *val = tmp;
+-              ret = IIO_VAL_INT;
+-              break;
++              return IIO_VAL_INT;
++      default:
++              return -EINVAL;
+       }
+-      mutex_unlock(&state->lock);
+-
+-      return ret;
+ }
+ static int scd30_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
+                          int val, int val2, long mask)
+ {
+       struct scd30_state *state = iio_priv(indio_dev);
+-      int ret = -EINVAL;
++      int ret;
+-      mutex_lock(&state->lock);
++      guard(mutex)(&state->lock);
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               if (val)
+-                      break;
++                      return -EINVAL;
+               val = 1000000000 / val2;
+               if (val < SCD30_MEAS_INTERVAL_MIN_S || val > SCD30_MEAS_INTERVAL_MAX_S)
+-                      break;
++                      return -EINVAL;
+               ret = scd30_command_write(state, CMD_MEAS_INTERVAL, val);
+               if (ret)
+-                      break;
++                      return ret;
+               state->meas_interval = val;
+-              break;
++              return 0;
+       case IIO_CHAN_INFO_RAW:
+               switch (chan->type) {
+               case IIO_PRESSURE:
+                       if (val < SCD30_PRESSURE_COMP_MIN_MBAR ||
+                           val > SCD30_PRESSURE_COMP_MAX_MBAR)
+-                              break;
++                              return -EINVAL;
+                       ret = scd30_command_write(state, CMD_START_MEAS, val);
+                       if (ret)
+-                              break;
++                              return ret;
+                       state->pressure_comp = val;
+-                      break;
++                      return 0;
+               default:
+-                      break;
++                      return -EINVAL;
+               }
+-              break;
+       case IIO_CHAN_INFO_CALIBBIAS:
+               if (val < 0 || val > SCD30_TEMP_OFFSET_MAX)
+-                      break;
++                      return -EINVAL;
+               /*
+                * Manufacturer does not explicitly specify min/max sensible
+                * values hence check is omitted for simplicity.
+                */
+-              ret = scd30_command_write(state, CMD_TEMP_OFFSET / 10, val);
++              return scd30_command_write(state, CMD_TEMP_OFFSET / 10, val);
++      default:
++              return -EINVAL;
+       }
+-      mutex_unlock(&state->lock);
+-
+-      return ret;
+ }
+ static int scd30_write_raw_get_fmt(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
diff --git a/queue-5.15/iio-dac-ad5686-acquire-lock-when-doing-powerdown-control.patch b/queue-5.15/iio-dac-ad5686-acquire-lock-when-doing-powerdown-control.patch
new file mode 100644 (file)
index 0000000..820e23e
--- /dev/null
@@ -0,0 +1,67 @@
+From stable+bounces-260524-greg=kroah.com@vger.kernel.org Thu Jun  4 20:43:03 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu,  4 Jun 2026 11:02:04 -0400
+Subject: iio: dac: ad5686: acquire lock when doing powerdown control
+To: stable@vger.kernel.org
+Cc: Rodrigo Alencar <rodrigo.alencar@analog.com>, Stable@vger.kernel.org, Jonathan Cameron <jic23@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260604150204.3692750-1-sashal@kernel.org>
+
+From: Rodrigo Alencar <rodrigo.alencar@analog.com>
+
+[ Upstream commit 5237c3175cae5ab05f18878cec3301a04403859e ]
+
+Protect access of pwr_down_mode and pwr_down_mask fields with existing
+mutex lock. Each channel exposes their own attributes for controlling
+powerdown modes and powerdown state. This fixes potential race conditions
+as those the write functions perform non-atomic read-modify-write
+operations to those pwr_down_* fields. This issue exists since the ad5686
+driver was first introduced.
+
+Fixes: c2f37c8dcadc ("iio: dac: New driver for AD5686R, AD5685R, AD5684R Digital to analog converters")
+Signed-off-by: Rodrigo Alencar <rodrigo.alencar@analog.com>
+Cc: <Stable@vger.kernel.org>
+Signed-off-by: Jonathan Cameron <jic23@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iio/dac/ad5686.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/iio/dac/ad5686.c
++++ b/drivers/iio/dac/ad5686.c
+@@ -30,6 +30,8 @@ static int ad5686_get_powerdown_mode(str
+ {
+       struct ad5686_state *st = iio_priv(indio_dev);
++      guard(mutex)(&st->lock);
++
+       return ((st->pwr_down_mode >> (chan->channel * 2)) & 0x3) - 1;
+ }
+@@ -39,6 +41,8 @@ static int ad5686_set_powerdown_mode(str
+ {
+       struct ad5686_state *st = iio_priv(indio_dev);
++      guard(mutex)(&st->lock);
++
+       st->pwr_down_mode &= ~(0x3 << (chan->channel * 2));
+       st->pwr_down_mode |= ((mode + 1) << (chan->channel * 2));
+@@ -57,6 +61,8 @@ static ssize_t ad5686_read_dac_powerdown
+ {
+       struct ad5686_state *st = iio_priv(indio_dev);
++      guard(mutex)(&st->lock);
++
+       return sysfs_emit(buf, "%d\n", !!(st->pwr_down_mask &
+                                      (0x3 << (chan->channel * 2))));
+ }
+@@ -77,6 +83,8 @@ static ssize_t ad5686_write_dac_powerdow
+       if (ret)
+               return ret;
++      guard(mutex)(&st->lock);
++
+       if (readin)
+               st->pwr_down_mask |= (0x3 << (chan->channel * 2));
+       else
diff --git a/queue-5.15/iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch b/queue-5.15/iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch
new file mode 100644 (file)
index 0000000..09f82a4
--- /dev/null
@@ -0,0 +1,65 @@
+From stable+bounces-260603-greg=kroah.com@vger.kernel.org Fri Jun  5 07:15:42 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu,  4 Jun 2026 21:31:12 -0400
+Subject: iio: dac: ad5686: fix ref bit initialization for single-channel parts
+To: stable@vger.kernel.org
+Cc: Rodrigo Alencar <rodrigo.alencar@analog.com>, Andy Shevchenko <andriy.shevchenko@intel.com>, Stable@vger.kernel.org, Jonathan Cameron <jic23@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260605013113.2963901-1-sashal@kernel.org>
+
+From: Rodrigo Alencar <rodrigo.alencar@analog.com>
+
+[ Upstream commit ecae2ae606d493cf11457946436335bd0e726663 ]
+
+The reference bit position was ignored when writing the register at the
+probe() function (!!val was used). When such bit is 1, internal voltage
+reference is disabled so that an external one can be used. For
+multi-channel devices, bit 0 of the Internal Reference Setup command
+behaves the same way, so AD5686_REF_BIT_MSK is created. The issue exists
+since support for single-channel devices were first introduced.
+
+Fixes: be1b24d24541 ("iio:dac:ad5686: Add AD5691R/AD5692R/AD5693/AD5693R support")
+Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
+Signed-off-by: Rodrigo Alencar <rodrigo.alencar@analog.com>
+Cc: <Stable@vger.kernel.org>
+Signed-off-by: Jonathan Cameron <jic23@kernel.org>
+[ adapted `has_external_vref` to the in-tree equivalent `voltage_uv` variable in the `val =` computation ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iio/dac/ad5686.c |    6 +++---
+ drivers/iio/dac/ad5686.h |    1 +
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+--- a/drivers/iio/dac/ad5686.c
++++ b/drivers/iio/dac/ad5686.c
+@@ -521,7 +521,7 @@ int ad5686_probe(struct device *dev,
+               break;
+       case AD5686_REGMAP:
+               cmd = AD5686_CMD_INTERNAL_REFER_SETUP;
+-              ref_bit_msk = 0;
++              ref_bit_msk = AD5686_REF_BIT_MSK;
+               break;
+       case AD5693_REGMAP:
+               cmd = AD5686_CMD_CONTROL_REG;
+@@ -533,9 +533,9 @@ int ad5686_probe(struct device *dev,
+               goto error_disable_reg;
+       }
+-      val = (voltage_uv | ref_bit_msk);
++      val = voltage_uv ? ref_bit_msk : 0;
+-      ret = st->write(st, cmd, 0, !!val);
++      ret = st->write(st, cmd, 0, val);
+       if (ret)
+               goto error_disable_reg;
+--- a/drivers/iio/dac/ad5686.h
++++ b/drivers/iio/dac/ad5686.h
+@@ -44,6 +44,7 @@
+ #define AD5310_REF_BIT_MSK                    BIT(8)
+ #define AD5683_REF_BIT_MSK                    BIT(12)
++#define AD5686_REF_BIT_MSK                    BIT(0)
+ #define AD5693_REF_BIT_MSK                    BIT(12)
+ /**
diff --git a/queue-5.15/iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch b/queue-5.15/iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch
new file mode 100644 (file)
index 0000000..3942db9
--- /dev/null
@@ -0,0 +1,39 @@
+From stable+bounces-260564-greg=kroah.com@vger.kernel.org Fri Jun  5 00:48:23 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu,  4 Jun 2026 15:17:52 -0400
+Subject: iio: gyro: adis16260: fix division by zero in write_raw
+To: stable@vger.kernel.org
+Cc: "Antoniu Miclaus" <antoniu.miclaus@analog.com>, "Nuno Sá" <nuno.sa@analog.com>, Stable@vger.kernel.org, "Jonathan Cameron" <Jonathan.Cameron@huawei.com>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260604191752.743368-1-sashal@kernel.org>
+
+From: Antoniu Miclaus <antoniu.miclaus@analog.com>
+
+[ Upstream commit 761e8b489e6cf166c574034b70637f8a7eadd0ee ]
+
+Add a validation check for the sampling frequency value before using it
+as a divisor. A user writing zero to the sampling_frequency sysfs
+attribute triggers a division by zero in the kernel.
+
+Fixes: 089a41985c6c ("staging: iio: adis16260 digital gyro driver")
+Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
+Reviewed-by: Nuno Sá <nuno.sa@analog.com>
+Cc: <Stable@vger.kernel.org>
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iio/gyro/adis16260.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/iio/gyro/adis16260.c
++++ b/drivers/iio/gyro/adis16260.c
+@@ -288,6 +288,9 @@ static int adis16260_write_raw(struct ii
+               addr = adis16260_addresses[chan->scan_index][1];
+               return adis_write_reg_16(adis, addr, val);
+       case IIO_CHAN_INFO_SAMP_FREQ:
++              if (val <= 0)
++                      return -EINVAL;
++
+               adis_dev_lock(adis);
+               if (spi_get_device_id(adis->spi)->driver_data)
+                       t = 256 / val;
diff --git a/queue-5.15/ipv6-addrconf-annotate-data-races-around-devconf-fields-ii.patch b/queue-5.15/ipv6-addrconf-annotate-data-races-around-devconf-fields-ii.patch
new file mode 100644 (file)
index 0000000..19d5078
--- /dev/null
@@ -0,0 +1,397 @@
+From stable+bounces-256872-greg=kroah.com@vger.kernel.org Sat May 30 17:09:36 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 07:39:26 -0400
+Subject: ipv6/addrconf: annotate data-races around devconf fields (II)
+To: stable@vger.kernel.org
+Cc: Eric Dumazet <edumazet@google.com>, Jiri Pirko <jiri@nvidia.com>, "David S. Miller" <davem@davemloft.net>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530113927.1939561-1-sashal@kernel.org>
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 2f0ff05a44302c91af54a5f9efe1b65b7681540e ]
+
+Final (?) round of this series.
+
+Annotate lockless reads on following devconf fields,
+because they be changed concurrently from /proc/net/ipv6/conf.
+
+- accept_dad
+- optimistic_dad
+- use_optimistic
+- use_oif_addrs_only
+- ra_honor_pio_life
+- keep_addr_on_down
+- ndisc_notify
+- ndisc_evict_nocarrier
+- suppress_frag_ndisc
+- addr_gen_mode
+- seg6_enabled
+- ioam6_enabled
+- ioam6_id
+- ioam6_id_wide
+- drop_unicast_in_l2_multicast
+- mldv[12]_unsolicited_report_interval
+- force_mld_version
+- force_tllao
+- accept_untracked_na
+- drop_unsolicited_na
+- accept_source_route
+
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Jiri Pirko <jiri@nvidia.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: d4ea0dfd7501 ("ipv6: ioam: add NULL check for idev in ipv6_hop_ioam()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv6/addrconf.c  |   47 +++++++++++++++++++++++++----------------------
+ net/ipv6/exthdrs.c   |   16 +++++++++-------
+ net/ipv6/ioam6.c     |    8 ++++----
+ net/ipv6/ip6_input.c |    2 +-
+ net/ipv6/mcast.c     |   14 +++++++-------
+ net/ipv6/ndisc.c     |   12 ++++++------
+ net/ipv6/seg6_hmac.c |    8 +++++---
+ 7 files changed, 57 insertions(+), 50 deletions(-)
+
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -1502,15 +1502,17 @@ static inline int ipv6_saddr_preferred(i
+       return 0;
+ }
+-static bool ipv6_use_optimistic_addr(struct net *net,
+-                                   struct inet6_dev *idev)
++static bool ipv6_use_optimistic_addr(const struct net *net,
++                                   const struct inet6_dev *idev)
+ {
+ #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+       if (!idev)
+               return false;
+-      if (!net->ipv6.devconf_all->optimistic_dad && !idev->cnf.optimistic_dad)
++      if (!READ_ONCE(net->ipv6.devconf_all->optimistic_dad) &&
++          !READ_ONCE(idev->cnf.optimistic_dad))
+               return false;
+-      if (!net->ipv6.devconf_all->use_optimistic && !idev->cnf.use_optimistic)
++      if (!READ_ONCE(net->ipv6.devconf_all->use_optimistic) &&
++          !READ_ONCE(idev->cnf.use_optimistic))
+               return false;
+       return true;
+@@ -1519,13 +1521,14 @@ static bool ipv6_use_optimistic_addr(str
+ #endif
+ }
+-static bool ipv6_allow_optimistic_dad(struct net *net,
+-                                    struct inet6_dev *idev)
++static bool ipv6_allow_optimistic_dad(const struct net *net,
++                                    const struct inet6_dev *idev)
+ {
+ #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+       if (!idev)
+               return false;
+-      if (!net->ipv6.devconf_all->optimistic_dad && !idev->cnf.optimistic_dad)
++      if (!READ_ONCE(net->ipv6.devconf_all->optimistic_dad) &&
++          !READ_ONCE(idev->cnf.optimistic_dad))
+               return false;
+       return true;
+@@ -1807,7 +1810,7 @@ int ipv6_dev_get_saddr(struct net *net,
+               idev = __in6_dev_get(dst_dev);
+               if ((dst_type & IPV6_ADDR_MULTICAST) ||
+                   dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL ||
+-                  (idev && idev->cnf.use_oif_addrs_only)) {
++                  (idev && READ_ONCE(idev->cnf.use_oif_addrs_only))) {
+                       use_oif_addr = true;
+               }
+       }
+@@ -2631,8 +2634,8 @@ int addrconf_prefix_rcv_add_addr(struct
+               };
+ #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+-              if ((net->ipv6.devconf_all->optimistic_dad ||
+-                   in6_dev->cnf.optimistic_dad) &&
++              if ((READ_ONCE(net->ipv6.devconf_all->optimistic_dad) ||
++                   READ_ONCE(in6_dev->cnf.optimistic_dad)) &&
+                   !net->ipv6.devconf_all->forwarding && sllao)
+                       cfg.ifa_flags |= IFA_F_OPTIMISTIC;
+ #endif
+@@ -3229,8 +3232,8 @@ void addrconf_add_linklocal(struct inet6
+       struct inet6_ifaddr *ifp;
+ #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+-      if ((dev_net(idev->dev)->ipv6.devconf_all->optimistic_dad ||
+-           idev->cnf.optimistic_dad) &&
++      if ((READ_ONCE(dev_net(idev->dev)->ipv6.devconf_all->optimistic_dad) ||
++           READ_ONCE(idev->cnf.optimistic_dad)) &&
+           !dev_net(idev->dev)->ipv6.devconf_all->forwarding)
+               cfg.ifa_flags |= IFA_F_OPTIMISTIC;
+ #endif
+@@ -3798,10 +3801,10 @@ static int addrconf_ifdown(struct net_de
+        */
+       if (!unregister && !idev->cnf.disable_ipv6) {
+               /* aggregate the system setting and interface setting */
+-              int _keep_addr = net->ipv6.devconf_all->keep_addr_on_down;
++              int _keep_addr = READ_ONCE(net->ipv6.devconf_all->keep_addr_on_down);
+               if (!_keep_addr)
+-                      _keep_addr = idev->cnf.keep_addr_on_down;
++                      _keep_addr = READ_ONCE(idev->cnf.keep_addr_on_down);
+               keep_addr = (_keep_addr > 0);
+       }
+@@ -4024,8 +4027,8 @@ static void addrconf_dad_begin(struct in
+       net = dev_net(dev);
+       if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
+-          (net->ipv6.devconf_all->accept_dad < 1 &&
+-           idev->cnf.accept_dad < 1) ||
++          (READ_ONCE(net->ipv6.devconf_all->accept_dad) < 1 &&
++           READ_ONCE(idev->cnf.accept_dad) < 1) ||
+           !(ifp->flags&IFA_F_TENTATIVE) ||
+           ifp->flags & IFA_F_NODAD) {
+               bool send_na = false;
+@@ -4117,8 +4120,8 @@ static void addrconf_dad_work(struct wor
+               action = DAD_ABORT;
+               ifp->state = INET6_IFADDR_STATE_POSTDAD;
+-              if ((dev_net(idev->dev)->ipv6.devconf_all->accept_dad > 1 ||
+-                   idev->cnf.accept_dad > 1) &&
++              if ((READ_ONCE(dev_net(idev->dev)->ipv6.devconf_all->accept_dad) > 1 ||
++                   READ_ONCE(idev->cnf.accept_dad) > 1) &&
+                   !idev->cnf.disable_ipv6 &&
+                   !(ifp->flags & IFA_F_STABLE_PRIVACY)) {
+                       struct in6_addr addr;
+@@ -4256,8 +4259,8 @@ static void addrconf_dad_completed(struc
+       /* send unsolicited NA if enabled */
+       if (send_na &&
+-          (ifp->idev->cnf.ndisc_notify ||
+-           dev_net(dev)->ipv6.devconf_all->ndisc_notify)) {
++          (READ_ONCE(ifp->idev->cnf.ndisc_notify) ||
++           READ_ONCE(dev_net(dev)->ipv6.devconf_all->ndisc_notify))) {
+               ndisc_send_na(dev, &in6addr_linklocal_allnodes, &ifp->addr,
+                             /*router=*/ !!ifp->idev->cnf.forwarding,
+                             /*solicited=*/ false, /*override=*/ true,
+@@ -6431,7 +6434,7 @@ static int addrconf_sysctl_addr_gen_mode
+               } else if (&net->ipv6.devconf_all->addr_gen_mode == ctl->data) {
+                       struct net_device *dev;
+-                      net->ipv6.devconf_dflt->addr_gen_mode = new_val;
++                      WRITE_ONCE(net->ipv6.devconf_dflt->addr_gen_mode, new_val);
+                       for_each_netdev(net, dev) {
+                               idev = __in6_dev_get(dev);
+                               if (idev &&
+@@ -6442,7 +6445,7 @@ static int addrconf_sysctl_addr_gen_mode
+                       }
+               }
+-              *((u32 *)ctl->data) = new_val;
++              WRITE_ONCE(*((u32 *)ctl->data), new_val);
+       }
+ out:
+--- a/net/ipv6/exthdrs.c
++++ b/net/ipv6/exthdrs.c
+@@ -382,9 +382,8 @@ static int ipv6_srh_rcv(struct sk_buff *
+               return -1;
+       }
+-      accept_seg6 = net->ipv6.devconf_all->seg6_enabled;
+-      if (accept_seg6 > idev->cnf.seg6_enabled)
+-              accept_seg6 = idev->cnf.seg6_enabled;
++      accept_seg6 = min(READ_ONCE(net->ipv6.devconf_all->seg6_enabled),
++                        READ_ONCE(idev->cnf.seg6_enabled));
+       if (!accept_seg6) {
+               kfree_skb(skb);
+@@ -689,11 +688,14 @@ static int ipv6_rthdr_rcv(struct sk_buff
+       struct ipv6_rt_hdr *hdr;
+       struct rt0_hdr *rthdr;
+       struct net *net = dev_net(skb->dev);
+-      int accept_source_route = net->ipv6.devconf_all->accept_source_route;
++      int accept_source_route;
+       idev = __in6_dev_get(skb->dev);
+-      if (idev && accept_source_route > idev->cnf.accept_source_route)
+-              accept_source_route = idev->cnf.accept_source_route;
++      accept_source_route = READ_ONCE(net->ipv6.devconf_all->accept_source_route);
++
++      if (idev)
++              accept_source_route = min(accept_source_route,
++                                        READ_ONCE(idev->cnf.accept_source_route));
+       if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
+           !pskb_may_pull(skb, (skb_transport_offset(skb) +
+@@ -957,7 +959,7 @@ static bool ipv6_hop_ioam(struct sk_buff
+               goto drop;
+       /* Ignore if IOAM is not enabled on ingress */
+-      if (!__in6_dev_get(skb->dev)->cnf.ioam6_enabled)
++      if (!READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_enabled))
+               goto ignore;
+       /* Truncated Option header */
+--- a/net/ipv6/ioam6.c
++++ b/net/ipv6/ioam6.c
+@@ -673,7 +673,7 @@ static void __ioam6_fill_trace_data(stru
+               if (!skb->dev)
+                       raw16 = IOAM6_U16_UNAVAILABLE;
+               else
+-                      raw16 = (__force u16)__in6_dev_get(skb->dev)->cnf.ioam6_id;
++                      raw16 = (__force u16)READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_id);
+               *(__be16 *)data = cpu_to_be16(raw16);
+               data += sizeof(__be16);
+@@ -681,7 +681,7 @@ static void __ioam6_fill_trace_data(stru
+               if (skb_dst(skb)->dev->flags & IFF_LOOPBACK)
+                       raw16 = IOAM6_U16_UNAVAILABLE;
+               else
+-                      raw16 = (__force u16)__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id;
++                      raw16 = (__force u16)READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id);
+               *(__be16 *)data = cpu_to_be16(raw16);
+               data += sizeof(__be16);
+@@ -758,7 +758,7 @@ static void __ioam6_fill_trace_data(stru
+               if (!skb->dev)
+                       raw32 = IOAM6_U32_UNAVAILABLE;
+               else
+-                      raw32 = __in6_dev_get(skb->dev)->cnf.ioam6_id_wide;
++                      raw32 = READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_id_wide);
+               *(__be32 *)data = cpu_to_be32(raw32);
+               data += sizeof(__be32);
+@@ -766,7 +766,7 @@ static void __ioam6_fill_trace_data(stru
+               if (skb_dst(skb)->dev->flags & IFF_LOOPBACK)
+                       raw32 = IOAM6_U32_UNAVAILABLE;
+               else
+-                      raw32 = __in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id_wide;
++                      raw32 = READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id_wide);
+               *(__be32 *)data = cpu_to_be32(raw32);
+               data += sizeof(__be32);
+--- a/net/ipv6/ip6_input.c
++++ b/net/ipv6/ip6_input.c
+@@ -228,7 +228,7 @@ static struct sk_buff *ip6_rcv_core(stru
+       if (!ipv6_addr_is_multicast(&hdr->daddr) &&
+           (skb->pkt_type == PACKET_BROADCAST ||
+            skb->pkt_type == PACKET_MULTICAST) &&
+-          idev->cnf.drop_unicast_in_l2_multicast)
++          READ_ONCE(idev->cnf.drop_unicast_in_l2_multicast))
+               goto err;
+       /* RFC4291 2.7
+--- a/net/ipv6/mcast.c
++++ b/net/ipv6/mcast.c
+@@ -159,9 +159,9 @@ static int unsolicited_report_interval(s
+       int iv;
+       if (mld_in_v1_mode(idev))
+-              iv = idev->cnf.mldv1_unsolicited_report_interval;
++              iv = READ_ONCE(idev->cnf.mldv1_unsolicited_report_interval);
+       else
+-              iv = idev->cnf.mldv2_unsolicited_report_interval;
++              iv = READ_ONCE(idev->cnf.mldv2_unsolicited_report_interval);
+       return iv > 0 ? iv : 1;
+ }
+@@ -1201,15 +1201,15 @@ static bool mld_marksources(struct ifmca
+ static int mld_force_mld_version(const struct inet6_dev *idev)
+ {
++      const struct net *net = dev_net(idev->dev);
++      int all_force;
++
++      all_force = READ_ONCE(net->ipv6.devconf_all->force_mld_version);
+       /* Normally, both are 0 here. If enforcement to a particular is
+        * being used, individual device enforcement will have a lower
+        * precedence over 'all' device (.../conf/all/force_mld_version).
+        */
+-
+-      if (dev_net(idev->dev)->ipv6.devconf_all->force_mld_version != 0)
+-              return dev_net(idev->dev)->ipv6.devconf_all->force_mld_version;
+-      else
+-              return idev->cnf.force_mld_version;
++      return all_force ?: READ_ONCE(idev->cnf.force_mld_version);
+ }
+ static bool mld_in_v2_mode_only(const struct inet6_dev *idev)
+--- a/net/ipv6/ndisc.c
++++ b/net/ipv6/ndisc.c
+@@ -450,7 +450,7 @@ static void ip6_nd_hdr(struct sk_buff *s
+       rcu_read_lock();
+       idev = __in6_dev_get(skb->dev);
+-      tclass = idev ? idev->cnf.ndisc_tclass : 0;
++      tclass = idev ? READ_ONCE(idev->cnf.ndisc_tclass) : 0;
+       rcu_read_unlock();
+       skb_push(skb, sizeof(*hdr));
+@@ -538,7 +538,7 @@ void ndisc_send_na(struct net_device *de
+               src_addr = solicited_addr;
+               if (ifp->flags & IFA_F_OPTIMISTIC)
+                       override = false;
+-              inc_opt |= ifp->idev->cnf.force_tllao;
++              inc_opt |= READ_ONCE(ifp->idev->cnf.force_tllao);
+               in6_ifa_put(ifp);
+       } else {
+               if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
+@@ -991,7 +991,7 @@ static void ndisc_recv_na(struct sk_buff
+        * and thus should not be accepted.
+        */
+       if (!msg->icmph.icmp6_solicited && idev &&
+-          idev->cnf.drop_unsolicited_na)
++          READ_ONCE(idev->cnf.drop_unsolicited_na))
+               return;
+       if (!ndisc_parse_options(dev, msg->opt, ndoptlen, &ndopts)) {
+@@ -1749,7 +1749,7 @@ static bool ndisc_suppress_frag_ndisc(st
+       if (!idev)
+               return true;
+       if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED &&
+-          idev->cnf.suppress_frag_ndisc) {
++          READ_ONCE(idev->cnf.suppress_frag_ndisc)) {
+               net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n");
+               return true;
+       }
+@@ -1824,8 +1824,8 @@ static int ndisc_netdev_event(struct not
+               idev = in6_dev_get(dev);
+               if (!idev)
+                       break;
+-              if (idev->cnf.ndisc_notify ||
+-                  net->ipv6.devconf_all->ndisc_notify)
++              if (READ_ONCE(idev->cnf.ndisc_notify) ||
++                  READ_ONCE(net->ipv6.devconf_all->ndisc_notify))
+                       ndisc_send_unsol_na(dev);
+               in6_dev_put(idev);
+               break;
+--- a/net/ipv6/seg6_hmac.c
++++ b/net/ipv6/seg6_hmac.c
+@@ -242,6 +242,7 @@ bool seg6_hmac_validate_skb(struct sk_bu
+       struct sr6_tlv_hmac *tlv;
+       struct ipv6_sr_hdr *srh;
+       struct inet6_dev *idev;
++      int require_hmac;
+       idev = __in6_dev_get(skb->dev);
+       if (!idev)
+@@ -251,16 +252,17 @@ bool seg6_hmac_validate_skb(struct sk_bu
+       tlv = seg6_get_tlv_hmac(srh);
++      require_hmac = READ_ONCE(idev->cnf.seg6_require_hmac);
+       /* mandatory check but no tlv */
+-      if (idev->cnf.seg6_require_hmac > 0 && !tlv)
++      if (require_hmac > 0 && !tlv)
+               return false;
+       /* no check */
+-      if (idev->cnf.seg6_require_hmac < 0)
++      if (require_hmac < 0)
+               return true;
+       /* check only if present */
+-      if (idev->cnf.seg6_require_hmac == 0 && !tlv)
++      if (require_hmac == 0 && !tlv)
+               return true;
+       /* now, seg6_require_hmac >= 0 && tlv */
diff --git a/queue-5.15/ipv6-ioam-add-null-check-for-idev-in-ipv6_hop_ioam.patch b/queue-5.15/ipv6-ioam-add-null-check-for-idev-in-ipv6_hop_ioam.patch
new file mode 100644 (file)
index 0000000..3c7c33f
--- /dev/null
@@ -0,0 +1,59 @@
+From stable+bounces-256873-greg=kroah.com@vger.kernel.org Sat May 30 17:09:38 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 07:39:27 -0400
+Subject: ipv6: ioam: add NULL check for idev in ipv6_hop_ioam()
+To: stable@vger.kernel.org
+Cc: Justin Iurman <justin.iurman@gmail.com>, Ido Schimmel <idosch@nvidia.com>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530113927.1939561-2-sashal@kernel.org>
+
+From: Justin Iurman <justin.iurman@gmail.com>
+
+[ Upstream commit d4ea0dfd75011b78cebf3808f98ac4c4f51a6fb9 ]
+
+Reported by Sashiko:
+
+The function ipv6_hop_ioam() accesses
+__in6_dev_get(skb->dev)->cnf.ioam6_enabled without validating the returned
+idev pointer. Because addrconf_ifdown() can concurrently clear dev->ip6_ptr
+via RCU, __in6_dev_get() can return NULL during interface teardown, which
+could cause a NULL pointer dereference when processing an IOAM Hop-by-Hop
+option.
+
+Let's add a check and use SKB_DROP_REASON_IPV6DISABLED accordingly.
+
+Fixes: 9ee11f0fff20 ("ipv6: ioam: Data plane support for Pre-allocated Trace")
+Cc: stable@vger.kernel.org
+Signed-off-by: Justin Iurman <justin.iurman@gmail.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260517183059.29140-1-justin.iurman@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv6/exthdrs.c |    8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/net/ipv6/exthdrs.c
++++ b/net/ipv6/exthdrs.c
+@@ -952,14 +952,20 @@ static bool ipv6_hop_ioam(struct sk_buff
+ {
+       struct ioam6_trace_hdr *trace;
+       struct ioam6_namespace *ns;
++      struct inet6_dev *idev;
+       struct ioam6_hdr *hdr;
+       /* Bad alignment (must be 4n-aligned) */
+       if (optoff & 3)
+               goto drop;
++      /* Does the device still have IPv6 configuration? */
++      idev = __in6_dev_get(skb->dev);
++      if (!idev)
++              goto drop;
++
+       /* Ignore if IOAM is not enabled on ingress */
+-      if (!READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_enabled))
++      if (!READ_ONCE(idev->cnf.ioam6_enabled))
+               goto ignore;
+       /* Truncated Option header */
diff --git a/queue-5.15/mm-huge_memory-update-file-pmd-counter-before-folio_put.patch b/queue-5.15/mm-huge_memory-update-file-pmd-counter-before-folio_put.patch
new file mode 100644 (file)
index 0000000..18401df
--- /dev/null
@@ -0,0 +1,56 @@
+From stable+bounces-263511-greg=kroah.com@vger.kernel.org Tue Jun 16 07:05:10 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Jun 2026 21:35:03 -0400
+Subject: mm/huge_memory: update file PMD counter before folio_put()
+To: stable@vger.kernel.org
+Cc: Yin Tirui <yintirui@huawei.com>, Lorenzo Stoakes <ljs@kernel.org>, "David Hildenbrand (arm)" <david@kernel.org>, Lance Yang <lance.yang@linux.dev>, Dev Jain <dev.jain@arm.com>, Baolin Wang <baolin.wang@linux.alibaba.com>, Barry Song <baohua@kernel.org>, Chen Jun <chenjun102@huawei.com>, Kefeng Wang <wangkefeng.wang@huawei.com>, "Liam R. Howlett" <liam@infradead.org>, Nico Pache <npache@redhat.com>, Ryan Roberts <ryan.roberts@arm.com>, Vlastimil Babka <vbabka@kernel.org>, Yang Shi <yang.shi@linux.alibaba.com>, Zi Yan <ziy@nvidia.com>, Andrew Morton <akpm@linux-foundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260616013503.2708473-1-sashal@kernel.org>
+
+From: Yin Tirui <yintirui@huawei.com>
+
+[ Upstream commit 8d878059924f12c1bc24556a92ec56add74de3c8 ]
+
+__split_huge_pmd_locked() updates the file/shmem RSS counter after
+dropping the PMD mapping's folio reference.  If folio_put() drops the last
+reference, mm_counter_file() can later read freed folio state via
+folio_test_swapbacked().
+
+Move the counter update before folio_put().
+
+Link: https://lore.kernel.org/20260526101337.1984081-1-yintirui@huawei.com
+Fixes: fadae2953072 ("thp: use mm_file_counter to determine update which rss counter")
+Signed-off-by: Yin Tirui <yintirui@huawei.com>
+Reviewed-by: Lorenzo Stoakes <ljs@kernel.org>
+Acked-by: David Hildenbrand (arm) <david@kernel.org>
+Reviewed-by: Lance Yang <lance.yang@linux.dev>
+Reviewed-by: Dev Jain <dev.jain@arm.com>
+Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
+Cc: Barry Song <baohua@kernel.org>
+Cc: Chen Jun <chenjun102@huawei.com>
+Cc: Kefeng Wang <wangkefeng.wang@huawei.com>
+Cc: Liam R. Howlett <liam@infradead.org>
+Cc: Nico Pache <npache@redhat.com>
+Cc: Ryan Roberts <ryan.roberts@arm.com>
+Cc: Vlastimil Babka <vbabka@kernel.org>
+Cc: Yang Shi <yang.shi@linux.alibaba.com>
+Cc: Zi Yan <ziy@nvidia.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/huge_memory.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/mm/huge_memory.c
++++ b/mm/huge_memory.c
+@@ -1994,7 +1994,9 @@ static void __split_huge_pmd_locked(stru
+                       if (!PageReferenced(page) && pmd_young(old_pmd))
+                               SetPageReferenced(page);
+                       page_remove_rmap(page, true);
++                      add_mm_counter(mm, mm_counter_file(page), -HPAGE_PMD_NR);
+                       put_page(page);
++                      return;
+               }
+               add_mm_counter(mm, mm_counter_file(page), -HPAGE_PMD_NR);
+               return;
diff --git a/queue-5.15/mm-hugetlb_cma-round-up-per_node-before-logging-it.patch b/queue-5.15/mm-hugetlb_cma-round-up-per_node-before-logging-it.patch
new file mode 100644 (file)
index 0000000..cacc038
--- /dev/null
@@ -0,0 +1,79 @@
+From stable+bounces-247238-greg=kroah.com@vger.kernel.org Thu May 14 21:22:58 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 May 2026 11:52:52 -0400
+Subject: mm/hugetlb_cma: round up per_node before logging it
+To: stable@vger.kernel.org
+Cc: Sang-Heon Jeon <ekffu200098@gmail.com>, Muchun Song <muchun.song@linux.dev>, David Hildenbrand <david@kernel.org>, Oscar Salvador <osalvador@suse.de>, Andrew Morton <akpm@linux-foundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260514155252.308763-1-sashal@kernel.org>
+
+From: Sang-Heon Jeon <ekffu200098@gmail.com>
+
+[ Upstream commit 8f5ce56b76303c55b78a87af996e2e0f8535f979 ]
+
+When the user requests a total hugetlb CMA size without per-node
+specification, hugetlb_cma_reserve() computes per_node from
+hugetlb_cma_size and the number of nodes that have memory
+
+        per_node = DIV_ROUND_UP(hugetlb_cma_size,
+                                nodes_weight(hugetlb_bootmem_nodes));
+
+The reservation loop later computes
+
+        size = round_up(min(per_node, hugetlb_cma_size - reserved),
+                          PAGE_SIZE << order);
+
+So the actually reserved per_node size is multiple of (PAGE_SIZE <<
+order), but the logged per_node is not rounded up, so it may be smaller
+than the actual reserved size.
+
+For example, as the existing comment describes, if a 3 GB area is
+requested on a machine with 4 NUMA nodes that have memory, 1 GB is
+allocated on the first three nodes, but the printed log is
+
+        hugetlb_cma: reserve 3072 MiB, up to 768 MiB per node
+
+Round per_node up to (PAGE_SIZE << order) before logging so that the
+printed log always matches the actual reserved size.  No functional change
+to the actual reservation size, as the following case analysis shows
+
+1. remaining (hugetlb_cma_size - reserved) >= rounded per_node
+ - AS-IS: min() picks unrounded per_node;
+    round_up() returns rounded per_node
+ - TO-BE: min() picks rounded per_node;
+    round_up() returns rounded per_node (no-op)
+2. remaining < unrounded per_node
+ - AS-IS: min() picks remaining;
+    round_up() returns round_up(remaining)
+ - TO-BE: min() picks remaining;
+    round_up() returns round_up(remaining)
+3. unrounded per_node <= remaining < rounded per_node
+ - AS-IS: min() picks unrounded per_node;
+    round_up() returns rounded per_node
+ - TO-BE: min() picks remaining;
+    round_up() returns round_up(remaining) equals rounded per_node
+
+Link: https://lore.kernel.org/20260422143353.852257-1-ekffu200098@gmail.com
+Fixes: cf11e85fc08c ("mm: hugetlb: optionally allocate gigantic hugepages using cma") # 5.7
+Signed-off-by: Sang-Heon Jeon <ekffu200098@gmail.com>
+Reviewed-by: Muchun Song <muchun.song@linux.dev>
+Cc: David Hildenbrand <david@kernel.org>
+Cc: Oscar Salvador <osalvador@suse.de>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+[ applied the one-line `round_up` to `mm/hugetlb.c` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/hugetlb.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -6493,6 +6493,7 @@ void __init hugetlb_cma_reserve(int orde
+        * let's allocate 1 GB on first three nodes and ignore the last one.
+        */
+       per_node = DIV_ROUND_UP(hugetlb_cma_size, nr_online_nodes);
++      per_node = round_up(per_node, PAGE_SIZE << order);
+       pr_info("hugetlb_cma: reserve %lu MiB, up to %lu MiB per node\n",
+               hugetlb_cma_size / SZ_1M, per_node / SZ_1M);
diff --git a/queue-5.15/mptcp-do-not-drop-partial-packets.patch b/queue-5.15/mptcp-do-not-drop-partial-packets.patch
new file mode 100644 (file)
index 0000000..f7b05e9
--- /dev/null
@@ -0,0 +1,77 @@
+From stable+bounces-259286-greg=kroah.com@vger.kernel.org Sun May 31 01:17:53 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 15:47:45 -0400
+Subject: mptcp: do not drop partial packets
+To: stable@vger.kernel.org
+Cc: Shardul Bankar <shardul.b@mpiricsoftware.com>, Paolo Abeni <pabeni@redhat.com>, "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530194745.3257532-1-sashal@kernel.org>
+
+From: Shardul Bankar <shardul.b@mpiricsoftware.com>
+
+[ Upstream commit 50c2d91c5dfa0e465826ec1f8dbad9cdc254bd85 ]
+
+When a packet arrives with map_seq < ack_seq < end_seq, the beginning
+of the packet has already been acknowledged but the end contains new
+data. Currently the entire packet is dropped as "old data," forcing
+the sender to retransmit.
+
+Instead, skip the already-acked bytes by adjusting the skb offset and
+enqueue only the new portion. Update bytes_received and ack_seq to
+reflect the new data consumed.
+
+A previous attempt at this fix has been sent by Paolo Abeni [1], but had
+issues [2]: it also added a zero-window check and changed rcv_wnd_sent
+initialization, which caused test regressions. This version addresses
+only the partial packet handling without modifying receive window
+accounting.
+
+Fixes: ab174ad8ef76 ("mptcp: move ooo skbs into msk out of order queue.")
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/c9b426a4e163aa3c4fe8b80c79f1a610f47ae7d8.1763075056.git.pabeni@redhat.com [1]
+Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/600 [2]
+Signed-off-by: Shardul Bankar <shardul.b@mpiricsoftware.com>
+[pabeni@redhat.com: update map]
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260515-net-mptcp-misc-fixes-7-1-rc4-v2-1-701e96419f2f@kernel.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[ dropped `msk->bytes_received += copy_len;` and relocated the `drop:` label to the function end for the existing RCVPRUNED `goto drop;` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/protocol.c |   22 +++++++++++++++++++---
+ 1 file changed, 19 insertions(+), 3 deletions(-)
+
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -329,10 +329,26 @@ static bool __mptcp_move_skb(struct mptc
+               return false;
+       }
+-      /* old data, keep it simple and drop the whole pkt, sender
+-       * will retransmit as needed, if needed.
++      /* Completely old data? */
++      if (!after64(MPTCP_SKB_CB(skb)->end_seq, msk->ack_seq)) {
++              MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA);
++              mptcp_drop(sk, skb);
++              return false;
++      }
++
++      /* Partial packet: map_seq < ack_seq < end_seq.
++       * Skip the already-acked bytes and enqueue the new data.
+        */
+-      MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA);
++      copy_len = MPTCP_SKB_CB(skb)->end_seq - msk->ack_seq;
++      MPTCP_SKB_CB(skb)->offset += msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq;
++      MPTCP_SKB_CB(skb)->map_seq += msk->ack_seq -
++                                    MPTCP_SKB_CB(skb)->map_seq;
++      WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len);
++
++      skb_set_owner_r(skb, sk);
++      __skb_queue_tail(&sk->sk_receive_queue, skb);
++      return true;
++
+ drop:
+       mptcp_drop(sk, skb);
+       return false;
diff --git a/queue-5.15/mptcp-pm-add_addr-rtx-fix-potential-data-race.patch b/queue-5.15/mptcp-pm-add_addr-rtx-fix-potential-data-race.patch
new file mode 100644 (file)
index 0000000..fc0dc17
--- /dev/null
@@ -0,0 +1,56 @@
+From stable+bounces-249313-greg=kroah.com@vger.kernel.org Mon May 18 20:14:36 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 18 May 2026 10:40:42 -0400
+Subject: mptcp: pm: ADD_ADDR rtx: fix potential data-race
+To: stable@vger.kernel.org
+Cc: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Mat Martineau <martineau@kernel.org>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260518144042.1361354-1-sashal@kernel.org>
+
+From: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
+
+[ Upstream commit 5cd6e0ad79d2615264f63929f8b457ad97ae550d ]
+
+This mptcp_pm_add_timer() helper is executed as a timer callback in
+softirq context. To avoid any data races, the socket lock needs to be
+held with bh_lock_sock().
+
+If the socket is in use, retry again soon after, similar to what is done
+with the keepalive timer.
+
+Fixes: 00cfd77b9063 ("mptcp: retransmit ADD_ADDR when timeout")
+Cc: stable@vger.kernel.org
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-3-fca8091060a4@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ applied hunk to `net/mptcp/pm_netlink.c` instead of `net/mptcp/pm.c` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/pm_netlink.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -330,6 +330,13 @@ static void mptcp_pm_add_timer(struct ti
+       if (!entry->addr.id)
+               return;
++      bh_lock_sock(sk);
++      if (sock_owned_by_user(sk)) {
++              /* Try again later. */
++              sk_reset_timer(sk, timer, jiffies + HZ / 20);
++              goto out;
++      }
++
+       if (mptcp_pm_should_add_signal_addr(msk)) {
+               sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8);
+               goto out;
+@@ -358,6 +365,7 @@ static void mptcp_pm_add_timer(struct ti
+               mptcp_pm_subflow_established(msk);
+ out:
++      bh_unlock_sock(sk);
+       __sock_put(sk);
+ }
diff --git a/queue-5.15/mptcp-pm-add_addr-rtx-resched-blocked-add_addr-quicker.patch b/queue-5.15/mptcp-pm-add_addr-rtx-resched-blocked-add_addr-quicker.patch
new file mode 100644 (file)
index 0000000..5b7f4c7
--- /dev/null
@@ -0,0 +1,53 @@
+From stable+bounces-249637-greg=kroah.com@vger.kernel.org Tue May 19 22:17:43 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 May 2026 12:18:04 -0400
+Subject: mptcp: pm: ADD_ADDR rtx: resched blocked ADD_ADDR quicker
+To: stable@vger.kernel.org
+Cc: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Mat Martineau <martineau@kernel.org>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260519161804.2778143-1-sashal@kernel.org>
+
+From: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
+
+[ Upstream commit 3cf12492891c4b5ff54dda404a2de4ec54c9e1b5 ]
+
+When an ADD_ADDR needs to be retransmitted and another one has already
+been prepared -- e.g. multiple ADD_ADDRs have been sent in a row and
+need to be retransmitted later -- this additional retransmission will
+need to wait.
+
+In this case, the timer was reset to TCP_RTO_MAX / 8, which is ~15
+seconds. This delay is unnecessary long: it should just be rescheduled
+at the next opportunity, e.g. after the retransmission timeout.
+
+Without this modification, some issues can be seen from time to time in
+the selftests when multiple ADD_ADDRs are sent, and the host takes time
+to process them, e.g. the "signal addresses, ADD_ADDR timeout" MPTCP
+Join selftest, especially with a debug kernel config.
+
+Note that on older kernels, 'timeout' is not available. It should be
+enough to replace it by one second (HZ).
+
+Fixes: 00cfd77b9063 ("mptcp: retransmit ADD_ADDR when timeout")
+Cc: stable@vger.kernel.org
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-6-fca8091060a4@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ replaced `TCP_RTO_MAX / 8` with `HZ` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/pm_netlink.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -338,7 +338,7 @@ static void mptcp_pm_add_timer(struct ti
+       }
+       if (mptcp_pm_should_add_signal_addr(msk)) {
+-              sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8);
++              sk_reset_timer(sk, timer, jiffies + HZ);
+               goto out;
+       }
diff --git a/queue-5.15/mptcp-pm-fix-add_addr-timer-infinite-retry-on-option-space-insufficient.patch b/queue-5.15/mptcp-pm-fix-add_addr-timer-infinite-retry-on-option-space-insufficient.patch
new file mode 100644 (file)
index 0000000..211ec8a
--- /dev/null
@@ -0,0 +1,144 @@
+From stable+bounces-256883-greg=kroah.com@vger.kernel.org Sat May 30 17:19:42 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 07:48:13 -0400
+Subject: mptcp: pm: fix ADD_ADDR timer infinite retry on option space insufficient
+To: stable@vger.kernel.org
+Cc: Li Xiasong <lixiasong1@huawei.com>, "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Paolo Abeni <pabeni@redhat.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530114813.1965800-1-sashal@kernel.org>
+
+From: Li Xiasong <lixiasong1@huawei.com>
+
+[ Upstream commit 51e398a3b8961b26a8c0a4ba9a777c5339791707 ]
+
+When TCP option space is insufficient (e.g., when sending ADD_ADDR with an
+IPv6 address and port while tcp_timestamps is enabled), the original code
+jumped to out_unlock without clearing the addr_signal flag. This caused
+mptcp_pm_add_timer to keep rescheduling indefinitely, not sending ADD_ADDR,
+preventing subsequent addresses in the endpoint list from being announced.
+
+Handle this case by clearing the ADD_ADDR signal and skipping the matching
+ADD_ADDR retransmission entry. The skip path cancels the matching timer
+(with id check) and advances PM state progression, preserving forward
+progress to subsequent PM work.
+
+This cancellation is inherently best-effort. A concurrent add_timer
+callback may already be running and may acquire pm.lock before the
+cancel path updates entry state. In that case, one final ADD_ADDR
+transmit attempt can still be executed.
+
+Once the cancel path sets entry->retrans_times to ADD_ADDR_RETRANS_MAX,
+the callback-side retrans_times check suppresses further ADD_ADDR
+retransmissions.
+
+Note that when an ADD_ADDR is being prepared, a pure-ACK is queued. On
+the output side, it means that it is fine to skip non-pure-ACK packets,
+when drop_other_suboptions is set: a pure-ACK will be processed soon
+after.
+
+Fixes: 00cfd77b9063 ("mptcp: retransmit ADD_ADDR when timeout")
+Cc: stable@vger.kernel.org
+Signed-off-by: Li Xiasong <lixiasong1@huawei.com>
+Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260515-net-mptcp-misc-fixes-7-1-rc4-v2-2-701e96419f2f@kernel.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/pm.c         |   34 +++++++++++++++++++++++++++-------
+ net/mptcp/pm_netlink.c |   16 +++++++++++++---
+ 2 files changed, 40 insertions(+), 10 deletions(-)
+
+--- a/net/mptcp/pm.c
++++ b/net/mptcp/pm.c
+@@ -270,6 +270,7 @@ bool mptcp_pm_add_addr_signal(struct mpt
+                             struct mptcp_addr_info *addr, bool *echo,
+                             bool *drop_other_suboptions)
+ {
++      bool skip_add_addr = false;
+       int ret = false;
+       u8 add_addr;
+       u8 family;
+@@ -291,24 +292,43 @@ bool mptcp_pm_add_addr_signal(struct mpt
+       }
+       *echo = mptcp_pm_should_add_signal_echo(msk);
+-      port = !!(*echo ? msk->pm.remote.port : msk->pm.local.port);
+-
+-      family = *echo ? msk->pm.remote.family : msk->pm.local.family;
+-      if (remaining < mptcp_add_addr_len(family, *echo, port))
+-              goto out_unlock;
+-
+       if (*echo) {
+               *addr = msk->pm.remote;
+               add_addr = msk->pm.addr_signal & ~BIT(MPTCP_ADD_ADDR_ECHO);
++              port = !!msk->pm.remote.port;
++              family = msk->pm.remote.family;
+       } else {
+               *addr = msk->pm.local;
+               add_addr = msk->pm.addr_signal & ~BIT(MPTCP_ADD_ADDR_SIGNAL);
++              port = !!msk->pm.local.port;
++              family = msk->pm.local.family;
+       }
+-      WRITE_ONCE(msk->pm.addr_signal, add_addr);
++
++      if (remaining < mptcp_add_addr_len(family, *echo, port)) {
++              if (!*drop_other_suboptions)
++                      goto out_unlock;
++
++              if (!*echo)
++                      skip_add_addr = true;
++              goto drop_signal_mark;
++      }
++
+       ret = true;
++drop_signal_mark:
++      WRITE_ONCE(msk->pm.addr_signal, add_addr);
++
+ out_unlock:
+       spin_unlock_bh(&msk->pm.lock);
++
++      /* On pure-ACK option-space exhaustion, stop retrying this ADD_ADDR:
++       * clear the signal bit, cancel the matching retransmission timer, and
++       * let the PM state machine progress.
++       */
++      if (skip_add_addr) {
++              mptcp_pm_del_add_timer(msk, addr, true);
++              mptcp_pm_subflow_established(msk);
++      }
+       return ret;
+ }
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -348,7 +348,13 @@ static void mptcp_pm_add_timer(struct ti
+       spin_lock_bh(&msk->pm.lock);
+-      if (!mptcp_pm_should_add_signal_addr(msk)) {
++      /* The cancel path (mptcp_pm_del_add_timer()) can race with this
++       * callback. Once cancel updates retrans_times to MAX, suppress further
++       * retransmissions here. If this callback acquires pm.lock first, one
++       * final transmit attempt is still possible.
++       */
++      if (entry->retrans_times < ADD_ADDR_RETRANS_MAX &&
++          !mptcp_pm_should_add_signal_addr(msk)) {
+               pr_debug("retransmit ADD_ADDR id=%d\n", entry->addr.id);
+               mptcp_pm_announce_addr(msk, &entry->addr, false);
+               mptcp_pm_add_addr_send_ack(msk);
+@@ -392,8 +398,12 @@ mptcp_pm_del_add_timer(struct mptcp_sock
+       /* Note: entry might have been removed by another thread.
+        * We hold rcu_read_lock() to ensure it is not freed under us.
+        */
+-      if (stop_timer)
+-              sk_stop_timer_sync(sk, &entry->add_timer);
++      if (stop_timer) {
++              if (check_id)
++                      sk_stop_timer(sk, &entry->add_timer);
++              else
++                      sk_stop_timer_sync(sk, &entry->add_timer);
++      }
+       rcu_read_unlock();
+       return entry;
diff --git a/queue-5.15/mptcp-pm-prio-skip-closed-subflows.patch b/queue-5.15/mptcp-pm-prio-skip-closed-subflows.patch
new file mode 100644 (file)
index 0000000..87700e0
--- /dev/null
@@ -0,0 +1,46 @@
+From stable+bounces-249304-greg=kroah.com@vger.kernel.org Mon May 18 20:00:14 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 18 May 2026 10:23:33 -0400
+Subject: mptcp: pm: prio: skip closed subflows
+To: stable@vger.kernel.org
+Cc: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Mat Martineau <martineau@kernel.org>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260518142333.1308198-1-sashal@kernel.org>
+
+From: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
+
+[ Upstream commit 166b78344031bf7ac9f55cb5282776cfd85f220e ]
+
+When sending an MP_PRIO, closed subflows need to be skipped.
+
+This fixes the case where the initial subflow got closed, re-opened
+later, then an MP_PRIO is needed for the same local address.
+
+Note that explicit MP_PRIO cannot be sent during the 3WHS, so it is fine
+to use __mptcp_subflow_active().
+
+Fixes: 067065422fcd ("mptcp: add the outgoing MP_PRIO support")
+Cc: stable@vger.kernel.org
+Fixes: b29fcfb54cd7 ("mptcp: full disconnect implementation")
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-9-fca8091060a4@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ applied to renamed function `mptcp_pm_nl_mp_prio_send_ack()` in `pm_netlink.c` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/pm_netlink.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -828,6 +828,9 @@ int mptcp_pm_nl_mp_prio_send_ack(struct
+               struct sock *sk = (struct sock *)msk;
+               struct mptcp_addr_info local;
++              if (!__mptcp_subflow_active(subflow))
++                      continue;
++
+               mptcp_local_address((struct sock_common *)ssk, &local);
+               if (!addresses_equal(&local, addr, addr->port))
+                       continue;
diff --git a/queue-5.15/mtd-docg3-convert-to-platform-remove-callback-returning-void.patch b/queue-5.15/mtd-docg3-convert-to-platform-remove-callback-returning-void.patch
deleted file mode 100644 (file)
index d85e0b0..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-From stable+bounces-242570-greg=kroah.com@vger.kernel.org Sat May  2 07:42:01 2026
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri,  1 May 2026 22:11:53 -0400
-Subject: mtd: docg3: Convert to platform remove callback returning void
-To: stable@vger.kernel.org
-Cc: "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>, "Miquel Raynal" <miquel.raynal@bootlin.com>, "Tudor Ambarus" <tudor.ambarus@linaro.org>, "Sasha Levin" <sashal@kernel.org>
-Message-ID: <20260502021154.4166366-1-sashal@kernel.org>
-
-From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
-
-[ Upstream commit eb0cec77d534413a800ec20944a2b1e37cfecdcf ]
-
-The .remove() callback for a platform driver returns an int which makes
-many driver authors wrongly assume it's possible to do error handling by
-returning an error code. However the value returned is ignored (apart
-from emitting a warning) and this typically results in resource leaks.
-
-To improve here there is a quest to make the remove callback return
-void. In the first step of this quest all drivers are converted to
-.remove_new(), which already returns void. Eventually after all drivers
-are converted, .remove_new() will be renamed to .remove().
-
-Trivially convert this driver from always returning zero in the remove
-callback to the void returning variant.
-
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
-Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
-Acked-by: Tudor Ambarus <tudor.ambarus@linaro.org>
-Link: https://lore.kernel.org/linux-mtd/20231008200143.196369-5-u.kleine-koenig@pengutronix.de
-Stable-dep-of: ca19808bc6fa ("mtd: docg3: fix use-after-free in docg3_release()")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- drivers/mtd/devices/docg3.c | 5 ++---
- 1 file changed, 2 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
-index 27c08f22dec8c..25a7df6448028 100644
---- a/drivers/mtd/devices/docg3.c
-+++ b/drivers/mtd/devices/docg3.c
-@@ -2038,7 +2038,7 @@ static int __init docg3_probe(struct platform_device *pdev)
-  *
-  * Returns 0
-  */
--static int docg3_release(struct platform_device *pdev)
-+static void docg3_release(struct platform_device *pdev)
- {
-       struct docg3_cascade *cascade = platform_get_drvdata(pdev);
-       struct docg3 *docg3 = cascade->floors[0]->priv;
-@@ -2050,7 +2050,6 @@ static int docg3_release(struct platform_device *pdev)
-                       doc_release_device(cascade->floors[floor]);
-       bch_free(docg3->cascade->bch);
--      return 0;
- }
- #ifdef CONFIG_OF
-@@ -2068,7 +2067,7 @@ static struct platform_driver g3_driver = {
-       },
-       .suspend        = docg3_suspend,
-       .resume         = docg3_resume,
--      .remove         = docg3_release,
-+      .remove_new     = docg3_release,
- };
- module_platform_driver_probe(g3_driver, docg3_probe);
--- 
-2.53.0
-
diff --git a/queue-5.15/mtd-docg3-fix-use-after-free-in-docg3_release.patch b/queue-5.15/mtd-docg3-fix-use-after-free-in-docg3_release.patch
deleted file mode 100644 (file)
index 1ecea34..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-From stable+bounces-242571-greg=kroah.com@vger.kernel.org Sat May  2 07:42:01 2026
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri,  1 May 2026 22:11:54 -0400
-Subject: mtd: docg3: fix use-after-free in docg3_release()
-To: stable@vger.kernel.org
-Cc: James Kim <james010kim@gmail.com>, Miquel Raynal <miquel.raynal@bootlin.com>, Sasha Levin <sashal@kernel.org>
-Message-ID: <20260502021154.4166366-2-sashal@kernel.org>
-
-From: James Kim <james010kim@gmail.com>
-
-[ Upstream commit ca19808bc6fac7e29420d8508df569b346b3e339 ]
-
-In docg3_release(), the docg3 pointer is obtained from
-cascade->floors[0]->priv before the loop that calls
-doc_release_device() on each floor. doc_release_device() frees the
-docg3 struct via kfree(docg3) at line 1881. After the loop,
-docg3->cascade->bch dereferences the already-freed pointer.
-
-Fix this by accessing cascade->bch directly, which is equivalent
-since docg3->cascade points back to the same cascade struct, and
-is already available as a local variable. This also removes the
-now-unused docg3 local variable.
-
-Fixes: c8ae3f744ddc ("lib/bch: Rework a little bit the exported function names")
-Cc: stable@vger.kernel.org
-Signed-off-by: James Kim <james010kim@gmail.com>
-Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- drivers/mtd/devices/docg3.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
-diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
-index 25a7df6448028..7de576404b14f 100644
---- a/drivers/mtd/devices/docg3.c
-+++ b/drivers/mtd/devices/docg3.c
-@@ -2041,7 +2041,6 @@ static int __init docg3_probe(struct platform_device *pdev)
- static void docg3_release(struct platform_device *pdev)
- {
-       struct docg3_cascade *cascade = platform_get_drvdata(pdev);
--      struct docg3 *docg3 = cascade->floors[0]->priv;
-       int floor;
-       doc_unregister_sysfs(pdev, cascade);
-@@ -2049,7 +2048,7 @@ static void docg3_release(struct platform_device *pdev)
-               if (cascade->floors[floor])
-                       doc_release_device(cascade->floors[floor]);
--      bch_free(docg3->cascade->bch);
-+      bch_free(cascade->bch);
- }
- #ifdef CONFIG_OF
--- 
-2.53.0
-
diff --git a/queue-5.15/net-hsr-defer-node-table-free-until-after-rcu-readers.patch b/queue-5.15/net-hsr-defer-node-table-free-until-after-rcu-readers.patch
new file mode 100644 (file)
index 0000000..3757f2a
--- /dev/null
@@ -0,0 +1,55 @@
+From stable+bounces-256837-greg=kroah.com@vger.kernel.org Sat May 30 05:37:45 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 20:07:34 -0400
+Subject: net: hsr: defer node table free until after RCU readers
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530000734.2087399-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit aaec7096f9961eb223b5b149abe9495525c205d9 ]
+
+HSR node-list and node-status generic-netlink operations run under
+rcu_read_lock(). They walk hsr->node_db through hsr_get_next_node() and
+hsr_get_node_data(), but RTM_DELLINK teardown removes the same node table
+with plain list_del() and frees each node immediately.
+
+That lets a generic-netlink reader hold a struct hsr_node pointer across
+hsr_dellink(). In a KASAN build, widening the reader window after
+hsr_get_next_node() obtains the node reproduces a slab-use-after-free
+when the reader copies node->macaddress_A; the freeing stack is
+hsr_del_nodes() from hsr_dellink().
+
+Use list_del_rcu() and defer the free through the existing
+hsr_free_node_rcu() callback. This matches the lifetime rule used by the
+HSR prune paths, which already delete nodes with list_del_rcu() and
+call_rcu().
+
+Fixes: b9a1e627405d ("hsr: implement dellink to clean up resources")
+Cc: stable@vger.kernel.org # v5.3+
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Link: https://patch.msgid.link/20260513233838.3064715-2-michael.bommarito@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ replaced `list_del`+`call_rcu(hsr_free_node_rcu)` with `list_del_rcu`+`kfree_rcu(node, rcu_head)` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/hsr/hsr_framereg.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/net/hsr/hsr_framereg.c
++++ b/net/hsr/hsr_framereg.c
+@@ -123,8 +123,10 @@ void hsr_del_nodes(struct list_head *nod
+       struct hsr_node *node;
+       struct hsr_node *tmp;
+-      list_for_each_entry_safe(node, tmp, node_db, mac_list)
+-              kfree(node);
++      list_for_each_entry_safe(node, tmp, node_db, mac_list) {
++              list_del_rcu(&node->mac_list);
++              kfree_rcu(node, rcu_head);
++      }
+ }
+ void prp_handle_san_frame(bool san, enum hsr_port_type port,
diff --git a/queue-5.15/net-ipv4-stop-checking-crypto_ahash_alignmask.patch b/queue-5.15/net-ipv4-stop-checking-crypto_ahash_alignmask.patch
new file mode 100644 (file)
index 0000000..98a0637
--- /dev/null
@@ -0,0 +1,87 @@
+From stable+bounces-246955-greg=kroah.com@vger.kernel.org Wed May 13 22:40:24 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 13:09:40 -0400
+Subject: net: ipv4: stop checking crypto_ahash_alignmask
+To: stable@vger.kernel.org
+Cc: Eric Biggers <ebiggers@google.com>, Herbert Xu <herbert@gondor.apana.org.au>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260513170942.3829179-1-sashal@kernel.org>
+
+From: Eric Biggers <ebiggers@google.com>
+
+[ Upstream commit e77f5dd701381cef35b9ea8b6dea6e62c8a7f9f3 ]
+
+Now that the alignmask for ahash and shash algorithms is always 0,
+crypto_ahash_alignmask() always returns 0 and will be removed.  In
+preparation for this, stop checking crypto_ahash_alignmask() in ah4.c.
+
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Stable-dep-of: ec54093e6a8f ("xfrm: ah: account for ESN high bits in async callbacks")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv4/ah4.c |   17 +++++++----------
+ 1 file changed, 7 insertions(+), 10 deletions(-)
+
+--- a/net/ipv4/ah4.c
++++ b/net/ipv4/ah4.c
+@@ -27,9 +27,7 @@ static void *ah_alloc_tmp(struct crypto_
+ {
+       unsigned int len;
+-      len = size + crypto_ahash_digestsize(ahash) +
+-            (crypto_ahash_alignmask(ahash) &
+-             ~(crypto_tfm_ctx_alignment() - 1));
++      len = size + crypto_ahash_digestsize(ahash);
+       len = ALIGN(len, crypto_tfm_ctx_alignment());
+@@ -46,10 +44,9 @@ static inline u8 *ah_tmp_auth(void *tmp,
+       return tmp + offset;
+ }
+-static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp,
+-                           unsigned int offset)
++static inline u8 *ah_tmp_icv(void *tmp, unsigned int offset)
+ {
+-      return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1);
++      return tmp + offset;
+ }
+ static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash,
+@@ -129,7 +126,7 @@ static void ah_output_done(struct crypto
+       int ihl = ip_hdrlen(skb);
+       iph = AH_SKB_CB(skb)->tmp;
+-      icv = ah_tmp_icv(ahp->ahash, iph, ihl);
++      icv = ah_tmp_icv(iph, ihl);
+       memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
+       top_iph->tos = iph->tos;
+@@ -182,7 +179,7 @@ static int ah_output(struct xfrm_state *
+       if (!iph)
+               goto out;
+       seqhi = (__be32 *)((char *)iph + ihl);
+-      icv = ah_tmp_icv(ahash, seqhi, seqhi_len);
++      icv = ah_tmp_icv(seqhi, seqhi_len);
+       req = ah_tmp_req(ahash, icv);
+       sg = ah_req_sg(ahash, req);
+       seqhisg = sg + nfrags;
+@@ -279,7 +276,7 @@ static void ah_input_done(struct crypto_
+       work_iph = AH_SKB_CB(skb)->tmp;
+       auth_data = ah_tmp_auth(work_iph, ihl);
+-      icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len);
++      icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
+       err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
+       if (err)
+@@ -374,7 +371,7 @@ static int ah_input(struct xfrm_state *x
+       seqhi = (__be32 *)((char *)work_iph + ihl);
+       auth_data = ah_tmp_auth(seqhi, seqhi_len);
+-      icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len);
++      icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
+       req = ah_tmp_req(ahash, icv);
+       sg = ah_req_sg(ahash, req);
+       seqhisg = sg + nfrags;
diff --git a/queue-5.15/net-ipv6-stop-checking-crypto_ahash_alignmask.patch b/queue-5.15/net-ipv6-stop-checking-crypto_ahash_alignmask.patch
new file mode 100644 (file)
index 0000000..7f0e1f0
--- /dev/null
@@ -0,0 +1,87 @@
+From stable+bounces-246956-greg=kroah.com@vger.kernel.org Wed May 13 22:40:25 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 13:09:41 -0400
+Subject: net: ipv6: stop checking crypto_ahash_alignmask
+To: stable@vger.kernel.org
+Cc: Eric Biggers <ebiggers@google.com>, Herbert Xu <herbert@gondor.apana.org.au>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260513170942.3829179-2-sashal@kernel.org>
+
+From: Eric Biggers <ebiggers@google.com>
+
+[ Upstream commit 0a6bfaa0e695facb072f2fedfb55df37c4483b50 ]
+
+Now that the alignmask for ahash and shash algorithms is always 0,
+crypto_ahash_alignmask() always returns 0 and will be removed.  In
+preparation for this, stop checking crypto_ahash_alignmask() in ah6.c.
+
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Stable-dep-of: ec54093e6a8f ("xfrm: ah: account for ESN high bits in async callbacks")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv6/ah6.c |   17 +++++++----------
+ 1 file changed, 7 insertions(+), 10 deletions(-)
+
+--- a/net/ipv6/ah6.c
++++ b/net/ipv6/ah6.c
+@@ -79,9 +79,7 @@ static void *ah_alloc_tmp(struct crypto_
+ {
+       unsigned int len;
+-      len = size + crypto_ahash_digestsize(ahash) +
+-            (crypto_ahash_alignmask(ahash) &
+-             ~(crypto_tfm_ctx_alignment() - 1));
++      len = size + crypto_ahash_digestsize(ahash);
+       len = ALIGN(len, crypto_tfm_ctx_alignment());
+@@ -103,10 +101,9 @@ static inline u8 *ah_tmp_auth(u8 *tmp, u
+       return tmp + offset;
+ }
+-static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp,
+-                           unsigned int offset)
++static inline u8 *ah_tmp_icv(void *tmp, unsigned int offset)
+ {
+-      return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1);
++      return tmp + offset;
+ }
+ static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash,
+@@ -330,7 +327,7 @@ static void ah6_output_done(struct crypt
+       iph_base = AH_SKB_CB(skb)->tmp;
+       iph_ext = ah_tmp_ext(iph_base);
+-      icv = ah_tmp_icv(ahp->ahash, iph_ext, extlen);
++      icv = ah_tmp_icv(iph_ext, extlen);
+       memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
+       memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
+@@ -387,7 +384,7 @@ static int ah6_output(struct xfrm_state
+       iph_ext = ah_tmp_ext(iph_base);
+       seqhi = (__be32 *)((char *)iph_ext + extlen);
+-      icv = ah_tmp_icv(ahash, seqhi, seqhi_len);
++      icv = ah_tmp_icv(seqhi, seqhi_len);
+       req = ah_tmp_req(ahash, icv);
+       sg = ah_req_sg(ahash, req);
+       seqhisg = sg + nfrags;
+@@ -483,7 +480,7 @@ static void ah6_input_done(struct crypto
+       work_iph = AH_SKB_CB(skb)->tmp;
+       auth_data = ah_tmp_auth(work_iph, hdr_len);
+-      icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len);
++      icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
+       err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
+       if (err)
+@@ -591,7 +588,7 @@ static int ah6_input(struct xfrm_state *
+       auth_data = ah_tmp_auth((u8 *)work_iph, hdr_len);
+       seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
+-      icv = ah_tmp_icv(ahash, seqhi, seqhi_len);
++      icv = ah_tmp_icv(seqhi, seqhi_len);
+       req = ah_tmp_req(ahash, icv);
+       sg = ah_req_sg(ahash, req);
+       seqhisg = sg + nfrags;
diff --git a/queue-5.15/net-skbuff-fix-missing-zerocopy-reference-in-pskb_carve-helpers.patch b/queue-5.15/net-skbuff-fix-missing-zerocopy-reference-in-pskb_carve-helpers.patch
new file mode 100644 (file)
index 0000000..74eed5e
--- /dev/null
@@ -0,0 +1,92 @@
+From stable+bounces-260705-greg=kroah.com@vger.kernel.org Fri Jun  5 19:27:46 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 09:57:38 -0400
+Subject: net: skbuff: fix missing zerocopy reference in pskb_carve helpers
+To: stable@vger.kernel.org
+Cc: Minh Nguyen <minhnguyen.080505@gmail.com>, Willem de Bruijn <willemb@google.com>, Paolo Abeni <pabeni@redhat.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260605135738.973875-1-sashal@kernel.org>
+
+From: Minh Nguyen <minhnguyen.080505@gmail.com>
+
+[ Upstream commit 98d0912e9f841e5529a5b89a972805f34cb1c69d ]
+
+pskb_carve_inside_header() and pskb_carve_inside_nonlinear() both copy
+the old skb_shared_info header into a new buffer via memcpy(), which
+includes the destructor_arg pointer (uarg) for MSG_ZEROCOPY skbs.
+Neither function calls net_zcopy_get() for the new shinfo, creating an
+unaccounted holder: every skb_shared_info with destructor_arg set will
+call skb_zcopy_clear() once when freed, but the corresponding
+net_zcopy_get() was never called for the new copy. Repeated calls
+drive uarg->refcnt to zero prematurely, freeing ubuf_info_msgzc while
+TX skbs still hold live destructor_arg pointers.
+
+KASAN reports use-after-free on a freed ubuf_info_msgzc:
+
+  BUG: KASAN: slab-use-after-free in skb_release_data+0x77b/0x810
+  Read of size 8 at addr ffff88801574d3e8 by task poc/220
+
+  Call Trace:
+   skb_release_data+0x77b/0x810
+   kfree_skb_list_reason+0x13e/0x610
+   skb_release_data+0x4cd/0x810
+   sk_skb_reason_drop+0xf3/0x340
+   skb_queue_purge_reason+0x282/0x440
+   rds_tcp_inc_free+0x1e/0x30
+   rds_recvmsg+0x354/0x1780
+   __sys_recvmsg+0xdf/0x180
+
+  Allocated by task 219:
+   msg_zerocopy_realloc+0x157/0x7b0
+   tcp_sendmsg_locked+0x2892/0x3ba0
+
+  Freed by task 219:
+   ip_recv_error+0x74a/0xb10
+   tcp_recvmsg+0x475/0x530
+
+The skb consuming the late access still referenced the same uarg via
+shinfo->destructor_arg copied by pskb_carve_inside_nonlinear() without
+a refcount bump. This has been verified to be reliably exploitable: a
+working proof-of-concept achieves full root privilege escalation from
+an unprivileged local user on a default kernel configuration.
+
+The fix follows the pattern of pskb_expand_head() which has the same
+memcpy/cloned structure. For pskb_carve_inside_header(), net_zcopy_get()
+is placed after skb_orphan_frags() succeeds, so the orphan error path
+needs no cleanup. For pskb_carve_inside_nonlinear(), net_zcopy_get() is
+placed after all failure points and just before skb_release_data(), so
+no error path needs cleanup at all -- matching pskb_expand_head() more
+closely and avoiding the need for a balancing net_zcopy_put().
+
+Fixes: 6fa01ccd8830 ("skbuff: Add pskb_extract() helper function")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-sonnet-4-6
+Signed-off-by: Minh Nguyen <minhnguyen.080505@gmail.com>
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Link: https://patch.msgid.link/20260526041240.329462-1-minhnguyen.080505@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/core/skbuff.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -6256,6 +6256,8 @@ static int pskb_carve_inside_header(stru
+                       kfree(data);
+                       return -ENOMEM;
+               }
++              if (skb_zcopy(skb))
++                      net_zcopy_get(skb_zcopy(skb));
+               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+                       skb_frag_ref(skb, i);
+               if (skb_has_frag_list(skb))
+@@ -6404,6 +6406,8 @@ static int pskb_carve_inside_nonlinear(s
+               kfree(data);
+               return -ENOMEM;
+       }
++      if (skb_zcopy(skb))
++              net_zcopy_get(skb_zcopy(skb));
+       skb_release_data(skb);
+       skb->head = data;
diff --git a/queue-5.15/netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch b/queue-5.15/netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch
new file mode 100644 (file)
index 0000000..7998a0d
--- /dev/null
@@ -0,0 +1,86 @@
+From stable+bounces-263416-greg=kroah.com@vger.kernel.org Mon Jun 15 23:07:24 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Jun 2026 13:37:18 -0400
+Subject: netfilter: nft_fib: fix stale stack leak via the OIFNAME register
+To: stable@vger.kernel.org
+Cc: Davide Ornaghi <d.ornaghi97@gmail.com>, Florian Westphal <fw@strlen.de>, Pablo Neira Ayuso <pablo@netfilter.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260615173718.2302669-1-sashal@kernel.org>
+
+From: Davide Ornaghi <d.ornaghi97@gmail.com>
+
+[ Upstream commit ab185e0c4fb82dfba6fb86f8271e06f931d9c64c ]
+
+For NFT_FIB_RESULT_OIFNAME the destination register is declared with
+len = IFNAMSIZ (four 32-bit registers), but on the lookup-fail,
+RTN_LOCAL and oif-mismatch paths nft_fib{4,6}_eval() only writes one
+register via "*dest = 0". The remaining three registers are left as
+whatever was on the stack in nft_do_chain()'s struct nft_regs, and a
+downstream expression that loads the register span can leak that
+uninitialised kernel stack to userspace.
+
+The NFTA_FIB_F_PRESENT existence check has the same shape: it is only
+meaningful for NFT_FIB_RESULT_OIF, yet it was accepted for any result type
+while the eval stores a single byte via nft_reg_store8(), leaving the rest
+of the declared span stale.
+
+Fix both:
+
+ - replace the bare "*dest = 0" in the eval with nft_fib_store_result(),
+   which strscpy_pad()s the whole IFNAMSIZ for OIFNAME (and is already
+   used on the other early-return path), and
+
+ - restrict NFTA_FIB_F_PRESENT to NFT_FIB_RESULT_OIF and declare its
+   destination as a single u8, so the marked span matches the one byte
+   the eval writes.
+
+Fixes: f6d0cbcf09c5 ("netfilter: nf_tables: add fib expression")
+Suggested-by: Florian Westphal <fw@strlen.de>
+Cc: stable@vger.kernel.org
+Signed-off-by: Davide Ornaghi <d.ornaghi97@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+[ kept the tree's existing `ip6_route_lookup`/`rt6_info` machinery (missing `fib6_lookup` refactor) and changed only `*dest = 0;` to `nft_fib_store_result(dest, priv, NULL)` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv4/netfilter/nft_fib_ipv4.c |    2 +-
+ net/ipv6/netfilter/nft_fib_ipv6.c |    2 +-
+ net/netfilter/nft_fib.c           |    6 ++++++
+ 3 files changed, 8 insertions(+), 2 deletions(-)
+
+--- a/net/ipv4/netfilter/nft_fib_ipv4.c
++++ b/net/ipv4/netfilter/nft_fib_ipv4.c
+@@ -118,7 +118,7 @@ void nft_fib4_eval(const struct nft_expr
+               fl4.saddr = get_saddr(iph->daddr);
+       }
+-      *dest = 0;
++      nft_fib_store_result(dest, priv, NULL);
+       if (fib_lookup(nft_net(pkt), &fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE))
+               return;
+--- a/net/ipv6/netfilter/nft_fib_ipv6.c
++++ b/net/ipv6/netfilter/nft_fib_ipv6.c
+@@ -189,7 +189,7 @@ void nft_fib6_eval(const struct nft_expr
+               }
+       }
+-      *dest = 0;
++      nft_fib_store_result(dest, priv, NULL);
+       rt = (void *)ip6_route_lookup(nft_net(pkt), &fl6, pkt->skb,
+                                     lookup_flags);
+       if (rt->dst.error)
+--- a/net/netfilter/nft_fib.c
++++ b/net/netfilter/nft_fib.c
+@@ -105,6 +105,12 @@ int nft_fib_init(const struct nft_ctx *c
+               return -EINVAL;
+       }
++      if (priv->flags & NFTA_FIB_F_PRESENT) {
++              if (priv->result != NFT_FIB_RESULT_OIF)
++                      return -EINVAL;
++              len = sizeof(u8);
++      }
++
+       err = nft_parse_register_store(ctx, tb[NFTA_FIB_DREG], &priv->dreg,
+                                      NULL, NFT_DATA_VALUE, len);
+       if (err < 0)
diff --git a/queue-5.15/octeontx2-af-cgx-add-bounds-check-to-cgx_speed_mbps-index.patch b/queue-5.15/octeontx2-af-cgx-add-bounds-check-to-cgx_speed_mbps-index.patch
new file mode 100644 (file)
index 0000000..e08b153
--- /dev/null
@@ -0,0 +1,52 @@
+From stable+bounces-259296-greg=kroah.com@vger.kernel.org Sun May 31 01:38:11 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 16:07:39 -0400
+Subject: octeontx2-af: CGX: add bounds check to cgx_speed_mbps index
+To: stable@vger.kernel.org
+Cc: Sam Daly <sam@samdaly.ie>, Sunil Goutham <sgoutham@marvell.com>, Linu Cherian <lcherian@marvell.com>, Geetha sowjanya <gakula@marvell.com>, hariprasad <hkelam@marvell.com>, Subbaraya Sundeep <sbhatta@marvell.com>, Andrew Lunn <andrew+netdev@lunn.ch>, stable <stable@kernel.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530200739.3283536-1-sashal@kernel.org>
+
+From: Sam Daly <sam@samdaly.ie>
+
+[ Upstream commit c0bf0a4f3f1f5f57aa83e1400ba4f56f0abfd542 ]
+
+cgx_speed_mbps has 13 elements but RESP_LINKSTAT_SPEED can yield values
+0-15. If it returns a value >= 13, this causes an out-of-bounds array
+access. Add a bounds check and default to speed 0 if the index is out of
+range.
+
+Fixes: 61071a871ea6 ("octeontx2-af: Forward CGX link notifications to PFs")
+Cc: Sunil Goutham <sgoutham@marvell.com>
+Cc: Linu Cherian <lcherian@marvell.com>
+Cc: Geetha sowjanya <gakula@marvell.com>
+Cc: hariprasad <hkelam@marvell.com>
+Cc: Subbaraya Sundeep <sbhatta@marvell.com>
+Cc: Andrew Lunn <andrew+netdev@lunn.ch>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Sam Daly <sam@samdaly.ie>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Link: https://patch.msgid.link/2026051352-refined-demise-e88d@gregkh
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/marvell/octeontx2/af/cgx.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
++++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+@@ -1096,10 +1096,13 @@ static inline void link_status_user_form
+                                          struct cgx *cgx, u8 lmac_id)
+ {
+       const char *lmac_string;
++      unsigned int speed;
+       linfo->link_up = FIELD_GET(RESP_LINKSTAT_UP, lstat);
+       linfo->full_duplex = FIELD_GET(RESP_LINKSTAT_FDUPLEX, lstat);
+-      linfo->speed = cgx_speed_mbps[FIELD_GET(RESP_LINKSTAT_SPEED, lstat)];
++      speed = FIELD_GET(RESP_LINKSTAT_SPEED, lstat);
++      linfo->speed = speed < ARRAY_SIZE(cgx_speed_mbps) ?
++                     cgx_speed_mbps[speed] : 0;
+       linfo->an = FIELD_GET(RESP_LINKSTAT_AN, lstat);
+       linfo->fec = FIELD_GET(RESP_LINKSTAT_FEC, lstat);
+       linfo->lmac_type_id = cgx_get_lmac_type(cgx, lmac_id);
diff --git a/queue-5.15/octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch b/queue-5.15/octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch
new file mode 100644 (file)
index 0000000..4a86f70
--- /dev/null
@@ -0,0 +1,62 @@
+From stable+bounces-259297-greg=kroah.com@vger.kernel.org Sun May 31 01:43:35 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 16:13:27 -0400
+Subject: octeontx2-pf: avoid double free of pool->stack on AQ init failure
+To: stable@vger.kernel.org
+Cc: Dawei Feng <dawei.feng@seu.edu.cn>, Zilin Guan <zilin@seu.edu.cn>, Simon Horman <horms@kernel.org>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530201327.3310899-1-sashal@kernel.org>
+
+From: Dawei Feng <dawei.feng@seu.edu.cn>
+
+[ Upstream commit 9b244c242bec48b37e82b89787afd6a4c43457e1 ]
+
+otx2_pool_aq_init() frees pool->stack when mailbox sync or retry
+allocation fails, but leaves the pointer unchanged. Later,
+otx2_sq_aura_pool_init() unwinds the partial setup through
+otx2_aura_pool_free(), which frees pool->stack again. The CN20K-specific
+cn20k_pool_aq_init() implementation has the same bug in
+its corresponding error path.
+
+Set pool->stack to NULL immediately after the local free so the shared
+cleanup path does not free the same stack again while cleaning up
+partially initialized pool state.
+
+The bug was first flagged by an experimental analysis tool we are
+developing for kernel memory-management bugs while analyzing
+v6.13-rc1. The tool is still under development and is not yet publicly
+available. Manual inspection confirms that the bug is still present in
+v7.1-rc3.
+
+Runtime validation was not performed because reproducing this path
+requires OcteonTX2/CN20K hardware.
+
+Fixes: caa2da34fd25 ("octeontx2-pf: Initialize and config queues")
+Fixes: d322fbd17203 ("octeontx2-pf: Initialize cn20k specific aura and pool contexts")
+Cc: stable@vger.kernel.org
+Signed-off-by: Zilin Guan <zilin@seu.edu.cn>
+Signed-off-by: Dawei Feng <dawei.feng@seu.edu.cn>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260515151826.1005397-1-dawei.feng@seu.edu.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
+@@ -1258,11 +1258,13 @@ static int otx2_pool_init(struct otx2_ni
+               err = otx2_sync_mbox_msg(&pfvf->mbox);
+               if (err) {
+                       qmem_free(pfvf->dev, pool->stack);
++                      pool->stack = NULL;
+                       return err;
+               }
+               aq = otx2_mbox_alloc_msg_npa_aq_enq(&pfvf->mbox);
+               if (!aq) {
+                       qmem_free(pfvf->dev, pool->stack);
++                      pool->stack = NULL;
+                       return -ENOMEM;
+               }
+       }
diff --git a/queue-5.15/phy-tegra-xusb-disable-trk-clk-when-not-in-use.patch b/queue-5.15/phy-tegra-xusb-disable-trk-clk-when-not-in-use.patch
new file mode 100644 (file)
index 0000000..b795867
--- /dev/null
@@ -0,0 +1,51 @@
+From sashal@kernel.org Mon Jun  1 16:32:21 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon,  1 Jun 2026 07:02:17 -0400
+Subject: phy: tegra: xusb: Disable trk clk when not in use
+To: stable@vger.kernel.org
+Cc: Wayne Chang <waynec@nvidia.com>, Jon Hunter <jonathanh@nvidia.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260601110218.439979-1-sashal@kernel.org>
+
+From: Wayne Chang <waynec@nvidia.com>
+
+[ Upstream commit 71d9e899584e11bbd7eaf9934a619c69a15060d8 ]
+
+Pad tracking is a one-time calibration for Tegra186 and Tegra194.
+Clk should be disabled after calibration.
+
+Disable clk after calibration.
+While at it add 100us delay for HW recording the calibration value.
+
+Signed-off-by: Wayne Chang <waynec@nvidia.com>
+Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
+Link: https://lore.kernel.org/r/20230111110450.24617-5-jonathanh@nvidia.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: da110228b54f ("phy: tegra: xusb: Fix per-pad high-speed termination calibration")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/phy/tegra/xusb-tegra186.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/phy/tegra/xusb-tegra186.c
++++ b/drivers/phy/tegra/xusb-tegra186.c
+@@ -612,6 +612,10 @@ static void tegra186_utmi_bias_pad_power
+       value &= ~USB2_PD_TRK;
+       padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
++      udelay(100);
++
++      clk_disable_unprepare(priv->usb2_trk_clk);
++
+       mutex_unlock(&padctl->lock);
+ }
+@@ -636,8 +640,6 @@ static void tegra186_utmi_bias_pad_power
+       value |= USB2_PD_TRK;
+       padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
+-      clk_disable_unprepare(priv->usb2_trk_clk);
+-
+       mutex_unlock(&padctl->lock);
+ }
diff --git a/queue-5.15/phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch b/queue-5.15/phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch
new file mode 100644 (file)
index 0000000..b886ca1
--- /dev/null
@@ -0,0 +1,144 @@
+From stable+bounces-259529-greg=kroah.com@vger.kernel.org Mon Jun  1 16:37:04 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon,  1 Jun 2026 07:02:18 -0400
+Subject: phy: tegra: xusb: Fix per-pad high-speed termination calibration
+To: stable@vger.kernel.org
+Cc: Wayne Chang <waynec@nvidia.com>, Wei-Cheng Chen <weichengc@nvidia.com>, Jon Hunter <jonathanh@nvidia.com>, Vinod Koul <vkoul@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260601110218.439979-2-sashal@kernel.org>
+
+From: Wayne Chang <waynec@nvidia.com>
+
+[ Upstream commit da110228b54f2e2143d97ea7151e0dc22e539d67 ]
+
+The existing code reads a single hs_term_range_adj value from bit field
+[10:7] of FUSE_SKU_CALIB_0 and applies it to all USB2 pads uniformly.
+However, on SoCs that support per-pad termination, each pad has its own
+hs_term_range_adj field: pad 0 in FUSE_SKU_CALIB_0[10:7], and pads 1-3
+in FUSE_USB_CALIB_EXT_0 at bit offsets [8:5], [12:9], and [16:13]
+respectively.
+
+Fix the calibration by reading per-pad values from the appropriate fuse
+registers. For SoCs that do not support per-pad termination, replicate
+pad 0's value to all pads to maintain existing behavior.
+
+Add a has_per_pad_term flag to the SoC data to indicate whether per-pad
+termination values are available in FUSE_USB_CALIB_EXT_0.
+
+Fixes: 1ef535c6ba8e ("phy: tegra: xusb: Add Tegra194 support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Wayne Chang <waynec@nvidia.com>
+Signed-off-by: Wei-Cheng Chen <weichengc@nvidia.com>
+Reviewed-by: Jon Hunter <jonathanh@nvidia.com>
+Tested-by: Jon Hunter <jonathanh@nvidia.com>
+Link: https://patch.msgid.link/20260504033305.2283145-1-weichengc@nvidia.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/phy/tegra/xusb-tegra186.c |   32 +++++++++++++++++++++++++-------
+ drivers/phy/tegra/xusb.h          |    1 +
+ 2 files changed, 26 insertions(+), 7 deletions(-)
+
+--- a/drivers/phy/tegra/xusb-tegra186.c
++++ b/drivers/phy/tegra/xusb-tegra186.c
+@@ -20,8 +20,8 @@
+ /* FUSE USB_CALIB registers */
+ #define HS_CURR_LEVEL_PADX_SHIFT(x)   ((x) ? (11 + (x - 1) * 6) : 0)
+ #define HS_CURR_LEVEL_PAD_MASK                0x3f
+-#define HS_TERM_RANGE_ADJ_SHIFT               7
+-#define HS_TERM_RANGE_ADJ_MASK                0xf
++#define HS_TERM_RANGE_ADJ_PADX_SHIFT(x)       ((x) ? (5 + (x - 1) * 4) : 7)
++#define HS_TERM_RANGE_ADJ_PAD_MASK    0xf
+ #define HS_SQUELCH_SHIFT              29
+ #define HS_SQUELCH_MASK                       0x7
+@@ -238,7 +238,7 @@
+ struct tegra_xusb_fuse_calibration {
+       u32 *hs_curr_level;
+       u32 hs_squelch;
+-      u32 hs_term_range_adj;
++      u32 *hs_term_range_adj;
+       u32 rpd_ctrl;
+ };
+@@ -864,7 +864,7 @@ static int tegra186_utmi_phy_power_on(st
+       value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
+       value &= ~TERM_RANGE_ADJ(~0);
+-      value |= TERM_RANGE_ADJ(priv->calib.hs_term_range_adj);
++      value |= TERM_RANGE_ADJ(priv->calib.hs_term_range_adj[index]);
+       value &= ~RPD_CTRL(~0);
+       value |= RPD_CTRL(priv->calib.rpd_ctrl);
+       padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
+@@ -1400,17 +1400,23 @@ static const char * const tegra186_usb3_
+ static int
+ tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl)
+ {
++      const struct tegra_xusb_padctl_soc *soc = padctl->base.soc;
+       struct device *dev = padctl->base.dev;
+       unsigned int i, count;
+       u32 value, *level;
++      u32 *hs_term_range_adj;
+       int err;
+-      count = padctl->base.soc->ports.usb2.count;
++      count = soc->ports.usb2.count;
+       level = devm_kcalloc(dev, count, sizeof(u32), GFP_KERNEL);
+       if (!level)
+               return -ENOMEM;
++      hs_term_range_adj = devm_kcalloc(dev, count, sizeof(u32), GFP_KERNEL);
++      if (!hs_term_range_adj)
++              return -ENOMEM;
++
+       err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
+       if (err) {
+               if (err != -EPROBE_DEFER)
+@@ -1429,8 +1435,8 @@ tegra186_xusb_read_fuse_calibration(stru
+       padctl->calib.hs_squelch = (value >> HS_SQUELCH_SHIFT) &
+                                       HS_SQUELCH_MASK;
+-      padctl->calib.hs_term_range_adj = (value >> HS_TERM_RANGE_ADJ_SHIFT) &
+-                                              HS_TERM_RANGE_ADJ_MASK;
++      hs_term_range_adj[0] = (value >> HS_TERM_RANGE_ADJ_PADX_SHIFT(0)) &
++                              HS_TERM_RANGE_ADJ_PAD_MASK;
+       err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value);
+       if (err) {
+@@ -1442,6 +1448,17 @@ tegra186_xusb_read_fuse_calibration(stru
+       padctl->calib.rpd_ctrl = (value >> RPD_CTRL_SHIFT) & RPD_CTRL_MASK;
++      for (i = 1; i < count; i++) {
++              if (soc->has_per_pad_term)
++                      hs_term_range_adj[i] =
++                              (value >> HS_TERM_RANGE_ADJ_PADX_SHIFT(i)) &
++                              HS_TERM_RANGE_ADJ_PAD_MASK;
++              else
++                      hs_term_range_adj[i] = hs_term_range_adj[0];
++      }
++
++      padctl->calib.hs_term_range_adj = hs_term_range_adj;
++
+       return 0;
+ }
+@@ -1643,6 +1660,7 @@ const struct tegra_xusb_padctl_soc tegra
+       .supply_names = tegra194_xusb_padctl_supply_names,
+       .num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names),
+       .supports_gen2 = true,
++      .has_per_pad_term = true,
+ };
+ EXPORT_SYMBOL_GPL(tegra194_xusb_padctl_soc);
+ #endif
+--- a/drivers/phy/tegra/xusb.h
++++ b/drivers/phy/tegra/xusb.h
+@@ -431,6 +431,7 @@ struct tegra_xusb_padctl_soc {
+       unsigned int num_supplies;
+       bool supports_gen2;
+       bool need_fake_usb3_port;
++      bool has_per_pad_term;
+ };
+ struct tegra_xusb_padctl {
diff --git a/queue-5.15/pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch b/queue-5.15/pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch
new file mode 100644 (file)
index 0000000..9cd22e8
--- /dev/null
@@ -0,0 +1,72 @@
+From stable+bounces-247969-greg=kroah.com@vger.kernel.org Fri May 15 21:43:49 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 May 2026 11:55:36 -0400
+Subject: pmdomain: core: Fix detach procedure for virtual devices in genpd
+To: stable@vger.kernel.org
+Cc: Ulf Hansson <ulf.hansson@linaro.org>, Geert Uytterhoeven <geert@linux-m68k.org>, Geert Uytterhoeven <geert+renesas@glider.be>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260515155536.3359591-1-sashal@kernel.org>
+
+From: Ulf Hansson <ulf.hansson@linaro.org>
+
+[ Upstream commit 26735dfdd8930d9ef1fa92e590a9bf77726efdf6 ]
+
+If a device is attached to a PM domain through genpd_dev_pm_attach_by_id(),
+genpd calls pm_runtime_enable() for the corresponding virtual device that
+it registers. While this avoids boilerplate code in drivers, there is no
+corresponding call to pm_runtime_disable() in genpd_dev_pm_detach().
+
+This means these virtual devices are typically detached from its genpd,
+while runtime PM remains enabled for them, which is not how things are
+designed to work. In worst cases it may lead to critical errors, like a
+NULL pointer dereference bug in genpd_runtime_suspend(), which was recently
+reported. For another case, we may end up keeping an unnecessary vote for a
+performance state for the device.
+
+To fix these problems, let's add this missing call to pm_runtime_disable()
+in genpd_dev_pm_detach().
+
+Reported-by: Geert Uytterhoeven <geert@linux-m68k.org>
+Closes: https://lore.kernel.org/all/CAMuHMdWapT40hV3c+CSBqFOW05aWcV1a6v_NiJYgoYi0i9_PDQ@mail.gmail.com/
+Fixes: 3c095f32a92b ("PM / Domains: Add support for multi PM domains per device to genpd")
+Cc: stable@vger.kernel.org
+Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/base/power/domain.c |   10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/drivers/base/power/domain.c
++++ b/drivers/base/power/domain.c
+@@ -2596,6 +2596,7 @@ static struct bus_type genpd_bus_type =
+ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
+ {
+       struct generic_pm_domain *pd;
++      bool is_virt_dev;
+       unsigned int i;
+       int ret = 0;
+@@ -2605,6 +2606,13 @@ static void genpd_dev_pm_detach(struct d
+       dev_dbg(dev, "removing from PM domain %s\n", pd->name);
++      /* Check if the device was created by genpd at attach. */
++      is_virt_dev = dev->bus == &genpd_bus_type;
++
++      /* Disable runtime PM if we enabled it at attach. */
++      if (is_virt_dev)
++              pm_runtime_disable(dev);
++
+       /* Drop the default performance state */
+       if (dev_gpd_data(dev)->default_pstate) {
+               dev_pm_genpd_set_performance_state(dev, 0);
+@@ -2630,7 +2638,7 @@ static void genpd_dev_pm_detach(struct d
+       genpd_queue_power_off_work(pd);
+       /* Unregister the device if it was created by genpd. */
+-      if (dev->bus == &genpd_bus_type)
++      if (is_virt_dev)
+               device_unregister(dev);
+ }
diff --git a/queue-5.15/qed-fix-double-free-in-qed_cxt_tables_alloc.patch b/queue-5.15/qed-fix-double-free-in-qed_cxt_tables_alloc.patch
new file mode 100644 (file)
index 0000000..f358d79
--- /dev/null
@@ -0,0 +1,58 @@
+From stable+bounces-256817-greg=kroah.com@vger.kernel.org Sat May 30 05:00:39 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 19:30:29 -0400
+Subject: qed: fix double free in qed_cxt_tables_alloc()
+To: stable@vger.kernel.org
+Cc: Dawei Feng <dawei.feng@seu.edu.cn>, Zilin Guan <zilin@seu.edu.cn>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529233029.1896294-2-sashal@kernel.org>
+
+From: Dawei Feng <dawei.feng@seu.edu.cn>
+
+[ Upstream commit 2bccfb8476ca5f3548afbd623dc7a6980d4e77de ]
+
+If one of the later PF or VF CID bitmap allocations fails,
+qed_cid_map_alloc() jumps to cid_map_fail and frees the previously
+allocated CID bitmaps before returning an error. qed_cxt_tables_alloc()
+then calls qed_cxt_mngr_free(), which invokes qed_cid_map_free()
+again.
+
+Fix this by setting each CID bitmap pointer to NULL after bitmap_free()
+to avoid double free.
+
+The bug was first flagged by an experimental analysis tool we are
+developing for kernel memory-management bugs while analyzing
+v6.13-rc1. The tool is still under development and is not yet publicly
+available. Manual inspection confirms that the bug is still
+present in v7.1-rc3.
+
+Runtime reproduction was not attempted because exercising the failing
+allocation path requires device-specific setup.
+
+Fixes: fe56b9e6a8d9 ("qed: Add module with basic common support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Zilin Guan <zilin@seu.edu.cn>
+Signed-off-by: Dawei Feng <dawei.feng@seu.edu.cn>
+Link: https://patch.msgid.link/20260520070323.2762379-1-dawei.feng@seu.edu.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/qlogic/qed/qed_cxt.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
++++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+@@ -1038,11 +1038,13 @@ static void qed_cid_map_free(struct qed_
+       for (type = 0; type < MAX_CONN_TYPES; type++) {
+               bitmap_free(p_mngr->acquired[type].cid_map);
++              p_mngr->acquired[type].cid_map = NULL;
+               p_mngr->acquired[type].max_count = 0;
+               p_mngr->acquired[type].start_cid = 0;
+               for (vf = 0; vf < MAX_NUM_VFS; vf++) {
+                       bitmap_free(p_mngr->acquired_vf[type][vf].cid_map);
++                      p_mngr->acquired_vf[type][vf].cid_map = NULL;
+                       p_mngr->acquired_vf[type][vf].max_count = 0;
+                       p_mngr->acquired_vf[type][vf].start_cid = 0;
+               }
diff --git a/queue-5.15/qed-use-the-bitmap-api-to-simplify-some-functions.patch b/queue-5.15/qed-use-the-bitmap-api-to-simplify-some-functions.patch
new file mode 100644 (file)
index 0000000..b497f91
--- /dev/null
@@ -0,0 +1,99 @@
+From stable+bounces-256816-greg=kroah.com@vger.kernel.org Sat May 30 05:00:37 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 19:30:28 -0400
+Subject: qed: Use the bitmap API to simplify some functions
+To: stable@vger.kernel.org
+Cc: Christophe JAILLET <christophe.jaillet@wanadoo.fr>, "David S. Miller" <davem@davemloft.net>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529233029.1896294-1-sashal@kernel.org>
+
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+
+[ Upstream commit 5e6c7ccd3ea4b25dd6b4b0363859913f315deacb ]
+
+'cid_map' is a bitmap. So use 'bitmap_zalloc()' to simplify code,
+improve the semantic and avoid some open-coded arithmetic in allocator
+arguments.
+
+Also change the corresponding 'kfree()' into 'bitmap_free()' to keep
+consistency.
+
+Also change some 'memset()' into 'bitmap_zero()' to keep consistency. This
+is also much less verbose.
+
+Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 2bccfb8476ca ("qed: fix double free in qed_cxt_tables_alloc()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/qlogic/qed/qed_cxt.c |   24 +++++-------------------
+ 1 file changed, 5 insertions(+), 19 deletions(-)
+
+--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
++++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+@@ -1037,12 +1037,12 @@ static void qed_cid_map_free(struct qed_
+       u32 type, vf;
+       for (type = 0; type < MAX_CONN_TYPES; type++) {
+-              kfree(p_mngr->acquired[type].cid_map);
++              bitmap_free(p_mngr->acquired[type].cid_map);
+               p_mngr->acquired[type].max_count = 0;
+               p_mngr->acquired[type].start_cid = 0;
+               for (vf = 0; vf < MAX_NUM_VFS; vf++) {
+-                      kfree(p_mngr->acquired_vf[type][vf].cid_map);
++                      bitmap_free(p_mngr->acquired_vf[type][vf].cid_map);
+                       p_mngr->acquired_vf[type][vf].max_count = 0;
+                       p_mngr->acquired_vf[type][vf].start_cid = 0;
+               }
+@@ -1055,15 +1055,10 @@ qed_cid_map_alloc_single(struct qed_hwfn
+                        u32 cid_start,
+                        u32 cid_count, struct qed_cid_acquired_map *p_map)
+ {
+-      u32 size;
+-
+       if (!cid_count)
+               return 0;
+-      size = DIV_ROUND_UP(cid_count,
+-                          sizeof(unsigned long) * BITS_PER_BYTE) *
+-             sizeof(unsigned long);
+-      p_map->cid_map = kzalloc(size, GFP_KERNEL);
++      p_map->cid_map = bitmap_zalloc(cid_count, GFP_KERNEL);
+       if (!p_map->cid_map)
+               return -ENOMEM;
+@@ -1217,7 +1212,6 @@ void qed_cxt_mngr_setup(struct qed_hwfn
+       struct qed_cid_acquired_map *p_map;
+       struct qed_conn_type_cfg *p_cfg;
+       int type;
+-      u32 len;
+       /* Reset acquired cids */
+       for (type = 0; type < MAX_CONN_TYPES; type++) {
+@@ -1226,11 +1220,7 @@ void qed_cxt_mngr_setup(struct qed_hwfn
+               p_cfg = &p_mngr->conn_cfg[type];
+               if (p_cfg->cid_count) {
+                       p_map = &p_mngr->acquired[type];
+-                      len = DIV_ROUND_UP(p_map->max_count,
+-                                         sizeof(unsigned long) *
+-                                         BITS_PER_BYTE) *
+-                            sizeof(unsigned long);
+-                      memset(p_map->cid_map, 0, len);
++                      bitmap_zero(p_map->cid_map, p_map->max_count);
+               }
+               if (!p_cfg->cids_per_vf)
+@@ -1238,11 +1228,7 @@ void qed_cxt_mngr_setup(struct qed_hwfn
+               for (vf = 0; vf < MAX_NUM_VFS; vf++) {
+                       p_map = &p_mngr->acquired_vf[type][vf];
+-                      len = DIV_ROUND_UP(p_map->max_count,
+-                                         sizeof(unsigned long) *
+-                                         BITS_PER_BYTE) *
+-                            sizeof(unsigned long);
+-                      memset(p_map->cid_map, 0, len);
++                      bitmap_zero(p_map->cid_map, p_map->max_count);
+               }
+       }
+ }
diff --git a/queue-5.15/rdma-move-dma-block-iterator-logic-into-dedicated-files.patch b/queue-5.15/rdma-move-dma-block-iterator-logic-into-dedicated-files.patch
new file mode 100644 (file)
index 0000000..e80f98e
--- /dev/null
@@ -0,0 +1,482 @@
+From stable+bounces-263506-greg=kroah.com@vger.kernel.org Tue Jun 16 06:38:08 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Jun 2026 21:07:37 -0400
+Subject: RDMA: Move DMA block iterator logic into dedicated files
+To: stable@vger.kernel.org
+Cc: Leon Romanovsky <leonro@nvidia.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260616010738.2640782-2-sashal@kernel.org>
+
+From: Leon Romanovsky <leonro@nvidia.com>
+
+[ Upstream commit 6094ea64c69520ed1e770e7c79c43412de202bfa ]
+
+The DMA iterator logic was mixed into verbs and umem-specific code,
+forcing all users to include rdma/ib_umem.h. Move the block iterator
+logic into iter.c and rdma/iter.h so that rdma/ib_umem.h and
+rdma/ib_verbs.h can be separated in a follow-up patch.
+
+Link: https://patch.msgid.link/20260213-refactor-umem-v1-1-f3be85847922@nvidia.com
+Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
+Stable-dep-of: 15fe76e23615 ("RDMA/umem: Fix truncation for block sizes >= 4G")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/infiniband/core/Makefile             |    2 
+ drivers/infiniband/core/iter.c               |   43 +++++++++++++
+ drivers/infiniband/core/verbs.c              |   38 -----------
+ drivers/infiniband/hw/bnxt_re/qplib_res.c    |    2 
+ drivers/infiniband/hw/cxgb4/mem.c            |    2 
+ drivers/infiniband/hw/efa/efa_verbs.c        |    2 
+ drivers/infiniband/hw/hns/hns_roce_alloc.c   |    2 
+ drivers/infiniband/hw/irdma/main.h           |    2 
+ drivers/infiniband/hw/mlx4/mr.c              |    1 
+ drivers/infiniband/hw/mlx5/mem.c             |    1 
+ drivers/infiniband/hw/mlx5/mr.c              |    1 
+ drivers/infiniband/hw/mthca/mthca_provider.c |    2 
+ drivers/infiniband/hw/ocrdma/ocrdma_verbs.c  |    2 
+ drivers/infiniband/hw/qedr/verbs.c           |    2 
+ drivers/infiniband/hw/vmw_pvrdma/pvrdma.h    |    2 
+ include/rdma/ib_umem.h                       |   32 ---------
+ include/rdma/ib_verbs.h                      |   48 --------------
+ include/rdma/iter.h                          |   88 +++++++++++++++++++++++++++
+ 18 files changed, 144 insertions(+), 128 deletions(-)
+ create mode 100644 drivers/infiniband/core/iter.c
+ create mode 100644 include/rdma/iter.h
+
+--- a/drivers/infiniband/core/Makefile
++++ b/drivers/infiniband/core/Makefile
+@@ -12,7 +12,7 @@ ib_core-y :=                 packer.o ud_header.o verb
+                               roce_gid_mgmt.o mr_pool.o addr.o sa_query.o \
+                               multicast.o mad.o smi.o agent.o mad_rmpp.o \
+                               nldev.o restrack.o counters.o ib_core_uverbs.o \
+-                              trace.o lag.o
++                              trace.o lag.o iter.o
+ ib_core-$(CONFIG_SECURITY_INFINIBAND) += security.o
+ ib_core-$(CONFIG_CGROUP_RDMA) += cgroup.o
+--- /dev/null
++++ b/drivers/infiniband/core/iter.c
+@@ -0,0 +1,43 @@
++// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
++/* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. */
++
++#include <linux/export.h>
++#include <rdma/iter.h>
++
++void __rdma_block_iter_start(struct ib_block_iter *biter,
++                           struct scatterlist *sglist, unsigned int nents,
++                           unsigned long pgsz)
++{
++      memset(biter, 0, sizeof(struct ib_block_iter));
++      biter->__sg = sglist;
++      biter->__sg_nents = nents;
++
++      /* Driver provides best block size to use */
++      biter->__pg_bit = __fls(pgsz);
++}
++EXPORT_SYMBOL(__rdma_block_iter_start);
++
++bool __rdma_block_iter_next(struct ib_block_iter *biter)
++{
++      unsigned int block_offset;
++      unsigned int delta;
++
++      if (!biter->__sg_nents || !biter->__sg)
++              return false;
++
++      biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance;
++      block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1);
++      delta = BIT_ULL(biter->__pg_bit) - block_offset;
++
++      while (biter->__sg_nents && biter->__sg &&
++             sg_dma_len(biter->__sg) - biter->__sg_advance <= delta) {
++              delta -= sg_dma_len(biter->__sg) - biter->__sg_advance;
++              biter->__sg_advance = 0;
++              biter->__sg = sg_next(biter->__sg);
++              biter->__sg_nents--;
++      }
++      biter->__sg_advance += delta;
++
++      return true;
++}
++EXPORT_SYMBOL(__rdma_block_iter_next);
+--- a/drivers/infiniband/core/verbs.c
++++ b/drivers/infiniband/core/verbs.c
+@@ -2950,41 +2950,3 @@ int rdma_init_netdev(struct ib_device *d
+                                            netdev, params.param);
+ }
+ EXPORT_SYMBOL(rdma_init_netdev);
+-
+-void __rdma_block_iter_start(struct ib_block_iter *biter,
+-                           struct scatterlist *sglist, unsigned int nents,
+-                           unsigned long pgsz)
+-{
+-      memset(biter, 0, sizeof(struct ib_block_iter));
+-      biter->__sg = sglist;
+-      biter->__sg_nents = nents;
+-
+-      /* Driver provides best block size to use */
+-      biter->__pg_bit = __fls(pgsz);
+-}
+-EXPORT_SYMBOL(__rdma_block_iter_start);
+-
+-bool __rdma_block_iter_next(struct ib_block_iter *biter)
+-{
+-      unsigned int block_offset;
+-      unsigned int delta;
+-
+-      if (!biter->__sg_nents || !biter->__sg)
+-              return false;
+-
+-      biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance;
+-      block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1);
+-      delta = BIT_ULL(biter->__pg_bit) - block_offset;
+-
+-      while (biter->__sg_nents && biter->__sg &&
+-             sg_dma_len(biter->__sg) - biter->__sg_advance <= delta) {
+-              delta -= sg_dma_len(biter->__sg) - biter->__sg_advance;
+-              biter->__sg_advance = 0;
+-              biter->__sg = sg_next(biter->__sg);
+-              biter->__sg_nents--;
+-      }
+-      biter->__sg_advance += delta;
+-
+-      return true;
+-}
+-EXPORT_SYMBOL(__rdma_block_iter_next);
+--- a/drivers/infiniband/hw/bnxt_re/qplib_res.c
++++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c
+@@ -46,7 +46,7 @@
+ #include <linux/if_vlan.h>
+ #include <linux/vmalloc.h>
+ #include <rdma/ib_verbs.h>
+-#include <rdma/ib_umem.h>
++#include <rdma/iter.h>
+ #include "roce_hsi.h"
+ #include "qplib_res.h"
+--- a/drivers/infiniband/hw/cxgb4/mem.c
++++ b/drivers/infiniband/hw/cxgb4/mem.c
+@@ -32,9 +32,9 @@
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+-#include <rdma/ib_umem.h>
+ #include <linux/atomic.h>
+ #include <rdma/ib_user_verbs.h>
++#include <rdma/iter.h>
+ #include "iw_cxgb4.h"
+--- a/drivers/infiniband/hw/efa/efa_verbs.c
++++ b/drivers/infiniband/hw/efa/efa_verbs.c
+@@ -7,9 +7,9 @@
+ #include <linux/log2.h>
+ #include <rdma/ib_addr.h>
+-#include <rdma/ib_umem.h>
+ #include <rdma/ib_user_verbs.h>
+ #include <rdma/ib_verbs.h>
++#include <rdma/iter.h>
+ #include <rdma/uverbs_ioctl.h>
+ #include "efa.h"
+--- a/drivers/infiniband/hw/hns/hns_roce_alloc.c
++++ b/drivers/infiniband/hw/hns/hns_roce_alloc.c
+@@ -34,7 +34,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/vmalloc.h>
+ #include "hns_roce_device.h"
+-#include <rdma/ib_umem.h>
++#include <rdma/iter.h>
+ void hns_roce_buf_free(struct hns_roce_dev *hr_dev, struct hns_roce_buf *buf)
+ {
+--- a/drivers/infiniband/hw/irdma/main.h
++++ b/drivers/infiniband/hw/irdma/main.h
+@@ -37,8 +37,8 @@
+ #include <rdma/rdma_cm.h>
+ #include <rdma/iw_cm.h>
+ #include <rdma/ib_user_verbs.h>
+-#include <rdma/ib_umem.h>
+ #include <rdma/ib_cache.h>
++#include <rdma/iter.h>
+ #include <rdma/uverbs_ioctl.h>
+ #include "status.h"
+ #include "osdep.h"
+--- a/drivers/infiniband/hw/mlx4/mr.c
++++ b/drivers/infiniband/hw/mlx4/mr.c
+@@ -33,6 +33,7 @@
+ #include <linux/slab.h>
+ #include <rdma/ib_user_verbs.h>
++#include <rdma/iter.h>
+ #include "mlx4_ib.h"
+--- a/drivers/infiniband/hw/mlx5/mem.c
++++ b/drivers/infiniband/hw/mlx5/mem.c
+@@ -33,6 +33,7 @@
+ #include <linux/module.h>
+ #include <rdma/ib_umem.h>
+ #include <rdma/ib_umem_odp.h>
++#include <rdma/iter.h>
+ #include "mlx5_ib.h"
+ #include <linux/jiffies.h>
+--- a/drivers/infiniband/hw/mlx5/mr.c
++++ b/drivers/infiniband/hw/mlx5/mr.c
+@@ -42,6 +42,7 @@
+ #include <rdma/ib_umem.h>
+ #include <rdma/ib_umem_odp.h>
+ #include <rdma/ib_verbs.h>
++#include <rdma/iter.h>
+ #include "dm.h"
+ #include "mlx5_ib.h"
+--- a/drivers/infiniband/hw/mthca/mthca_provider.c
++++ b/drivers/infiniband/hw/mthca/mthca_provider.c
+@@ -35,8 +35,8 @@
+  */
+ #include <rdma/ib_smi.h>
+-#include <rdma/ib_umem.h>
+ #include <rdma/ib_user_verbs.h>
++#include <rdma/iter.h>
+ #include <rdma/uverbs_ioctl.h>
+ #include <linux/sched.h>
+--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
++++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+@@ -44,9 +44,9 @@
+ #include <rdma/ib_verbs.h>
+ #include <rdma/ib_user_verbs.h>
+ #include <rdma/iw_cm.h>
+-#include <rdma/ib_umem.h>
+ #include <rdma/ib_addr.h>
+ #include <rdma/ib_cache.h>
++#include <rdma/iter.h>
+ #include <rdma/uverbs_ioctl.h>
+ #include "ocrdma.h"
+--- a/drivers/infiniband/hw/qedr/verbs.c
++++ b/drivers/infiniband/hw/qedr/verbs.c
+@@ -39,9 +39,9 @@
+ #include <rdma/ib_verbs.h>
+ #include <rdma/ib_user_verbs.h>
+ #include <rdma/iw_cm.h>
+-#include <rdma/ib_umem.h>
+ #include <rdma/ib_addr.h>
+ #include <rdma/ib_cache.h>
++#include <rdma/iter.h>
+ #include <rdma/uverbs_ioctl.h>
+ #include <linux/qed/common_hsi.h>
+--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h
++++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h
+@@ -53,8 +53,8 @@
+ #include <linux/pci.h>
+ #include <linux/semaphore.h>
+ #include <linux/workqueue.h>
+-#include <rdma/ib_umem.h>
+ #include <rdma/ib_verbs.h>
++#include <rdma/iter.h>
+ #include <rdma/vmw_pvrdma-abi.h>
+ #include "pvrdma_ring.h"
+--- a/include/rdma/ib_umem.h
++++ b/include/rdma/ib_umem.h
+@@ -70,38 +70,6 @@ static inline size_t ib_umem_num_pages(s
+ {
+       return ib_umem_num_dma_blocks(umem, PAGE_SIZE);
+ }
+-
+-static inline void __rdma_umem_block_iter_start(struct ib_block_iter *biter,
+-                                              struct ib_umem *umem,
+-                                              unsigned long pgsz)
+-{
+-      __rdma_block_iter_start(biter, umem->sgt_append.sgt.sgl,
+-                              umem->sgt_append.sgt.nents, pgsz);
+-      biter->__sg_advance = ib_umem_offset(umem) & ~(pgsz - 1);
+-      biter->__sg_numblocks = ib_umem_num_dma_blocks(umem, pgsz);
+-}
+-
+-static inline bool __rdma_umem_block_iter_next(struct ib_block_iter *biter)
+-{
+-      return __rdma_block_iter_next(biter) && biter->__sg_numblocks--;
+-}
+-
+-/**
+- * rdma_umem_for_each_dma_block - iterate over contiguous DMA blocks of the umem
+- * @umem: umem to iterate over
+- * @biter: block iterator variable
+- * @pgsz: Page size to split the list into
+- *
+- * pgsz must be <= PAGE_SIZE or computed by ib_umem_find_best_pgsz(). The
+- * returned DMA blocks will be aligned to pgsz and span the range:
+- * ALIGN_DOWN(umem->address, pgsz) to ALIGN(umem->address + umem->length, pgsz)
+- *
+- * Performs exactly ib_umem_num_dma_blocks() iterations.
+- */
+-#define rdma_umem_for_each_dma_block(umem, biter, pgsz)                        \
+-      for (__rdma_umem_block_iter_start(biter, umem, pgsz);                  \
+-           __rdma_umem_block_iter_next(biter);)
+-
+ #ifdef CONFIG_INFINIBAND_USER_MEM
+ struct ib_umem *ib_umem_get(struct ib_device *device, unsigned long addr,
+--- a/include/rdma/ib_verbs.h
++++ b/include/rdma/ib_verbs.h
+@@ -2808,22 +2808,6 @@ struct ib_client {
+       u8 no_kverbs_req:1;
+ };
+-/*
+- * IB block DMA iterator
+- *
+- * Iterates the DMA-mapped SGL in contiguous memory blocks aligned
+- * to a HW supported page size.
+- */
+-struct ib_block_iter {
+-      /* internal states */
+-      struct scatterlist *__sg;       /* sg holding the current aligned block */
+-      dma_addr_t __dma_addr;          /* unaligned DMA address of this block */
+-      size_t __sg_numblocks;          /* ib_umem_num_dma_blocks() */
+-      unsigned int __sg_nents;        /* number of SG entries */
+-      unsigned int __sg_advance;      /* number of bytes to advance in sg in next step */
+-      unsigned int __pg_bit;          /* alignment of current block */
+-};
+-
+ struct ib_device *_ib_alloc_device(size_t size);
+ #define ib_alloc_device(drv_struct, member)                                    \
+       container_of(_ib_alloc_device(sizeof(struct drv_struct) +              \
+@@ -2845,38 +2829,6 @@ void ib_unregister_device_queued(struct
+ int ib_register_client   (struct ib_client *client);
+ void ib_unregister_client(struct ib_client *client);
+-void __rdma_block_iter_start(struct ib_block_iter *biter,
+-                           struct scatterlist *sglist,
+-                           unsigned int nents,
+-                           unsigned long pgsz);
+-bool __rdma_block_iter_next(struct ib_block_iter *biter);
+-
+-/**
+- * rdma_block_iter_dma_address - get the aligned dma address of the current
+- * block held by the block iterator.
+- * @biter: block iterator holding the memory block
+- */
+-static inline dma_addr_t
+-rdma_block_iter_dma_address(struct ib_block_iter *biter)
+-{
+-      return biter->__dma_addr & ~(BIT_ULL(biter->__pg_bit) - 1);
+-}
+-
+-/**
+- * rdma_for_each_block - iterate over contiguous memory blocks of the sg list
+- * @sglist: sglist to iterate over
+- * @biter: block iterator holding the memory block
+- * @nents: maximum number of sg entries to iterate over
+- * @pgsz: best HW supported page size to use
+- *
+- * Callers may use rdma_block_iter_dma_address() to get each
+- * blocks aligned DMA address.
+- */
+-#define rdma_for_each_block(sglist, biter, nents, pgsz)               \
+-      for (__rdma_block_iter_start(biter, sglist, nents,      \
+-                                   pgsz);                     \
+-           __rdma_block_iter_next(biter);)
+-
+ /**
+  * ib_get_client_data - Get IB client context
+  * @device:Device to get context for
+--- /dev/null
++++ b/include/rdma/iter.h
+@@ -0,0 +1,88 @@
++/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
++/* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. */
++
++#ifndef _RDMA_ITER_H_
++#define _RDMA_ITER_H_
++
++#include <linux/scatterlist.h>
++#include <rdma/ib_umem.h>
++
++/**
++ * IB block DMA iterator
++ *
++ * Iterates the DMA-mapped SGL in contiguous memory blocks aligned
++ * to a HW supported page size.
++ */
++struct ib_block_iter {
++      /* internal states */
++      struct scatterlist *__sg;       /* sg holding the current aligned block */
++      dma_addr_t __dma_addr;          /* unaligned DMA address of this block */
++      size_t __sg_numblocks;          /* ib_umem_num_dma_blocks() */
++      unsigned int __sg_nents;        /* number of SG entries */
++      unsigned int __sg_advance;      /* number of bytes to advance in sg in next step */
++      unsigned int __pg_bit;          /* alignment of current block */
++};
++
++void __rdma_block_iter_start(struct ib_block_iter *biter,
++                           struct scatterlist *sglist,
++                           unsigned int nents,
++                           unsigned long pgsz);
++bool __rdma_block_iter_next(struct ib_block_iter *biter);
++
++/**
++ * rdma_block_iter_dma_address - get the aligned dma address of the current
++ * block held by the block iterator.
++ * @biter: block iterator holding the memory block
++ */
++static inline dma_addr_t
++rdma_block_iter_dma_address(struct ib_block_iter *biter)
++{
++      return biter->__dma_addr & ~(BIT_ULL(biter->__pg_bit) - 1);
++}
++
++/**
++ * rdma_for_each_block - iterate over contiguous memory blocks of the sg list
++ * @sglist: sglist to iterate over
++ * @biter: block iterator holding the memory block
++ * @nents: maximum number of sg entries to iterate over
++ * @pgsz: best HW supported page size to use
++ *
++ * Callers may use rdma_block_iter_dma_address() to get each
++ * blocks aligned DMA address.
++ */
++#define rdma_for_each_block(sglist, biter, nents, pgsz)               \
++      for (__rdma_block_iter_start(biter, sglist, nents,      \
++                                   pgsz);                     \
++           __rdma_block_iter_next(biter);)
++
++static inline void __rdma_umem_block_iter_start(struct ib_block_iter *biter,
++                                              struct ib_umem *umem,
++                                              unsigned long pgsz)
++{
++      __rdma_block_iter_start(biter, umem->sgt_append.sgt.sgl,
++                              umem->sgt_append.sgt.nents, pgsz);
++      biter->__sg_advance = ib_umem_offset(umem) & ~(pgsz - 1);
++      biter->__sg_numblocks = ib_umem_num_dma_blocks(umem, pgsz);
++}
++
++static inline bool __rdma_umem_block_iter_next(struct ib_block_iter *biter)
++{
++      return __rdma_block_iter_next(biter) && biter->__sg_numblocks--;
++}
++
++/**
++ * rdma_umem_for_each_dma_block - iterate over contiguous DMA blocks of the umem
++ * @umem: umem to iterate over
++ * @pgsz: Page size to split the list into
++ *
++ * pgsz must be <= PAGE_SIZE or computed by ib_umem_find_best_pgsz(). The
++ * returned DMA blocks will be aligned to pgsz and span the range:
++ * ALIGN_DOWN(umem->address, pgsz) to ALIGN(umem->address + umem->length, pgsz)
++ *
++ * Performs exactly ib_umem_num_dma_blocks() iterations.
++ */
++#define rdma_umem_for_each_dma_block(umem, biter, pgsz)                        \
++      for (__rdma_umem_block_iter_start(biter, umem, pgsz);                  \
++           __rdma_umem_block_iter_next(biter);)
++
++#endif /* _RDMA_ITER_H_ */
diff --git a/queue-5.15/rdma-umem-fix-kernel-doc-warnings.patch b/queue-5.15/rdma-umem-fix-kernel-doc-warnings.patch
new file mode 100644 (file)
index 0000000..5b3cd65
--- /dev/null
@@ -0,0 +1,60 @@
+From stable+bounces-263504-greg=kroah.com@vger.kernel.org Tue Jun 16 06:37:44 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Jun 2026 21:07:36 -0400
+Subject: RDMA/umem: fix kernel-doc warnings
+To: stable@vger.kernel.org
+Cc: Randy Dunlap <rdunlap@infradead.org>, Leon Romanovsky <leon@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260616010738.2640782-1-sashal@kernel.org>
+
+From: Randy Dunlap <rdunlap@infradead.org>
+
+[ Upstream commit ff46d1392750444fab5ae5a0194764ffdc4ac0d2 ]
+
+Add or correct kernel-doc comments to eliminate warnings:
+
+Warning: include/rdma/ib_umem.h:104 function parameter 'biter' not
+ described in 'rdma_umem_for_each_dma_block'
+Warning: include/rdma/ib_umem.h:140 function parameter 'pgsz_bitmap' not
+ described in 'ib_umem_find_best_pgoff'
+Warning: include/rdma/ib_umem.h:141 No description found for return
+ value of 'ib_umem_find_best_pgoff'
+
+Signed-off-by: Randy Dunlap <rdunlap@infradead.org>
+Link: https://patch.msgid.link/20260224003120.3173892-1-rdunlap@infradead.org
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Stable-dep-of: 15fe76e23615 ("RDMA/umem: Fix truncation for block sizes >= 4G")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/rdma/ib_umem.h |    6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/include/rdma/ib_umem.h
++++ b/include/rdma/ib_umem.h
+@@ -89,6 +89,7 @@ static inline bool __rdma_umem_block_ite
+ /**
+  * rdma_umem_for_each_dma_block - iterate over contiguous DMA blocks of the umem
+  * @umem: umem to iterate over
++ * @biter: block iterator variable
+  * @pgsz: Page size to split the list into
+  *
+  * pgsz must be <= PAGE_SIZE or computed by ib_umem_find_best_pgsz(). The
+@@ -116,7 +117,7 @@ unsigned long ib_umem_find_best_pgsz(str
+  * ib_umem_find_best_pgoff - Find best HW page size
+  *
+  * @umem: umem struct
+- * @pgsz_bitmap bitmap of HW supported page sizes
++ * @pgsz_bitmap: bitmap of HW supported page sizes
+  * @pgoff_bitmask: Mask of bits that can be represented with an offset
+  *
+  * This is very similar to ib_umem_find_best_pgsz() except instead of accepting
+@@ -129,6 +130,9 @@ unsigned long ib_umem_find_best_pgsz(str
+  *
+  * If the pgoff_bitmask requires either alignment in the low bit or an
+  * unavailable page size for the high bits, this function returns 0.
++ *
++ * Returns: best HW page size for the parameters or 0 if none available
++ *   for the given parameters.
+  */
+ static inline unsigned long ib_umem_find_best_pgoff(struct ib_umem *umem,
+                                                   unsigned long pgsz_bitmap,
diff --git a/queue-5.15/rdma-umem-fix-truncation-for-block-sizes-4g.patch b/queue-5.15/rdma-umem-fix-truncation-for-block-sizes-4g.patch
new file mode 100644 (file)
index 0000000..5743240
--- /dev/null
@@ -0,0 +1,44 @@
+From stable+bounces-263505-greg=kroah.com@vger.kernel.org Tue Jun 16 06:37:44 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Jun 2026 21:07:38 -0400
+Subject: RDMA/umem: Fix truncation for block sizes >= 4G
+To: stable@vger.kernel.org
+Cc: Jason Gunthorpe <jgg@nvidia.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260616010738.2640782-3-sashal@kernel.org>
+
+From: Jason Gunthorpe <jgg@nvidia.com>
+
+[ Upstream commit 15fe76e23615f502d051ef0768f86babaf08746c ]
+
+When the iommu is used the linearization of the mapping can give a single
+block that is very large split across multiple SG entries.
+
+When __rdma_block_iter_next() reassembles the split SG entries it is
+overflowing the 32 bit stack values and computed the wrong DMA addresses
+for blocks after the truncation.
+
+Use the right types to hold DMA addresses.
+
+Link: https://patch.msgid.link/r/1-v1-88303e9e509f+f7-ib_umem_types_jgg@nvidia.com
+Cc: stable@vger.kernel.org
+Fixes: a808273a495c ("RDMA/verbs: Add a DMA iterator to return aligned contiguous memory blocks")
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/infiniband/core/iter.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/infiniband/core/iter.c
++++ b/drivers/infiniband/core/iter.c
+@@ -19,8 +19,8 @@ EXPORT_SYMBOL(__rdma_block_iter_start);
+ bool __rdma_block_iter_next(struct ib_block_iter *biter)
+ {
+-      unsigned int block_offset;
+-      unsigned int delta;
++      dma_addr_t block_offset;
++      dma_addr_t delta;
+       if (!biter->__sg_nents || !biter->__sg)
+               return false;
diff --git a/queue-5.15/rxrpc-fix-conn-level-packet-handling-to-unshare-response-packets.patch b/queue-5.15/rxrpc-fix-conn-level-packet-handling-to-unshare-response-packets.patch
deleted file mode 100644 (file)
index 70d91f1..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-From stable+bounces-242815-greg=kroah.com@vger.kernel.org Mon May  4 00:44:24 2026
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun,  3 May 2026 15:14:16 -0400
-Subject: rxrpc: Fix conn-level packet handling to unshare RESPONSE packets
-To: stable@vger.kernel.org
-Cc: David Howells <dhowells@redhat.com>, Marc Dionne <marc.dionne@auristor.com>, Jeffrey Altman <jaltman@auristor.com>, Simon Horman <horms@kernel.org>, linux-afs@lists.infradead.org, stable@kernel.org, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
-Message-ID: <20260503191416.1286222-1-sashal@kernel.org>
-
-From: David Howells <dhowells@redhat.com>
-
-[ Upstream commit 24481a7f573305706054c59e275371f8d0fe919f ]
-
-The security operations that verify the RESPONSE packets decrypt bits of it
-in place - however, the sk_buff may be shared with a packet sniffer, which
-would lead to the sniffer seeing an apparently corrupt packet (actually
-decrypted).
-
-Fix this by handing a copy of the packet off to the specific security
-handler if the packet was cloned.
-
-Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both")
-Closes: https://sashiko.dev/#/patchset/20260408121252.2249051-1-dhowells%40redhat.com
-Signed-off-by: David Howells <dhowells@redhat.com>
-cc: Marc Dionne <marc.dionne@auristor.com>
-cc: Jeffrey Altman <jaltman@auristor.com>
-cc: Simon Horman <horms@kernel.org>
-cc: linux-afs@lists.infradead.org
-cc: stable@kernel.org
-Link: https://patch.msgid.link/20260422161438.2593376-5-dhowells@redhat.com
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-[ adapted callback signature to include `_abort_code` ]
-Signed-off-by: Sasha Levin <sashal@kernel.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- net/rxrpc/conn_event.c | 30 +++++++++++++++++++++++++++++-
- 1 file changed, 29 insertions(+), 1 deletion(-)
-
-diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c
-index 5d91ef562ff78..09438850f9a5a 100644
---- a/net/rxrpc/conn_event.c
-+++ b/net/rxrpc/conn_event.c
-@@ -285,6 +285,34 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call)
-       }
- }
-+static int rxrpc_verify_response(struct rxrpc_connection *conn,
-+                               struct sk_buff *skb,
-+                               u32 *_abort_code)
-+{
-+      int ret;
-+
-+      if (skb_cloned(skb)) {
-+              /* Copy the packet if shared so that we can do in-place
-+               * decryption.
-+               */
-+              struct sk_buff *nskb = skb_copy(skb, GFP_NOFS);
-+
-+              if (nskb) {
-+                      rxrpc_new_skb(nskb, rxrpc_skb_unshared);
-+                      ret = conn->security->verify_response(conn, nskb, _abort_code);
-+                      rxrpc_free_skb(nskb, rxrpc_skb_freed);
-+              } else {
-+                      /* OOM - Drop the packet. */
-+                      rxrpc_see_skb(skb, rxrpc_skb_unshared_nomem);
-+                      ret = -ENOMEM;
-+              }
-+      } else {
-+              ret = conn->security->verify_response(conn, skb, _abort_code);
-+      }
-+
-+      return ret;
-+}
-+
- /*
-  * connection-level Rx packet processor
-  */
-@@ -337,7 +365,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
-                                                           _abort_code);
-       case RXRPC_PACKET_TYPE_RESPONSE:
--              ret = conn->security->verify_response(conn, skb, _abort_code);
-+              ret = rxrpc_verify_response(conn, skb, _abort_code);
-               if (ret < 0)
-                       return ret;
--- 
-2.53.0
-
diff --git a/queue-5.15/scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch b/queue-5.15/scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch
new file mode 100644 (file)
index 0000000..df30b3c
--- /dev/null
@@ -0,0 +1,203 @@
+From stable+bounces-260823-greg=kroah.com@vger.kernel.org Sat Jun  6 02:05:22 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 16:34:05 -0400
+Subject: scsi: target: iscsi: Bound iscsi_encode_text_output() appends to rsp_buf
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, John Garry <john.g.garry@oracle.com>, "Martin K. Petersen" <martin.petersen@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260605203405.2224281-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit bf33e01f88388c43e285492a63e539df6ffed64c ]
+
+iscsi_encode_text_output() concatenates "key=value\0" records into
+login->rsp_buf, an 8192-byte kzalloc(MAX_KEY_VALUE_PAIRS) buffer
+allocated in iscsit_alloc_login_setup_buffer(). The three sprintf() call
+sites in this function (lines 1398, 1411, 1424 in v7.1-rc2) never check
+the remaining buffer capacity:
+
+       *length += sprintf(output_buf, "%s=%s", er->key, er->value);
+       *length += 1;
+       output_buf = textbuf + *length;
+
+The 8192-byte ceiling at iscsi_target_check_login_request() bounds the
+*input* Login PDU payload, but a single PDU can carry up to 2048 minimal
+four-byte "a=b\0" pairs, each unknown key expanding to a 16-byte
+"a=NotUnderstood\0" output record via iscsi_add_notunderstood_response().
+2048 * 16 = 32 KiB of output into an 8 KiB buffer, producing a ~24 KiB
+heap overrun in the kmalloc-8k slab.
+
+The fix introduces a static iscsi_encode_text_record() helper that uses
+snprintf() with a per-call bounds check against the remaining buffer,
+and threads a u32 textbuf_size parameter through
+iscsi_encode_text_output(). Both call sites in
+iscsi_target_handle_csg_zero() (PHASE_SECURITY) and
+iscsi_target_handle_csg_one() (PHASE_OPERATIONAL) pass
+MAX_KEY_VALUE_PAIRS. On overflow the encoder logs the condition, calls
+iscsi_release_extra_responses() to drop queued records, and returns -1;
+both caller sites now emit ISCSI_STATUS_CLS_INITIATOR_ERR /
+ISCSI_LOGIN_STATUS_INIT_ERR via iscsit_tx_login_rsp() before returning,
+so the initiator sees an explicit failed-login response rather than a
+silent connection drop. (Prior to this patch only the PHASE_OPERATIONAL
+caller did that; the PHASE_SECURITY caller is converted to the same
+shape.)
+
+Fixes: e48354ce078c ("iscsi-target: Add iSCSI fabric support for target v4.1")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Tested-by: John Garry <john.g.garry@oracle.com>
+Reviewed-by: John Garry <john.g.garry@oracle.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/target/iscsi/iscsi_target_nego.c       |    7 ++
+ drivers/target/iscsi/iscsi_target_parameters.c |   62 +++++++++++++++++++------
+ drivers/target/iscsi/iscsi_target_parameters.h |    2 
+ 3 files changed, 55 insertions(+), 16 deletions(-)
+
+--- a/drivers/target/iscsi/iscsi_target_nego.c
++++ b/drivers/target/iscsi/iscsi_target_nego.c
+@@ -870,10 +870,14 @@ static int iscsi_target_handle_csg_zero(
+                       SENDER_TARGET,
+                       login->rsp_buf,
+                       &login->rsp_length,
++                      MAX_KEY_VALUE_PAIRS,
+                       conn->param_list,
+                       conn->tpg->tpg_attrib.login_keys_workaround);
+-      if (ret < 0)
++      if (ret < 0) {
++              iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
++                              ISCSI_LOGIN_STATUS_INIT_ERR);
+               return -1;
++      }
+       if (!iscsi_check_negotiated_keys(conn->param_list)) {
+               if (conn->tpg->tpg_attrib.authentication &&
+@@ -941,6 +945,7 @@ static int iscsi_target_handle_csg_one(s
+                       SENDER_TARGET,
+                       login->rsp_buf,
+                       &login->rsp_length,
++                      MAX_KEY_VALUE_PAIRS,
+                       conn->param_list,
+                       conn->tpg->tpg_attrib.login_keys_workaround);
+       if (ret < 0) {
+--- a/drivers/target/iscsi/iscsi_target_parameters.c
++++ b/drivers/target/iscsi/iscsi_target_parameters.c
+@@ -1419,19 +1419,42 @@ free_buffer:
+       return -1;
+ }
++/*
++ * Append "key=value" plus a trailing NUL into @textbuf at *@length.
++ * Returns 0 on success and advances *@length, or -EMSGSIZE if the
++ * record (including the NUL) would not fit in the remaining buffer.
++ */
++static int iscsi_encode_text_record(char *textbuf, u32 *length,
++                                  u32 textbuf_size,
++                                  const char *key, const char *value)
++{
++      int n;
++      u32 avail;
++
++      if (*length >= textbuf_size)
++              return -EMSGSIZE;
++
++      avail = textbuf_size - *length;
++      n = snprintf(textbuf + *length, avail, "%s=%s", key, value);
++      if (n < 0 || (u32)n + 1 > avail)
++              return -EMSGSIZE;
++
++      *length += n + 1;
++      return 0;
++}
++
+ int iscsi_encode_text_output(
+       u8 phase,
+       u8 sender,
+       char *textbuf,
+       u32 *length,
++      u32 textbuf_size,
+       struct iscsi_param_list *param_list,
+       bool keys_workaround)
+ {
+-      char *output_buf = NULL;
+       struct iscsi_extra_response *er;
+       struct iscsi_param *param;
+-
+-      output_buf = textbuf + *length;
++      int ret;
+       if (iscsi_enforce_integrity_rules(phase, param_list) < 0)
+               return -1;
+@@ -1443,10 +1466,12 @@ int iscsi_encode_text_output(
+                   !IS_PSTATE_RESPONSE_SENT(param) &&
+                   !IS_PSTATE_REPLY_OPTIONAL(param) &&
+                   (param->phase & phase)) {
+-                      *length += sprintf(output_buf, "%s=%s",
+-                              param->name, param->value);
+-                      *length += 1;
+-                      output_buf = textbuf + *length;
++                      ret = iscsi_encode_text_record(textbuf, length,
++                                                     textbuf_size,
++                                                     param->name,
++                                                     param->value);
++                      if (ret < 0)
++                              goto err_overflow;
+                       SET_PSTATE_RESPONSE_SENT(param);
+                       pr_debug("Sending key: %s=%s\n",
+                               param->name, param->value);
+@@ -1456,10 +1481,12 @@ int iscsi_encode_text_output(
+                   !IS_PSTATE_ACCEPTOR(param) &&
+                   !IS_PSTATE_PROPOSER(param) &&
+                   (param->phase & phase)) {
+-                      *length += sprintf(output_buf, "%s=%s",
+-                              param->name, param->value);
+-                      *length += 1;
+-                      output_buf = textbuf + *length;
++                      ret = iscsi_encode_text_record(textbuf, length,
++                                                     textbuf_size,
++                                                     param->name,
++                                                     param->value);
++                      if (ret < 0)
++                              goto err_overflow;
+                       SET_PSTATE_PROPOSER(param);
+                       iscsi_check_proposer_for_optional_reply(param,
+                                                               keys_workaround);
+@@ -1469,14 +1496,21 @@ int iscsi_encode_text_output(
+       }
+       list_for_each_entry(er, &param_list->extra_response_list, er_list) {
+-              *length += sprintf(output_buf, "%s=%s", er->key, er->value);
+-              *length += 1;
+-              output_buf = textbuf + *length;
++              ret = iscsi_encode_text_record(textbuf, length, textbuf_size,
++                                             er->key, er->value);
++              if (ret < 0)
++                      goto err_overflow;
+               pr_debug("Sending key: %s=%s\n", er->key, er->value);
+       }
+       iscsi_release_extra_responses(param_list);
+       return 0;
++
++err_overflow:
++      pr_err("iSCSI login response buffer (%u bytes) exhausted, dropping login.\n",
++             textbuf_size);
++      iscsi_release_extra_responses(param_list);
++      return -1;
+ }
+ int iscsi_check_negotiated_keys(struct iscsi_param_list *param_list)
+--- a/drivers/target/iscsi/iscsi_target_parameters.h
++++ b/drivers/target/iscsi/iscsi_target_parameters.h
+@@ -46,7 +46,7 @@ extern struct iscsi_param *iscsi_find_pa
+ extern int iscsi_extract_key_value(char *, char **, char **);
+ extern int iscsi_update_param_value(struct iscsi_param *, char *);
+ extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsi_conn *);
+-extern int iscsi_encode_text_output(u8, u8, char *, u32 *,
++extern int iscsi_encode_text_output(u8, u8, char *, u32 *, u32,
+                       struct iscsi_param_list *, bool);
+ extern int iscsi_check_negotiated_keys(struct iscsi_param_list *);
+ extern void iscsi_set_connection_parameters(struct iscsi_conn_ops *,
diff --git a/queue-5.15/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch b/queue-5.15/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch
new file mode 100644 (file)
index 0000000..5c1b57c
--- /dev/null
@@ -0,0 +1,124 @@
+From stable+bounces-260879-greg=kroah.com@vger.kernel.org Sat Jun  6 18:19:36 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  6 Jun 2026 08:49:28 -0400
+Subject: scsi: target: iscsi: Fix CRC overread and double-free in iscsit_handle_text_cmd()
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, John Garry <john.g.garry@oracle.com>, "Martin K. Petersen" <martin.petersen@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606124928.2878279-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit 778c2ab142c625a8a8afa570e0f9b7873f445d99 ]
+
+Two latent bugs in the Text-phase handler, both present since the
+original LIO integration in commit e48354ce078c ("iscsi-target: Add
+iSCSI fabric support for target v4.1"):
+
+1) DataDigest CRC buffer overread (4 bytes past text_in).
+
+   text_in is kzalloc()'d at ALIGN(payload_length, 4).  rx_size is then
+   incremented by ISCSI_CRC_LEN to make room for the received DataDigest
+   in the iovec, but the same (now-bumped) rx_size is passed as the
+   buffer length to iscsit_crc_buf():
+
+       if (conn->conn_ops->DataDigest) {
+               ...
+               rx_size += ISCSI_CRC_LEN;
+       }
+       ...
+       if (conn->conn_ops->DataDigest) {
+               data_crc = iscsit_crc_buf(text_in, rx_size, 0, NULL);
+
+   iscsit_crc_buf() walks rx_size bytes of text_in with crc32c(), so
+   when DataDigest is negotiated it reads 4 bytes past the end of the
+   text_in allocation.  KASAN reproduces this directly on the unpatched
+   mainline tree as slab-out-of-bounds in crc32c() called from the Text
+   PDU path.  The OOB bytes feed crc32c() and are then compared against
+   the initiator-supplied checksum, so the value does not flow back to
+   the attacker, but the kernel does read past the buffer on every Text
+   PDU with DataDigest=CRC32C.
+
+   Fix by passing the actual padded payload length
+   (ALIGN(payload_length, 4)) that was used for the kzalloc().
+
+2) Stale cmd->text_in_ptr re-free (double-free) on ERL>0 bad DataDigest
+   drop.
+
+   On DataDigest mismatch with ErrorRecoveryLevel > 0 the handler
+   silently drops the PDU and lets the initiator plug the CmdSN gap:
+
+               kfree(text_in);
+               return 0;
+
+   cmd->text_in_ptr still points at the freed buffer.  The next Text
+   Request on the same ITT re-enters iscsit_setup_text_cmd(), which
+   unconditionally does
+
+       kfree(cmd->text_in_ptr);
+       cmd->text_in_ptr = NULL;
+
+   freeing the same pointer a second time.  Session teardown via
+   iscsit_release_cmd() has the same shape and hits the same double-free
+   if the connection is dropped before a second Text Request arrives.
+
+   On an unmodified mainline tree the bug-1 CRC overread fires first on
+   the initial valid Text Request and perturbs the subsequent state, so
+   #4 was isolated by building a kernel with only the bug-1 hunk of this
+   patch applied plus temporary printk() observability around the three
+   relevant kfree() sites.  The observability prints are not part of
+   this patch.  On that build, a three-PDU Text Request sequence after
+   login produces two back-to-back splats:
+
+       BUG: KASAN: double-free in iscsit_setup_text_cmd+0x??
+       BUG: KASAN: double-free in iscsit_release_cmd+0x??
+
+   showing the same pointer freed in the ERL>0 drop path and again in
+   iscsit_setup_text_cmd() (next Text Request on the same ITT) and once
+   more in iscsit_release_cmd() (session teardown).  On distro kernels
+   with CONFIG_SLAB_FREELIST_HARDENED=y (default) the double-free
+   becomes a remote kernel BUG(); on non-hardened kernels it corrupts
+   the slab freelist.
+
+   Fix by clearing cmd->text_in_ptr after the kfree() in the ERL>0 drop
+   path.  With both hunks applied #4 is directly observable on the stock
+   tree without observability printks; fixing bug-1 alone would mask #4
+   less, not more, so the hunks are submitted together.
+
+Both fixes are one-liners.  The Text PDU state machine is unchanged and
+the wire protocol is unaffected.
+
+Fixes: e48354ce078c ("iscsi-target: Add iSCSI fabric support for target v4.1")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Tested-by: John Garry <john.g.garry@oracle.com>
+Reviewed-by: John Garry <john.g.garry@oracle.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/target/iscsi/iscsi_target.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/target/iscsi/iscsi_target.c
++++ b/drivers/target/iscsi/iscsi_target.c
+@@ -2296,8 +2296,9 @@ iscsit_handle_text_cmd(struct iscsi_conn
+               if (conn->conn_ops->DataDigest) {
+                       iscsit_do_crypto_hash_buf(conn->conn_rx_hash,
+-                                                text_in, rx_size, 0, NULL,
+-                                                &data_crc);
++                                                text_in,
++                                                ALIGN(payload_length, 4),
++                                                0, NULL, &data_crc);
+                       if (checksum != data_crc) {
+                               pr_err("Text data CRC32C DataDigest"
+@@ -2317,6 +2318,7 @@ iscsit_handle_text_cmd(struct iscsi_conn
+                                       " Command CmdSN: 0x%08x due to"
+                                       " DataCRC error.\n", hdr->cmdsn);
+                                       kfree(text_in);
++                                      cmd->text_in_ptr = NULL;
+                                       return 0;
+                               }
+                       } else {
diff --git a/queue-5.15/selftests-mptcp-drop-nanoseconds-width-specifier.patch b/queue-5.15/selftests-mptcp-drop-nanoseconds-width-specifier.patch
new file mode 100644 (file)
index 0000000..e5462d9
--- /dev/null
@@ -0,0 +1,69 @@
+From stable+bounces-256912-greg=kroah.com@vger.kernel.org Sat May 30 20:11:19 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 10:37:34 -0400
+Subject: selftests: mptcp: drop nanoseconds width specifier
+To: stable@vger.kernel.org
+Cc: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Paolo Abeni <pabeni@redhat.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530143734.2474733-1-sashal@kernel.org>
+
+From: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
+
+[ Upstream commit 01ff78e4b3d98689184c52d97f9575dfbdc3b10f ]
+
+Using the format specifier +%s%3N with GNU date is honoured, and only
+prints 3 digits of the nanoseconds portion of the seconds since epoch,
+which corresponds to the milliseconds.
+
+The uutils implementation of date currently does not honour this, and
+always prints all 9 digits. This is a known issue [1], but can be worked
+around by adapting this test to use nanoseconds instead of microseconds,
+and then divide it by 1e6.
+
+This fix is similar to what has been done on systemd side [2], and it is
+needed to run the selftests on Ubuntu 26.04, containing uutils 0.8.0.
+
+Note that the Fixes tag is there even if this patch doesn't fix an issue
+in the kernel selftests, but it is useful for those using uutils 0.8.0.
+
+Fixes: 048d19d444be ("mptcp: add basic kselftest for mptcp")
+Cc: stable@vger.kernel.org
+Link: https://github.com/uutils/coreutils/issues/11658 [1]
+Link: https://github.com/systemd/systemd/pull/41627 [2]
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260515-net-mptcp-misc-fixes-7-1-rc4-v2-6-701e96419f2f@kernel.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/selftests/net/mptcp/mptcp_connect.sh |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh
++++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh
+@@ -462,7 +462,7 @@ do_transfer()
+       wait_local_port_listen "${listener_ns}" "${port}"
+       local start
+-      start=$(date +%s%3N)
++      start=$(date +%s%N)
+       timeout ${timeout_test} \
+               ip netns exec ${connector_ns} \
+                       ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \
+@@ -475,7 +475,7 @@ do_transfer()
+       local rets=$?
+       local stop
+-      stop=$(date +%s%3N)
++      stop=$(date +%s%N)
+       if $capture; then
+               sleep 1
+@@ -491,7 +491,7 @@ do_transfer()
+       fi
+       local duration
+-      duration=$((stop-start))
++      duration=$(((stop-start) / 1000000))
+       printf "(duration %05sms) " "${duration}"
+       if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ]; then
+               echo "[ FAIL ] client exit code $retc, server $rets" 1>&2
diff --git a/queue-5.15/serial-altera_jtaguart-handle-uart_add_one_port-failures.patch b/queue-5.15/serial-altera_jtaguart-handle-uart_add_one_port-failures.patch
new file mode 100644 (file)
index 0000000..92e7958
--- /dev/null
@@ -0,0 +1,59 @@
+From sashal@kernel.org Sat Jun  6 17:48:48 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  6 Jun 2026 08:18:43 -0400
+Subject: serial: altera_jtaguart: handle uart_add_one_port() failures
+To: stable@vger.kernel.org
+Cc: Myeonghun Pak <mhun512@gmail.com>, stable <stable@kernel.org>, Ijae Kim <ae878000@gmail.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606121843.2850594-2-sashal@kernel.org>
+
+From: Myeonghun Pak <mhun512@gmail.com>
+
+[ Upstream commit ea66be25f0e934f49d24cd0c5845d13cdba3520b ]
+
+altera_jtaguart_probe() maps the register window before registering the
+UART port, but it ignores failures from uart_add_one_port(). If port
+registration fails, probe still returns success and the mapping remains
+live until a later remove path that is not part of probe failure cleanup.
+
+Return the uart_add_one_port() error and unmap the register window on
+that failure path.
+
+This issue was identified during our ongoing static-analysis research while
+reviewing kernel code.
+
+Fixes: 5bcd601049c6 ("serial: Add driver for the Altera JTAG UART")
+Cc: stable <stable@kernel.org>
+Co-developed-by: Ijae Kim <ae878000@gmail.com>
+Signed-off-by: Ijae Kim <ae878000@gmail.com>
+Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
+Link: https://patch.msgid.link/20260512065837.79528-1-mhun512@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/altera_jtaguart.c |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/tty/serial/altera_jtaguart.c
++++ b/drivers/tty/serial/altera_jtaguart.c
+@@ -421,6 +421,7 @@ static int altera_jtaguart_probe(struct
+       struct resource *res_mem;
+       int i = pdev->id;
+       int irq;
++      int ret;
+       /* -1 emphasizes that the platform must have one port, no .N suffix */
+       if (i == -1)
+@@ -460,7 +461,11 @@ static int altera_jtaguart_probe(struct
+       port->flags = UPF_BOOT_AUTOCONF;
+       port->dev = &pdev->dev;
+-      uart_add_one_port(&altera_jtaguart_driver, port);
++      ret = uart_add_one_port(&altera_jtaguart_driver, port);
++      if (ret) {
++              iounmap(port->membase);
++              return ret;
++      }
+       return 0;
+ }
diff --git a/queue-5.15/serial-altera_jtaguart-use-platform_get_irq_optional-to-get-the-interrupt.patch b/queue-5.15/serial-altera_jtaguart-use-platform_get_irq_optional-to-get-the-interrupt.patch
new file mode 100644 (file)
index 0000000..71cc7ef
--- /dev/null
@@ -0,0 +1,59 @@
+From sashal@kernel.org Sat Jun  6 17:48:47 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  6 Jun 2026 08:18:42 -0400
+Subject: serial: altera_jtaguart: Use platform_get_irq_optional() to get the interrupt
+To: stable@vger.kernel.org
+Cc: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606121843.2850594-1-sashal@kernel.org>
+
+From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+
+[ Upstream commit 60302276caff50f907bc3391a364691ab4a21b43 ]
+
+platform_get_resource(pdev, IORESOURCE_IRQ, ..) relies on static
+allocation of IRQ resources in DT core code, this causes an issue
+when using hierarchical interrupt domains using "interrupts" property
+in the node as this bypasses the hierarchical setup and messes up the
+irq chaining.
+
+In preparation for removal of static setup of IRQ resource from DT core
+code use platform_get_irq_optional().
+
+Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+Link: https://lore.kernel.org/r/20211224142917.6966-7-prabhakar.mahadev-lad.rj@bp.renesas.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: ea66be25f0e9 ("serial: altera_jtaguart: handle uart_add_one_port() failures")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/altera_jtaguart.c |   11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- a/drivers/tty/serial/altera_jtaguart.c
++++ b/drivers/tty/serial/altera_jtaguart.c
+@@ -418,8 +418,9 @@ static int altera_jtaguart_probe(struct
+       struct altera_jtaguart_platform_uart *platp =
+                       dev_get_platdata(&pdev->dev);
+       struct uart_port *port;
+-      struct resource *res_irq, *res_mem;
++      struct resource *res_mem;
+       int i = pdev->id;
++      int irq;
+       /* -1 emphasizes that the platform must have one port, no .N suffix */
+       if (i == -1)
+@@ -438,9 +439,11 @@ static int altera_jtaguart_probe(struct
+       else
+               return -ENODEV;
+-      res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+-      if (res_irq)
+-              port->irq = res_irq->start;
++      irq = platform_get_irq_optional(pdev, 0);
++      if (irq < 0 && irq != -ENXIO)
++              return irq;
++      if (irq > 0)
++              port->irq = irq;
+       else if (platp)
+               port->irq = platp->irq;
+       else
diff --git a/queue-5.15/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch b/queue-5.15/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch
new file mode 100644 (file)
index 0000000..6c8cebe
--- /dev/null
@@ -0,0 +1,42 @@
+From sashal@kernel.org Sat Jun  6 17:48:58 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  6 Jun 2026 08:18:54 -0400
+Subject: serial: qcom-geni: fix UART_RX_PAR_EN bit position
+To: stable@vger.kernel.org
+Cc: Prasanna S <prasanna.s@oss.qualcomm.com>, stable <stable@kernel.org>, Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606121854.2850880-3-sashal@kernel.org>
+
+From: Prasanna S <prasanna.s@oss.qualcomm.com>
+
+[ Upstream commit ca2584d841b69391ffc4144840563d2e1a0018df ]
+
+UART_RX_PAR_EN is incorrectly defined as bit 3, which triggers false
+framing errors (S_GP_IRQ_1_EN) and causes received data to be dropped
+when parity is enabled and the parity bit is 0.
+
+Define UART_RX_PAR_EN as bit 4 of the SE_UART_RX_TRANS_CFG register, as
+specified in the reference manual.
+
+Fixes: c4f528795d1a ("tty: serial: msm_geni_serial: Add serial driver support for GENI based QUP")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Prasanna S <prasanna.s@oss.qualcomm.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260428-serial-bit-correct-v1-1-9131ad5b97d8@oss.qualcomm.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/qcom_geni_serial.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/tty/serial/qcom_geni_serial.c
++++ b/drivers/tty/serial/qcom_geni_serial.c
+@@ -43,7 +43,7 @@
+ #define TX_STOP_BIT_LEN_2             2
+ /* SE_UART_RX_TRANS_CFG */
+-#define UART_RX_PAR_EN                        BIT(3)
++#define UART_RX_PAR_EN                        BIT(4)
+ /* SE_UART_RX_WORD_LEN */
+ #define RX_WORD_LEN_MASK              GENMASK(9, 0)
diff --git a/queue-5.15/serial-samsung_tty-use-port-lock-wrappers.patch b/queue-5.15/serial-samsung_tty-use-port-lock-wrappers.patch
new file mode 100644 (file)
index 0000000..999a3be
--- /dev/null
@@ -0,0 +1,236 @@
+From sashal@kernel.org Sat Jun  6 00:01:18 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 14:31:13 -0400
+Subject: serial: samsung_tty: Use port lock wrappers
+To: stable@vger.kernel.org
+Cc: Thomas Gleixner <tglx@linutronix.de>, John Ogness <john.ogness@linutronix.de>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260605183115.2054750-1-sashal@kernel.org>
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit 97d7a9aeba1d424c2359f1686d02c75d798ad184 ]
+
+When a serial port is used for kernel console output, then all
+modifications to the UART registers which are done from other contexts,
+e.g. getty, termios, are interference points for the kernel console.
+
+So far this has been ignored and the printk output is based on the
+principle of hope. The rework of the console infrastructure which aims to
+support threaded and atomic consoles, requires to mark sections which
+modify the UART registers as unsafe. This allows the atomic write function
+to make informed decisions and eventually to restore operational state. It
+also allows to prevent the regular UART code from modifying UART registers
+while printk output is in progress.
+
+All modifications of UART registers are guarded by the UART port lock,
+which provides an obvious synchronization point with the console
+infrastructure.
+
+To avoid adding this functionality to all UART drivers, wrap the
+spin_[un]lock*() invocations for uart_port::lock into helper functions
+which just contain the spin_[un]lock*() invocations for now. In a
+subsequent step these helpers will gain the console synchronization
+mechanisms.
+
+Converted with coccinelle. No functional change.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: John Ogness <john.ogness@linutronix.de>
+Link: https://lore.kernel.org/r/20230914183831.587273-54-john.ogness@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: a3bb136bff5e ("tty: serial: samsung: Remove redundant port lock acquisition in rx helpers")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/samsung_tty.c |   44 +++++++++++++++++++--------------------
+ 1 file changed, 22 insertions(+), 22 deletions(-)
+
+--- a/drivers/tty/serial/samsung_tty.c
++++ b/drivers/tty/serial/samsung_tty.c
+@@ -246,7 +246,7 @@ static void s3c24xx_serial_rx_enable(str
+       unsigned int ucon, ufcon;
+       int count = 10000;
+-      spin_lock_irqsave(&port->lock, flags);
++      uart_port_lock_irqsave(port, &flags);
+       while (--count && !s3c24xx_serial_txempty_nofifo(port))
+               udelay(100);
+@@ -260,7 +260,7 @@ static void s3c24xx_serial_rx_enable(str
+       wr_regl(port, S3C2410_UCON, ucon);
+       ourport->rx_enabled = 1;
+-      spin_unlock_irqrestore(&port->lock, flags);
++      uart_port_unlock_irqrestore(port, flags);
+ }
+ static void s3c24xx_serial_rx_disable(struct uart_port *port)
+@@ -269,14 +269,14 @@ static void s3c24xx_serial_rx_disable(st
+       unsigned long flags;
+       unsigned int ucon;
+-      spin_lock_irqsave(&port->lock, flags);
++      uart_port_lock_irqsave(port, &flags);
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~S3C2410_UCON_RXIRQMODE;
+       wr_regl(port, S3C2410_UCON, ucon);
+       ourport->rx_enabled = 0;
+-      spin_unlock_irqrestore(&port->lock, flags);
++      uart_port_unlock_irqrestore(port, flags);
+ }
+ static void s3c24xx_serial_stop_tx(struct uart_port *port)
+@@ -344,7 +344,7 @@ static void s3c24xx_serial_tx_dma_comple
+                               dma->tx_transfer_addr, dma->tx_size,
+                               DMA_TO_DEVICE);
+-      spin_lock_irqsave(&port->lock, flags);
++      uart_port_lock_irqsave(port, &flags);
+       xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+       port->icount.tx += count;
+@@ -354,7 +354,7 @@ static void s3c24xx_serial_tx_dma_comple
+               uart_write_wakeup(port);
+       s3c24xx_serial_start_next_tx(ourport);
+-      spin_unlock_irqrestore(&port->lock, flags);
++      uart_port_unlock_irqrestore(port, flags);
+ }
+ static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
+@@ -620,7 +620,7 @@ static void s3c24xx_serial_rx_dma_comple
+       received  = dma->rx_bytes_requested - state.residue;
+       async_tx_ack(dma->rx_desc);
+-      spin_lock_irqsave(&port->lock, flags);
++      uart_port_lock_irqsave(port, &flags);
+       if (received)
+               s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
+@@ -632,7 +632,7 @@ static void s3c24xx_serial_rx_dma_comple
+       s3c64xx_start_rx_dma(ourport);
+-      spin_unlock_irqrestore(&port->lock, flags);
++      uart_port_unlock_irqrestore(port, flags);
+ }
+ static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
+@@ -723,7 +723,7 @@ static irqreturn_t s3c24xx_serial_rx_cha
+       utrstat = rd_regl(port, S3C2410_UTRSTAT);
+       rd_regl(port, S3C2410_UFSTAT);
+-      spin_lock(&port->lock);
++      uart_port_lock(port);
+       if (!(utrstat & S3C2410_UTRSTAT_TIMEOUT)) {
+               s3c64xx_start_rx_dma(ourport);
+@@ -752,7 +752,7 @@ static irqreturn_t s3c24xx_serial_rx_cha
+       wr_regl(port, S3C2410_UTRSTAT, S3C2410_UTRSTAT_TIMEOUT);
+ finish:
+-      spin_unlock(&port->lock);
++      uart_port_unlock(port);
+       return IRQ_HANDLED;
+ }
+@@ -849,9 +849,9 @@ static irqreturn_t s3c24xx_serial_rx_cha
+       struct s3c24xx_uart_port *ourport = dev_id;
+       struct uart_port *port = &ourport->port;
+-      spin_lock(&port->lock);
++      uart_port_lock(port);
+       s3c24xx_serial_rx_drain_fifo(ourport);
+-      spin_unlock(&port->lock);
++      uart_port_unlock(port);
+       return IRQ_HANDLED;
+ }
+@@ -933,11 +933,11 @@ static irqreturn_t s3c24xx_serial_tx_irq
+       struct s3c24xx_uart_port *ourport = id;
+       struct uart_port *port = &ourport->port;
+-      spin_lock(&port->lock);
++      uart_port_lock(port);
+       s3c24xx_serial_tx_chars(ourport);
+-      spin_unlock(&port->lock);
++      uart_port_unlock(port);
+       return IRQ_HANDLED;
+ }
+@@ -1025,7 +1025,7 @@ static void s3c24xx_serial_break_ctl(str
+       unsigned long flags;
+       unsigned int ucon;
+-      spin_lock_irqsave(&port->lock, flags);
++      uart_port_lock_irqsave(port, &flags);
+       ucon = rd_regl(port, S3C2410_UCON);
+@@ -1036,7 +1036,7 @@ static void s3c24xx_serial_break_ctl(str
+       wr_regl(port, S3C2410_UCON, ucon);
+-      spin_unlock_irqrestore(&port->lock, flags);
++      uart_port_unlock_irqrestore(port, flags);
+ }
+ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
+@@ -1295,7 +1295,7 @@ static int s3c64xx_serial_startup(struct
+       ourport->rx_enabled = 1;
+       ourport->tx_enabled = 0;
+-      spin_lock_irqsave(&port->lock, flags);
++      uart_port_lock_irqsave(port, &flags);
+       ufcon = rd_regl(port, S3C2410_UFCON);
+       ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8;
+@@ -1305,7 +1305,7 @@ static int s3c64xx_serial_startup(struct
+       enable_rx_pio(ourport);
+-      spin_unlock_irqrestore(&port->lock, flags);
++      uart_port_unlock_irqrestore(port, flags);
+       /* Enable Rx Interrupt */
+       s3c24xx_clear_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM);
+@@ -1333,7 +1333,7 @@ static int apple_s5l_serial_startup(stru
+       ourport->rx_enabled = 1;
+       ourport->tx_enabled = 0;
+-      spin_lock_irqsave(&port->lock, flags);
++      uart_port_lock_irqsave(port, &flags);
+       ufcon = rd_regl(port, S3C2410_UFCON);
+       ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8;
+@@ -1343,7 +1343,7 @@ static int apple_s5l_serial_startup(stru
+       enable_rx_pio(ourport);
+-      spin_unlock_irqrestore(&port->lock, flags);
++      uart_port_unlock_irqrestore(port, flags);
+       /* Enable Rx Interrupt */
+       s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTHRESH_ENA, S3C2410_UCON);
+@@ -1644,7 +1644,7 @@ static void s3c24xx_serial_set_termios(s
+               ulcon |= S3C2410_LCON_PNONE;
+       }
+-      spin_lock_irqsave(&port->lock, flags);
++      uart_port_lock_irqsave(port, &flags);
+       dev_dbg(port->dev,
+               "setting ulcon to %08x, brddiv to %d, udivslot %08x\n",
+@@ -1702,7 +1702,7 @@ static void s3c24xx_serial_set_termios(s
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= RXSTAT_DUMMY_READ;
+-      spin_unlock_irqrestore(&port->lock, flags);
++      uart_port_unlock_irqrestore(port, flags);
+ }
+ static const char *s3c24xx_serial_type(struct uart_port *port)
index 8bccfa5c6852ad1859f0d3694308d37e2ad51d18..37f6671c6d3edfa6b36415acf12fe1d87aa6b498 100644 (file)
@@ -301,6 +301,97 @@ alsa-aloop-fix-peer-runtime-uaf-during-format-change-stop.patch
 printk-add-print_hex_dump_devel.patch
 crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch
 tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch
-rxrpc-fix-conn-level-packet-handling-to-unshare-response-packets.patch
-mtd-docg3-fix-use-after-free-in-docg3_release.patch
-mtd-docg3-convert-to-platform-remove-callback-returning-void.patch
+smb-client-validate-the-whole-dacl-before-rewriting-it-in-cifsacl.patch
+usb-typec-tcpm-reset-internal-port-states-on-soft-reset-ams.patch
+wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch
+usb-dwc3-move-guid-programming-after-phy-initialization.patch
+net-ipv4-stop-checking-crypto_ahash_alignmask.patch
+net-ipv6-stop-checking-crypto_ahash_alignmask.patch
+xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch
+xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch
+spi-syncuacer-fix-controller-deregistration.patch
+spi-sun4i-fix-controller-deregistration.patch
+spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch
+spi-ti-qspi-fix-controller-deregistration.patch
+spi-zynq-qspi-fix-controller-deregistration.patch
+spi-sun6i-fix-controller-deregistration.patch
+spi-tegra114-fix-controller-deregistration.patch
+spi-tegra20-sflash-fix-controller-deregistration.patch
+spi-uniphier-fix-controller-deregistration.patch
+mm-hugetlb_cma-round-up-per_node-before-logging-it.patch
+fbcon-avoid-oob-font-access-if-console-rotation-fails.patch
+spi-topcliff-pch-convert-to-platform-remove-callback-returning-void.patch
+spi-topcliff-pch-fix-controller-deregistration.patch
+btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch
+tracing-probes-limit-size-of-event-probe-to-3k.patch
+pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch
+smb-client-validate-dacloffset-before-building-dacl-pointers.patch
+btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch
+smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch
+mptcp-pm-prio-skip-closed-subflows.patch
+mptcp-pm-add_addr-rtx-fix-potential-data-race.patch
+mptcp-pm-add_addr-rtx-resched-blocked-add_addr-quicker.patch
+f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch
+f2fs-fix-false-alarm-of-lockdep-on-cp_global_sem-lock.patch
+spi-st-ssc4-fix-controller-deregistration.patch
+spi-lantiq-ssc-fix-controller-deregistration.patch
+genetlink-use-internal-flags-for-multicast-groups.patch
+smb-client-require-net-admin-for-cifs-swn-netlink.patch
+bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch
+bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch
+bluetooth-hci_sync-make-use-of-hci_cmd_sync_queue-set-2.patch
+bluetooth-mgmt-validate-add-extended-advertising-data-length.patch
+qed-use-the-bitmap-api-to-simplify-some-functions.patch
+qed-fix-double-free-in-qed_cxt_tables_alloc.patch
+bluetooth-consolidate-code-around-sk_alloc-into-a-helper-function.patch
+bluetooth-init-sk_peer_-on-bt_sock_alloc.patch
+bluetooth-serialize-accept_q-access.patch
+net-hsr-defer-node-table-free-until-after-rcu-readers.patch
+ice-fix-vf-queue-configuration-with-low-mtu-values.patch
+ipv6-addrconf-annotate-data-races-around-devconf-fields-ii.patch
+ipv6-ioam-add-null-check-for-idev-in-ipv6_hop_ioam.patch
+use-less-confusing-names-for-iov_iter-direction-initializers.patch
+mptcp-pm-fix-add_addr-timer-infinite-retry-on-option-space-insufficient.patch
+selftests-mptcp-drop-nanoseconds-width-specifier.patch
+mptcp-do-not-drop-partial-packets.patch
+octeontx2-af-cgx-add-bounds-check-to-cgx_speed_mbps-index.patch
+octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch
+spi-qup-switch-to-use-modern-name.patch
+spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch
+arm64-tlb-flush-walk-cache-when-unsharing-pmd-tables.patch
+phy-tegra-xusb-disable-trk-clk-when-not-in-use.patch
+phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch
+bluetooth-l2cap-use-chan-timer-to-close-channels-in-cleanup_listen.patch
+iio-adc-fix-the-return-value-handle-for-platform_get_irq.patch
+iio-adc-npcm-convert-to-platform-remove-callback-returning-void.patch
+iio-adc-npcm-fix-unbalanced-clk_disable_unprepare.patch
+iio-dac-ad5686-acquire-lock-when-doing-powerdown-control.patch
+iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch
+iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch
+iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch
+iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch
+usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch
+net-skbuff-fix-missing-zerocopy-reference-in-pskb_carve-helpers.patch
+serial-samsung_tty-use-port-lock-wrappers.patch
+tty-serial-samsung-use-u32-for-register-interactions.patch
+tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch
+usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch
+usb-gadget-f_hid-tidy-error-handling-in-hidg_alloc.patch
+usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch
+thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch
+scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch
+usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch
+drm-hyperv-remove-support-for-hyper-v-2008-and-2008r2-win7.patch
+drm-hyperv-validate-resolution_count-and-fix-win8-fallback.patch
+serial-altera_jtaguart-use-platform_get_irq_optional-to-get-the-interrupt.patch
+serial-altera_jtaguart-handle-uart_add_one_port-failures.patch
+tty-serial-qcom-geni-serial-remove-unused-symbols.patch
+tty-serial-qcom-geni-serial-align-define-values.patch
+serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch
+scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch
+netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch
+hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch
+rdma-umem-fix-kernel-doc-warnings.patch
+rdma-move-dma-block-iterator-logic-into-dedicated-files.patch
+rdma-umem-fix-truncation-for-block-sizes-4g.patch
+mm-huge_memory-update-file-pmd-counter-before-folio_put.patch
diff --git a/queue-5.15/smb-client-require-net-admin-for-cifs-swn-netlink.patch b/queue-5.15/smb-client-require-net-admin-for-cifs-swn-netlink.patch
new file mode 100644 (file)
index 0000000..f3ac22b
--- /dev/null
@@ -0,0 +1,62 @@
+From stable+bounces-256669-greg=kroah.com@vger.kernel.org Fri May 29 22:56:50 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 13:21:53 -0400
+Subject: smb: client: require net admin for CIFS SWN netlink
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Steve French <stfrench@microsoft.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529172153.1318415-2-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit d1ebfce2c1d161186a82e77590bf7da2ea1bce91 ]
+
+CIFS_GENL_CMD_SWN_NOTIFY is the userspace witness-notify command.  The
+intended sender is the cifs.witness helper, but the generic-netlink
+operation currently has no capability flag, so any local process can send
+RESOURCE_CHANGE or CLIENT_MOVE notifications to the in-kernel witness
+handler.
+
+The same family exposes CIFS_GENL_MCGRP_SWN without multicast-group
+capability flags.  Register messages sent to that group include the witness
+registration id and, for NTLM-authenticated mounts, the username, domain,
+and password attributes copied from the CIFS session.  An unprivileged
+local process should not be able to join that group and receive those
+messages.
+
+Require CAP_NET_ADMIN for incoming SWN_NOTIFY commands with
+GENL_ADMIN_PERM, and require CAP_NET_ADMIN over the network namespace for
+joining the SWN multicast group with GENL_MCAST_CAP_NET_ADMIN.  The
+cifs.witness service runs with the privileges needed for both operations.
+
+Fixes: fed979a7e082 ("cifs: Set witness notification handler for messages from userspace daemon")
+Cc: stable@vger.kernel.org
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/netlink.c |    6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/fs/cifs/netlink.c
++++ b/fs/cifs/netlink.c
+@@ -33,13 +33,17 @@ static const struct nla_policy cifs_genl
+ static const struct genl_ops cifs_genl_ops[] = {
+       {
+               .cmd = CIFS_GENL_CMD_SWN_NOTIFY,
++              .flags = GENL_ADMIN_PERM,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = cifs_swn_notify,
+       },
+ };
+ static const struct genl_multicast_group cifs_genl_mcgrps[] = {
+-      [CIFS_GENL_MCGRP_SWN] = { .name = CIFS_GENL_MCGRP_SWN_NAME },
++      [CIFS_GENL_MCGRP_SWN] = {
++              .name = CIFS_GENL_MCGRP_SWN_NAME,
++              .flags = GENL_MCAST_CAP_NET_ADMIN,
++      },
+ };
+ struct genl_family cifs_genl_family = {
diff --git a/queue-5.15/smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch b/queue-5.15/smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch
new file mode 100644 (file)
index 0000000..e4560bf
--- /dev/null
@@ -0,0 +1,158 @@
+From stable+bounces-249152-greg=kroah.com@vger.kernel.org Mon May 18 04:36:16 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 17 May 2026 19:05:32 -0400
+Subject: smb: client: Use FullSessionKey for AES-256 encryption key derivation
+To: stable@vger.kernel.org
+Cc: Piyush Sachdeva <s.piyush1024@gmail.com>, Bharath SM <bharathsm@microsoft.com>, Piyush Sachdeva <psachdeva@microsoft.com>, Steve French <stfrench@microsoft.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260517230532.410411-1-sashal@kernel.org>
+
+From: Piyush Sachdeva <s.piyush1024@gmail.com>
+
+[ Upstream commit 5be7a0cef3229fb3b63a07c0d289daf752545424 ]
+
+When Kerberos authentication is used with AES-256 encryption (AES-256-CCM
+or AES-256-GCM), the SMB3 encryption and decryption keys must be derived
+using the full session key (Session.FullSessionKey) rather than just the
+first 16 bytes (Session.SessionKey).
+
+Per MS-SMB2 section 3.2.5.3.1, when Connection.Dialect is "3.1.1" and
+Connection.CipherId is AES-256-CCM or AES-256-GCM, Session.FullSessionKey
+must be set to the full cryptographic key from the GSS authentication
+context. The encryption and decryption key derivation (SMBC2SCipherKey,
+SMBS2CCipherKey) must use this FullSessionKey as the KDF input. The
+signing key derivation continues to use Session.SessionKey (first 16
+bytes) in all cases.
+
+Previously, generate_key() hardcoded SMB2_NTLMV2_SESSKEY_SIZE (16) as the
+HMAC-SHA256 key input length for all derivations. When Kerberos with
+AES-256 provides a 32-byte session key, the KDF for encryption/decryption
+was using only the first 16 bytes, producing keys that did not match the
+server's, causing mount failures with sec=krb5 and require_gcm_256=1.
+
+Add a full_key_size parameter to generate_key() and pass the appropriate
+size from generate_smb3signingkey():
+ - Signing: always SMB2_NTLMV2_SESSKEY_SIZE (16 bytes)
+ - Encryption/Decryption: ses->auth_key.len when AES-256, otherwise 16
+
+Also fix cifs_dump_full_key() to report the actual session key length for
+AES-256 instead of hardcoded CIFS_SESS_KEY_SIZE, so that userspace tools
+like Wireshark receive the correct key for decryption.
+
+Cc: <stable@vger.kernel.org>
+Reviewed-by: Bharath SM <bharathsm@microsoft.com>
+Signed-off-by: Piyush Sachdeva <psachdeva@microsoft.com>
+Signed-off-by: Piyush Sachdeva <s.piyush1024@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+[ adapted to legacy crypto_shash API and ses->binding boolean instead of upstream's hmac_sha256 helpers and chan_lock machinery ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/ioctl.c         |    2 +-
+ fs/cifs/smb2transport.c |   36 ++++++++++++++++++++++++++----------
+ 2 files changed, 27 insertions(+), 11 deletions(-)
+
+--- a/fs/cifs/ioctl.c
++++ b/fs/cifs/ioctl.c
+@@ -262,7 +262,7 @@ search_end:
+               break;
+       case SMB2_ENCRYPTION_AES256_CCM:
+       case SMB2_ENCRYPTION_AES256_GCM:
+-              out.session_key_length = CIFS_SESS_KEY_SIZE;
++              out.session_key_length = ses->auth_key.len;
+               out.server_in_key_length = out.server_out_key_length = SMB3_GCM256_CRYPTKEY_SIZE;
+               break;
+       default:
+--- a/fs/cifs/smb2transport.c
++++ b/fs/cifs/smb2transport.c
+@@ -291,7 +291,8 @@ out:
+ }
+ static int generate_key(struct cifs_ses *ses, struct kvec label,
+-                      struct kvec context, __u8 *key, unsigned int key_size)
++                      struct kvec context, __u8 *key, unsigned int key_size,
++                      unsigned int full_key_size)
+ {
+       unsigned char zero = 0x0;
+       __u8 i[4] = {0, 0, 0, 1};
+@@ -312,7 +313,7 @@ static int generate_key(struct cifs_ses
+       }
+       rc = crypto_shash_setkey(server->secmech.hmacsha256,
+-              ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
++              ses->auth_key.response, full_key_size);
+       if (rc) {
+               cifs_server_dbg(VFS, "%s: Could not set with session key\n", __func__);
+               goto smb3signkey_ret;
+@@ -393,10 +394,9 @@ static int
+ generate_smb3signingkey(struct cifs_ses *ses,
+                       const struct derivation_triplet *ptriplet)
+ {
+-      int rc;
+-#ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS
++      unsigned int full_key_size = SMB2_NTLMV2_SESSKEY_SIZE;
+       struct TCP_Server_Info *server = ses->server;
+-#endif
++      int rc;
+       /*
+        * All channels use the same encryption/decryption keys but
+@@ -412,30 +412,46 @@ generate_smb3signingkey(struct cifs_ses
+               rc = generate_key(ses, ptriplet->signing.label,
+                                 ptriplet->signing.context,
+                                 cifs_ses_binding_channel(ses)->signkey,
+-                                SMB3_SIGN_KEY_SIZE);
++                                SMB3_SIGN_KEY_SIZE,
++                                SMB2_NTLMV2_SESSKEY_SIZE);
+               if (rc)
+                       return rc;
+       } else {
+               rc = generate_key(ses, ptriplet->signing.label,
+                                 ptriplet->signing.context,
+                                 ses->smb3signingkey,
+-                                SMB3_SIGN_KEY_SIZE);
++                                SMB3_SIGN_KEY_SIZE,
++                                SMB2_NTLMV2_SESSKEY_SIZE);
+               if (rc)
+                       return rc;
++              /*
++               * Per MS-SMB2 3.2.5.3.1, signing key always uses Session.SessionKey
++               * (first 16 bytes). Encryption/decryption keys use
++               * Session.FullSessionKey when dialect is 3.1.1 and cipher is
++               * AES-256-CCM or AES-256-GCM, otherwise Session.SessionKey.
++               */
++
++              if (server->dialect == SMB311_PROT_ID &&
++                  (server->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
++                   server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
++                      full_key_size = ses->auth_key.len;
++
+               memcpy(ses->chans[0].signkey, ses->smb3signingkey,
+                      SMB3_SIGN_KEY_SIZE);
+               rc = generate_key(ses, ptriplet->encryption.label,
+                                 ptriplet->encryption.context,
+                                 ses->smb3encryptionkey,
+-                                SMB3_ENC_DEC_KEY_SIZE);
++                                SMB3_ENC_DEC_KEY_SIZE,
++                                full_key_size);
+               if (rc)
+                       return rc;
+               rc = generate_key(ses, ptriplet->decryption.label,
+                                 ptriplet->decryption.context,
+                                 ses->smb3decryptionkey,
+-                                SMB3_ENC_DEC_KEY_SIZE);
++                                SMB3_ENC_DEC_KEY_SIZE,
++                                full_key_size);
+               if (rc)
+                       return rc;
+       }
+@@ -450,7 +466,7 @@ generate_smb3signingkey(struct cifs_ses
+                       &ses->Suid);
+       cifs_dbg(VFS, "Cipher type   %d\n", server->cipher_type);
+       cifs_dbg(VFS, "Session Key   %*ph\n",
+-               SMB2_NTLMV2_SESSKEY_SIZE, ses->auth_key.response);
++               (int)ses->auth_key.len, ses->auth_key.response);
+       cifs_dbg(VFS, "Signing Key   %*ph\n",
+                SMB3_SIGN_KEY_SIZE, ses->smb3signingkey);
+       if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) ||
diff --git a/queue-5.15/smb-client-validate-dacloffset-before-building-dacl-pointers.patch b/queue-5.15/smb-client-validate-dacloffset-before-building-dacl-pointers.patch
new file mode 100644 (file)
index 0000000..c346d79
--- /dev/null
@@ -0,0 +1,120 @@
+From stable+bounces-249027-greg=kroah.com@vger.kernel.org Sun May 17 00:39:15 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 16 May 2026 15:09:10 -0400
+Subject: smb: client: validate dacloffset before building DACL pointers
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Steve French <stfrench@microsoft.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260516190910.4016968-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit f98b48151cc502ada59d9778f0112d21f2586ca3 ]
+
+parse_sec_desc(), build_sec_desc(), and the chown path in
+id_mode_to_cifs_acl() all add the server-supplied dacloffset to pntsd
+before proving a DACL header fits inside the returned security
+descriptor.
+
+On 32-bit builds a malicious server can return dacloffset near
+U32_MAX, wrap the derived DACL pointer below end_of_acl, and then slip
+past the later pointer-based bounds checks. build_sec_desc() and
+id_mode_to_cifs_acl() can then dereference DACL fields from the wrapped
+pointer in the chmod/chown rewrite paths.
+
+Validate dacloffset numerically before building any DACL pointer and
+reuse the same helper at the three DACL entry points.
+
+Fixes: bc3e9dd9d104 ("cifs: Change SIDs in ACEs while transferring file ownership.")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-6
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+[ renamed smb_ntsd/smb_acl structs to cifs_ntsd/cifs_acl and kept existing inline ACL size check instead of using missing validate_dacl() helper ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/cifsacl.c |   35 ++++++++++++++++++++++++++++++++---
+ 1 file changed, 32 insertions(+), 3 deletions(-)
+
+--- a/fs/cifs/cifsacl.c
++++ b/fs/cifs/cifsacl.c
+@@ -1254,6 +1254,17 @@ static int parse_sid(struct cifs_sid *ps
+       return 0;
+ }
++static bool dacl_offset_valid(unsigned int acl_len, __u32 dacloffset)
++{
++      if (acl_len < sizeof(struct cifs_acl))
++              return false;
++
++      if (dacloffset < sizeof(struct cifs_ntsd))
++              return false;
++
++      return dacloffset <= acl_len - sizeof(struct cifs_acl);
++}
++
+ /* Convert CIFS ACL to POSIX form */
+ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
+@@ -1274,7 +1285,6 @@ static int parse_sec_desc(struct cifs_sb
+       group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
+                               le32_to_cpu(pntsd->gsidoffset));
+       dacloffset = le32_to_cpu(pntsd->dacloffset);
+-      dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
+       cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
+                pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
+                le32_to_cpu(pntsd->gsidoffset),
+@@ -1305,11 +1315,18 @@ static int parse_sec_desc(struct cifs_sb
+               return rc;
+       }
+-      if (dacloffset)
++      if (dacloffset) {
++              if (!dacl_offset_valid(acl_len, dacloffset)) {
++                      cifs_dbg(VFS, "Server returned illegal DACL offset\n");
++                      return -EINVAL;
++              }
++
++              dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
+               parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
+                          group_sid_ptr, fattr, get_mode_from_special_sid);
+-      else
++      } else {
+               cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
++      }
+       return rc;
+ }
+@@ -1332,6 +1349,11 @@ static int build_sec_desc(struct cifs_nt
+       dacloffset = le32_to_cpu(pntsd->dacloffset);
+       if (dacloffset) {
++              if (!dacl_offset_valid(secdesclen, dacloffset)) {
++                      cifs_dbg(VFS, "Server returned illegal DACL offset\n");
++                      return -EINVAL;
++              }
++
+               dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
+               rc = validate_dacl(dacl_ptr, end_of_acl);
+               if (rc)
+@@ -1694,6 +1716,12 @@ id_mode_to_cifs_acl(struct inode *inode,
+               nsecdesclen = sizeof(struct cifs_ntsd) + (sizeof(struct cifs_sid) * 2);
+               dacloffset = le32_to_cpu(pntsd->dacloffset);
+               if (dacloffset) {
++                      if (!dacl_offset_valid(secdesclen, dacloffset)) {
++                              cifs_dbg(VFS, "Server returned illegal DACL offset\n");
++                              rc = -EINVAL;
++                              goto id_mode_to_cifs_acl_exit;
++                      }
++
+                       dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
+                       rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
+                       if (rc) {
+@@ -1736,6 +1764,7 @@ id_mode_to_cifs_acl(struct inode *inode,
+               rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag);
+               cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
+       }
++id_mode_to_cifs_acl_exit:
+       cifs_put_tlink(tlink);
+       kfree(pnntsd);
diff --git a/queue-5.15/smb-client-validate-the-whole-dacl-before-rewriting-it-in-cifsacl.patch b/queue-5.15/smb-client-validate-the-whole-dacl-before-rewriting-it-in-cifsacl.patch
new file mode 100644 (file)
index 0000000..332a8e0
--- /dev/null
@@ -0,0 +1,189 @@
+From 0a8cf165566ba55a39fd0f4de172119dd646d39a Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Sun, 19 Apr 2026 20:11:31 -0400
+Subject: smb: client: validate the whole DACL before rewriting it in cifsacl
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+commit 0a8cf165566ba55a39fd0f4de172119dd646d39a upstream.
+
+build_sec_desc() and id_mode_to_cifs_acl() derive a DACL pointer from a
+server-supplied dacloffset and then use the incoming ACL to rebuild the
+chmod/chown security descriptor.
+
+The original fix only checked that the struct smb_acl header fits before
+reading dacl_ptr->size or dacl_ptr->num_aces.  That avoids the immediate
+header-field OOB read, but the rewrite helpers still walk ACEs based on
+pdacl->num_aces with no structural validation of the incoming DACL body.
+
+A malicious server can return a truncated DACL that still contains a
+header, claims one or more ACEs, and then drive
+replace_sids_and_copy_aces() or set_chmod_dacl() past the validated
+extent while they compare or copy attacker-controlled ACEs.
+
+Factor the DACL structural checks into validate_dacl(), extend them to
+validate each ACE against the DACL bounds, and use the shared validator
+before the chmod/chown rebuild paths.  parse_dacl() reuses the same
+validator so the read-side parser and write-side rewrite paths agree on
+what constitutes a well-formed incoming DACL.
+
+Fixes: bc3e9dd9d104 ("cifs: Change SIDs in ACEs while transferring file ownership.")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-6
+Assisted-by: Codex:gpt-5-4
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+[ renamed smb_acl/smb_ace/smb_sid/smb_ntsd to cifs_* and widened num_aces from u16 to u32 for 6.1's __le32 field ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/cifsacl.c |   95 ++++++++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 85 insertions(+), 10 deletions(-)
+
+--- a/fs/cifs/cifsacl.c
++++ b/fs/cifs/cifsacl.c
+@@ -753,6 +753,78 @@ static void dump_ace(struct cifs_ace *pa
+ }
+ #endif
++static int validate_dacl(struct cifs_acl *pdacl, char *end_of_acl)
++{
++      int i, ace_hdr_size, ace_size, min_ace_size;
++      u16 dacl_size;
++      u32 num_aces;
++      char *acl_base, *end_of_dacl;
++      struct cifs_ace *pace;
++
++      if (!pdacl)
++              return 0;
++
++      if (end_of_acl < (char *)pdacl + sizeof(struct cifs_acl)) {
++              cifs_dbg(VFS, "ACL too small to parse DACL\n");
++              return -EINVAL;
++      }
++
++      dacl_size = le16_to_cpu(pdacl->size);
++      if (dacl_size < sizeof(struct cifs_acl) ||
++          end_of_acl < (char *)pdacl + dacl_size) {
++              cifs_dbg(VFS, "ACL too small to parse DACL\n");
++              return -EINVAL;
++      }
++
++      num_aces = le32_to_cpu(pdacl->num_aces);
++      if (!num_aces)
++              return 0;
++
++      ace_hdr_size = offsetof(struct cifs_ace, sid) +
++              offsetof(struct cifs_sid, sub_auth);
++      min_ace_size = ace_hdr_size + sizeof(__le32);
++      if (num_aces > (dacl_size - sizeof(struct cifs_acl)) / min_ace_size) {
++              cifs_dbg(VFS, "ACL too small to parse DACL\n");
++              return -EINVAL;
++      }
++
++      end_of_dacl = (char *)pdacl + dacl_size;
++      acl_base = (char *)pdacl;
++      ace_size = sizeof(struct cifs_acl);
++
++      for (i = 0; i < num_aces; ++i) {
++              if (end_of_dacl - acl_base < ace_size) {
++                      cifs_dbg(VFS, "ACL too small to parse ACE\n");
++                      return -EINVAL;
++              }
++
++              pace = (struct cifs_ace *)(acl_base + ace_size);
++              acl_base = (char *)pace;
++
++              if (end_of_dacl - acl_base < ace_hdr_size ||
++                  pace->sid.num_subauth == 0 ||
++                  pace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES) {
++                      cifs_dbg(VFS, "ACL too small to parse ACE\n");
++                      return -EINVAL;
++              }
++
++              ace_size = ace_hdr_size + sizeof(__le32) * pace->sid.num_subauth;
++              if (end_of_dacl - acl_base < ace_size ||
++                  le16_to_cpu(pace->size) < ace_size) {
++                      cifs_dbg(VFS, "ACL too small to parse ACE\n");
++                      return -EINVAL;
++              }
++
++              ace_size = le16_to_cpu(pace->size);
++              if (end_of_dacl - acl_base < ace_size) {
++                      cifs_dbg(VFS, "ACL too small to parse ACE\n");
++                      return -EINVAL;
++              }
++      }
++
++      return 0;
++}
++
+ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
+                      struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
+                      struct cifs_fattr *fattr, bool mode_from_special_sid)
+@@ -760,7 +832,7 @@ static void parse_dacl(struct cifs_acl *
+       int i;
+       int num_aces = 0;
+       int acl_size;
+-      char *acl_base;
++      char *acl_base, *end_of_dacl;
+       struct cifs_ace **ppace;
+       /* BB need to add parm so we can store the SID BB */
+@@ -772,11 +844,8 @@ static void parse_dacl(struct cifs_acl *
+               return;
+       }
+-      /* validate that we do not go past end of acl */
+-      if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
+-              cifs_dbg(VFS, "ACL too small to parse DACL\n");
++      if (validate_dacl(pdacl, end_of_acl))
+               return;
+-      }
+       cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
+                le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
+@@ -787,6 +856,7 @@ static void parse_dacl(struct cifs_acl *
+          user/group/other have no permissions */
+       fattr->cf_mode &= ~(0777);
++      end_of_dacl = (char *)pdacl + le16_to_cpu(pdacl->size);
+       acl_base = (char *)pdacl;
+       acl_size = sizeof(struct cifs_acl);
+@@ -804,7 +874,7 @@ static void parse_dacl(struct cifs_acl *
+               for (i = 0; i < num_aces; ++i) {
+                       ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
+ #ifdef CONFIG_CIFS_DEBUG2
+-                      dump_ace(ppace[i], end_of_acl);
++                      dump_ace(ppace[i], end_of_dacl);
+ #endif
+                       if (mode_from_special_sid &&
+                           ppace[i]->sid.num_subauth >= 3 &&
+@@ -1263,10 +1333,9 @@ static int build_sec_desc(struct cifs_nt
+       dacloffset = le32_to_cpu(pntsd->dacloffset);
+       if (dacloffset) {
+               dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
+-              if (end_of_acl < (char *)dacl_ptr + le16_to_cpu(dacl_ptr->size)) {
+-                      cifs_dbg(VFS, "Server returned illegal ACL size\n");
+-                      return -EINVAL;
+-              }
++              rc = validate_dacl(dacl_ptr, end_of_acl);
++              if (rc)
++                      return rc;
+       }
+       owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
+@@ -1626,6 +1695,12 @@ id_mode_to_cifs_acl(struct inode *inode,
+               dacloffset = le32_to_cpu(pntsd->dacloffset);
+               if (dacloffset) {
+                       dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
++                      rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
++                      if (rc) {
++                              kfree(pntsd);
++                              cifs_put_tlink(tlink);
++                              return rc;
++                      }
+                       if (mode_from_sid)
+                               nsecdesclen +=
+                                       le32_to_cpu(dacl_ptr->num_aces) * sizeof(struct cifs_ace);
diff --git a/queue-5.15/spi-lantiq-ssc-fix-controller-deregistration.patch b/queue-5.15/spi-lantiq-ssc-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..49c20bd
--- /dev/null
@@ -0,0 +1,59 @@
+From stable+bounces-250012-greg=kroah.com@vger.kernel.org Wed May 20 21:28:28 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 20 May 2026 11:18:21 -0400
+Subject: spi: lantiq-ssc: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Hauke Mehrtens <hauke@hauke-m.de>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260520151821.3913367-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit b99206710d032c16b7f8b75e4bc18414d8e4b9f4 ]
+
+Make sure to deregister the controller before releasing underlying
+resources like clocks during driver unbind.
+
+Fixes: 17f84b793c01 ("spi: lantiq-ssc: add support for Lantiq SSC SPI controller")
+Cc: stable@vger.kernel.org     # 4.11
+Cc: Hauke Mehrtens <hauke@hauke-m.de>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260409120419.388546-17-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ adapted spi_controller/host naming to spi_master/master and preserved the int-returning remove() with trailing return 0 ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-lantiq-ssc.c |    8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-lantiq-ssc.c
++++ b/drivers/spi/spi-lantiq-ssc.c
+@@ -1003,7 +1003,7 @@ static int lantiq_ssc_probe(struct platf
+               "Lantiq SSC SPI controller (Rev %i, TXFS %u, RXFS %u, DMA %u)\n",
+               revision, spi->tx_fifo_size, spi->rx_fifo_size, supports_dma);
+-      err = devm_spi_register_master(dev, master);
++      err = spi_register_master(master);
+       if (err) {
+               dev_err(dev, "failed to register spi_master\n");
+               goto err_wq_destroy;
+@@ -1027,6 +1027,10 @@ static int lantiq_ssc_remove(struct plat
+ {
+       struct lantiq_ssc_spi *spi = platform_get_drvdata(pdev);
++      spi_master_get(spi->master);
++
++      spi_unregister_master(spi->master);
++
+       lantiq_ssc_writel(spi, 0, LTQ_SPI_IRNEN);
+       lantiq_ssc_writel(spi, 0, LTQ_SPI_CLC);
+       rx_fifo_flush(spi);
+@@ -1037,6 +1041,8 @@ static int lantiq_ssc_remove(struct plat
+       clk_disable_unprepare(spi->spi_clk);
+       clk_put(spi->fpi_clk);
++      spi_master_put(spi->master);
++
+       return 0;
+ }
diff --git a/queue-5.15/spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch b/queue-5.15/spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch
new file mode 100644 (file)
index 0000000..f27740a
--- /dev/null
@@ -0,0 +1,47 @@
+From stable+bounces-259405-greg=kroah.com@vger.kernel.org Mon Jun  1 07:23:23 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 May 2026 21:51:42 -0400
+Subject: spi: qup: fix error pointer deref after DMA setup failure
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260601015142.161971-2-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit a7e8f3efd50a165ba0189f6dc57f7e51a7d149db ]
+
+The driver falls back to PIO mode if DMA setup fails during probe.
+
+Make sure to the clear the DMA channel pointers on setup failure to
+avoid dereferencing an error pointer (or attempting to release a channel
+a second time) on later probe errors or driver unbind.
+
+This issue was flagged by Sashiko when reviewing a devres allocation
+conversion patch.
+
+Fixes: 612762e82ae6 ("spi: qup: Add DMA capabilities")
+Link: https://sashiko.dev/#/patchset/20260505072909.618363-1-johan%40kernel.org?part=4
+Cc: stable@vger.kernel.org     # 4.1
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260512074334.914735-1-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-qup.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/spi/spi-qup.c
++++ b/drivers/spi/spi-qup.c
+@@ -969,8 +969,11 @@ static int spi_qup_init_dma(struct spi_c
+ err:
+       dma_release_channel(host->dma_tx);
++      host->dma_tx = NULL;
+ err_tx:
+       dma_release_channel(host->dma_rx);
++      host->dma_rx = NULL;
++
+       return ret;
+ }
diff --git a/queue-5.15/spi-qup-switch-to-use-modern-name.patch b/queue-5.15/spi-qup-switch-to-use-modern-name.patch
new file mode 100644 (file)
index 0000000..be0b459
--- /dev/null
@@ -0,0 +1,459 @@
+From stable+bounces-259406-greg=kroah.com@vger.kernel.org Mon Jun  1 07:23:36 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 May 2026 21:51:41 -0400
+Subject: spi: qup: switch to use modern name
+To: stable@vger.kernel.org
+Cc: Yang Yingliang <yangyingliang@huawei.com>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260601015142.161971-1-sashal@kernel.org>
+
+From: Yang Yingliang <yangyingliang@huawei.com>
+
+[ Upstream commit 597442ff4f6226206b7cc28b86eb2be0ae9c6418 ]
+
+Change legacy name master to modern name host or controller.
+
+No functional changed.
+
+Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
+Link: https://lore.kernel.org/r/20230818093154.1183529-10-yangyingliang@huawei.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: a7e8f3efd50a ("spi: qup: fix error pointer deref after DMA setup failure")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-qup.c |  164 +++++++++++++++++++++++++-------------------------
+ 1 file changed, 82 insertions(+), 82 deletions(-)
+
+--- a/drivers/spi/spi-qup.c
++++ b/drivers/spi/spi-qup.c
+@@ -386,20 +386,20 @@ static void spi_qup_write(struct spi_qup
+       } while (remainder);
+ }
+-static int spi_qup_prep_sg(struct spi_master *master, struct scatterlist *sgl,
++static int spi_qup_prep_sg(struct spi_controller *host, struct scatterlist *sgl,
+                          unsigned int nents, enum dma_transfer_direction dir,
+                          dma_async_tx_callback callback)
+ {
+-      struct spi_qup *qup = spi_master_get_devdata(master);
++      struct spi_qup *qup = spi_controller_get_devdata(host);
+       unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE;
+       struct dma_async_tx_descriptor *desc;
+       struct dma_chan *chan;
+       dma_cookie_t cookie;
+       if (dir == DMA_MEM_TO_DEV)
+-              chan = master->dma_tx;
++              chan = host->dma_tx;
+       else
+-              chan = master->dma_rx;
++              chan = host->dma_rx;
+       desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
+       if (IS_ERR_OR_NULL(desc))
+@@ -413,13 +413,13 @@ static int spi_qup_prep_sg(struct spi_ma
+       return dma_submit_error(cookie);
+ }
+-static void spi_qup_dma_terminate(struct spi_master *master,
++static void spi_qup_dma_terminate(struct spi_controller *host,
+                                 struct spi_transfer *xfer)
+ {
+       if (xfer->tx_buf)
+-              dmaengine_terminate_all(master->dma_tx);
++              dmaengine_terminate_all(host->dma_tx);
+       if (xfer->rx_buf)
+-              dmaengine_terminate_all(master->dma_rx);
++              dmaengine_terminate_all(host->dma_rx);
+ }
+ static u32 spi_qup_sgl_get_nents_len(struct scatterlist *sgl, u32 max,
+@@ -446,8 +446,8 @@ static int spi_qup_do_dma(struct spi_dev
+                         unsigned long timeout)
+ {
+       dma_async_tx_callback rx_done = NULL, tx_done = NULL;
+-      struct spi_master *master = spi->master;
+-      struct spi_qup *qup = spi_master_get_devdata(master);
++      struct spi_controller *host = spi->controller;
++      struct spi_qup *qup = spi_controller_get_devdata(host);
+       struct scatterlist *tx_sgl, *rx_sgl;
+       int ret;
+@@ -482,20 +482,20 @@ static int spi_qup_do_dma(struct spi_dev
+                       return ret;
+               }
+               if (rx_sgl) {
+-                      ret = spi_qup_prep_sg(master, rx_sgl, rx_nents,
++                      ret = spi_qup_prep_sg(host, rx_sgl, rx_nents,
+                                             DMA_DEV_TO_MEM, rx_done);
+                       if (ret)
+                               return ret;
+-                      dma_async_issue_pending(master->dma_rx);
++                      dma_async_issue_pending(host->dma_rx);
+               }
+               if (tx_sgl) {
+-                      ret = spi_qup_prep_sg(master, tx_sgl, tx_nents,
++                      ret = spi_qup_prep_sg(host, tx_sgl, tx_nents,
+                                             DMA_MEM_TO_DEV, tx_done);
+                       if (ret)
+                               return ret;
+-                      dma_async_issue_pending(master->dma_tx);
++                      dma_async_issue_pending(host->dma_tx);
+               }
+               if (!wait_for_completion_timeout(&qup->done, timeout))
+@@ -514,8 +514,8 @@ static int spi_qup_do_dma(struct spi_dev
+ static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
+                         unsigned long timeout)
+ {
+-      struct spi_master *master = spi->master;
+-      struct spi_qup *qup = spi_master_get_devdata(master);
++      struct spi_controller *host = spi->controller;
++      struct spi_qup *qup = spi_controller_get_devdata(host);
+       int ret, n_words, iterations, offset = 0;
+       n_words = qup->n_words;
+@@ -660,7 +660,7 @@ static irqreturn_t spi_qup_qup_irq(int i
+ /* set clock freq ... bits per word, determine mode */
+ static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer)
+ {
+-      struct spi_qup *controller = spi_master_get_devdata(spi->master);
++      struct spi_qup *controller = spi_controller_get_devdata(spi->controller);
+       int ret;
+       if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
+@@ -681,9 +681,9 @@ static int spi_qup_io_prep(struct spi_de
+       if (controller->n_words <= (controller->in_fifo_sz / sizeof(u32)))
+               controller->mode = QUP_IO_M_MODE_FIFO;
+-      else if (spi->master->can_dma &&
+-               spi->master->can_dma(spi->master, spi, xfer) &&
+-               spi->master->cur_msg_mapped)
++      else if (spi->controller->can_dma &&
++               spi->controller->can_dma(spi->controller, spi, xfer) &&
++               spi->controller->cur_msg_mapped)
+               controller->mode = QUP_IO_M_MODE_BAM;
+       else
+               controller->mode = QUP_IO_M_MODE_BLOCK;
+@@ -694,7 +694,7 @@ static int spi_qup_io_prep(struct spi_de
+ /* prep qup for another spi transaction of specific type */
+ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
+ {
+-      struct spi_qup *controller = spi_master_get_devdata(spi->master);
++      struct spi_qup *controller = spi_controller_get_devdata(spi->controller);
+       u32 config, iomode, control;
+       unsigned long flags;
+@@ -842,11 +842,11 @@ static int spi_qup_io_config(struct spi_
+       return 0;
+ }
+-static int spi_qup_transfer_one(struct spi_master *master,
++static int spi_qup_transfer_one(struct spi_controller *host,
+                             struct spi_device *spi,
+                             struct spi_transfer *xfer)
+ {
+-      struct spi_qup *controller = spi_master_get_devdata(master);
++      struct spi_qup *controller = spi_controller_get_devdata(host);
+       unsigned long timeout, flags;
+       int ret;
+@@ -880,21 +880,21 @@ static int spi_qup_transfer_one(struct s
+       spin_unlock_irqrestore(&controller->lock, flags);
+       if (ret && spi_qup_is_dma_xfer(controller->mode))
+-              spi_qup_dma_terminate(master, xfer);
++              spi_qup_dma_terminate(host, xfer);
+       return ret;
+ }
+-static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi,
++static bool spi_qup_can_dma(struct spi_controller *host, struct spi_device *spi,
+                           struct spi_transfer *xfer)
+ {
+-      struct spi_qup *qup = spi_master_get_devdata(master);
++      struct spi_qup *qup = spi_controller_get_devdata(host);
+       size_t dma_align = dma_get_cache_alignment();
+       int n_words;
+       if (xfer->rx_buf) {
+               if (!IS_ALIGNED((size_t)xfer->rx_buf, dma_align) ||
+-                  IS_ERR_OR_NULL(master->dma_rx))
++                  IS_ERR_OR_NULL(host->dma_rx))
+                       return false;
+               if (qup->qup_v1 && (xfer->len % qup->in_blk_sz))
+                       return false;
+@@ -902,7 +902,7 @@ static bool spi_qup_can_dma(struct spi_m
+       if (xfer->tx_buf) {
+               if (!IS_ALIGNED((size_t)xfer->tx_buf, dma_align) ||
+-                  IS_ERR_OR_NULL(master->dma_tx))
++                  IS_ERR_OR_NULL(host->dma_tx))
+                       return false;
+               if (qup->qup_v1 && (xfer->len % qup->out_blk_sz))
+                       return false;
+@@ -915,30 +915,30 @@ static bool spi_qup_can_dma(struct spi_m
+       return true;
+ }
+-static void spi_qup_release_dma(struct spi_master *master)
++static void spi_qup_release_dma(struct spi_controller *host)
+ {
+-      if (!IS_ERR_OR_NULL(master->dma_rx))
+-              dma_release_channel(master->dma_rx);
+-      if (!IS_ERR_OR_NULL(master->dma_tx))
+-              dma_release_channel(master->dma_tx);
++      if (!IS_ERR_OR_NULL(host->dma_rx))
++              dma_release_channel(host->dma_rx);
++      if (!IS_ERR_OR_NULL(host->dma_tx))
++              dma_release_channel(host->dma_tx);
+ }
+-static int spi_qup_init_dma(struct spi_master *master, resource_size_t base)
++static int spi_qup_init_dma(struct spi_controller *host, resource_size_t base)
+ {
+-      struct spi_qup *spi = spi_master_get_devdata(master);
++      struct spi_qup *spi = spi_controller_get_devdata(host);
+       struct dma_slave_config *rx_conf = &spi->rx_conf,
+                               *tx_conf = &spi->tx_conf;
+       struct device *dev = spi->dev;
+       int ret;
+       /* allocate dma resources, if available */
+-      master->dma_rx = dma_request_chan(dev, "rx");
+-      if (IS_ERR(master->dma_rx))
+-              return PTR_ERR(master->dma_rx);
+-
+-      master->dma_tx = dma_request_chan(dev, "tx");
+-      if (IS_ERR(master->dma_tx)) {
+-              ret = PTR_ERR(master->dma_tx);
++      host->dma_rx = dma_request_chan(dev, "rx");
++      if (IS_ERR(host->dma_rx))
++              return PTR_ERR(host->dma_rx);
++
++      host->dma_tx = dma_request_chan(dev, "tx");
++      if (IS_ERR(host->dma_tx)) {
++              ret = PTR_ERR(host->dma_tx);
+               goto err_tx;
+       }
+@@ -953,13 +953,13 @@ static int spi_qup_init_dma(struct spi_m
+       tx_conf->dst_addr = base + QUP_OUTPUT_FIFO;
+       tx_conf->dst_maxburst = spi->out_blk_sz;
+-      ret = dmaengine_slave_config(master->dma_rx, rx_conf);
++      ret = dmaengine_slave_config(host->dma_rx, rx_conf);
+       if (ret) {
+               dev_err(dev, "failed to configure RX channel\n");
+               goto err;
+       }
+-      ret = dmaengine_slave_config(master->dma_tx, tx_conf);
++      ret = dmaengine_slave_config(host->dma_tx, tx_conf);
+       if (ret) {
+               dev_err(dev, "failed to configure TX channel\n");
+               goto err;
+@@ -968,9 +968,9 @@ static int spi_qup_init_dma(struct spi_m
+       return 0;
+ err:
+-      dma_release_channel(master->dma_tx);
++      dma_release_channel(host->dma_tx);
+ err_tx:
+-      dma_release_channel(master->dma_rx);
++      dma_release_channel(host->dma_rx);
+       return ret;
+ }
+@@ -980,7 +980,7 @@ static void spi_qup_set_cs(struct spi_de
+       u32 spi_ioc;
+       u32 spi_ioc_orig;
+-      controller = spi_master_get_devdata(spi->master);
++      controller = spi_controller_get_devdata(spi->controller);
+       spi_ioc = readl_relaxed(controller->base + SPI_IO_CONTROL);
+       spi_ioc_orig = spi_ioc;
+       if (!val)
+@@ -994,7 +994,7 @@ static void spi_qup_set_cs(struct spi_de
+ static int spi_qup_probe(struct platform_device *pdev)
+ {
+-      struct spi_master *master;
++      struct spi_controller *host;
+       struct clk *iclk, *cclk;
+       struct spi_qup *controller;
+       struct resource *res;
+@@ -1030,32 +1030,32 @@ static int spi_qup_probe(struct platform
+               return -ENXIO;
+       }
+-      master = spi_alloc_master(dev, sizeof(struct spi_qup));
+-      if (!master) {
+-              dev_err(dev, "cannot allocate master\n");
++      host = spi_alloc_master(dev, sizeof(struct spi_qup));
++      if (!host) {
++              dev_err(dev, "cannot allocate host\n");
+               return -ENOMEM;
+       }
+       /* use num-cs unless not present or out of range */
+       if (of_property_read_u32(dev->of_node, "num-cs", &num_cs) ||
+           num_cs > SPI_NUM_CHIPSELECTS)
+-              master->num_chipselect = SPI_NUM_CHIPSELECTS;
++              host->num_chipselect = SPI_NUM_CHIPSELECTS;
+       else
+-              master->num_chipselect = num_cs;
++              host->num_chipselect = num_cs;
+-      master->bus_num = pdev->id;
+-      master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
+-      master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+-      master->max_speed_hz = max_freq;
+-      master->transfer_one = spi_qup_transfer_one;
+-      master->dev.of_node = pdev->dev.of_node;
+-      master->auto_runtime_pm = true;
+-      master->dma_alignment = dma_get_cache_alignment();
+-      master->max_dma_len = SPI_MAX_XFER;
++      host->bus_num = pdev->id;
++      host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
++      host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
++      host->max_speed_hz = max_freq;
++      host->transfer_one = spi_qup_transfer_one;
++      host->dev.of_node = pdev->dev.of_node;
++      host->auto_runtime_pm = true;
++      host->dma_alignment = dma_get_cache_alignment();
++      host->max_dma_len = SPI_MAX_XFER;
+-      platform_set_drvdata(pdev, master);
++      platform_set_drvdata(pdev, host);
+-      controller = spi_master_get_devdata(master);
++      controller = spi_controller_get_devdata(host);
+       controller->dev = dev;
+       controller->base = base;
+@@ -1063,16 +1063,16 @@ static int spi_qup_probe(struct platform
+       controller->cclk = cclk;
+       controller->irq = irq;
+-      ret = spi_qup_init_dma(master, res->start);
++      ret = spi_qup_init_dma(host, res->start);
+       if (ret == -EPROBE_DEFER)
+               goto error;
+       else if (!ret)
+-              master->can_dma = spi_qup_can_dma;
++              host->can_dma = spi_qup_can_dma;
+       controller->qup_v1 = (uintptr_t)of_device_get_match_data(dev);
+       if (!controller->qup_v1)
+-              master->set_cs = spi_qup_set_cs;
++              host->set_cs = spi_qup_set_cs;
+       spin_lock_init(&controller->lock);
+       init_completion(&controller->done);
+@@ -1150,7 +1150,7 @@ static int spi_qup_probe(struct platform
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+-      ret = devm_spi_register_master(dev, master);
++      ret = devm_spi_register_controller(dev, host);
+       if (ret)
+               goto disable_pm;
+@@ -1162,17 +1162,17 @@ error_clk:
+       clk_disable_unprepare(cclk);
+       clk_disable_unprepare(iclk);
+ error_dma:
+-      spi_qup_release_dma(master);
++      spi_qup_release_dma(host);
+ error:
+-      spi_master_put(master);
++      spi_controller_put(host);
+       return ret;
+ }
+ #ifdef CONFIG_PM
+ static int spi_qup_pm_suspend_runtime(struct device *device)
+ {
+-      struct spi_master *master = dev_get_drvdata(device);
+-      struct spi_qup *controller = spi_master_get_devdata(master);
++      struct spi_controller *host = dev_get_drvdata(device);
++      struct spi_qup *controller = spi_controller_get_devdata(host);
+       u32 config;
+       /* Enable clocks auto gaiting */
+@@ -1188,8 +1188,8 @@ static int spi_qup_pm_suspend_runtime(st
+ static int spi_qup_pm_resume_runtime(struct device *device)
+ {
+-      struct spi_master *master = dev_get_drvdata(device);
+-      struct spi_qup *controller = spi_master_get_devdata(master);
++      struct spi_controller *host = dev_get_drvdata(device);
++      struct spi_qup *controller = spi_controller_get_devdata(host);
+       u32 config;
+       int ret;
+@@ -1214,8 +1214,8 @@ static int spi_qup_pm_resume_runtime(str
+ #ifdef CONFIG_PM_SLEEP
+ static int spi_qup_suspend(struct device *device)
+ {
+-      struct spi_master *master = dev_get_drvdata(device);
+-      struct spi_qup *controller = spi_master_get_devdata(master);
++      struct spi_controller *host = dev_get_drvdata(device);
++      struct spi_qup *controller = spi_controller_get_devdata(host);
+       int ret;
+       if (pm_runtime_suspended(device)) {
+@@ -1223,7 +1223,7 @@ static int spi_qup_suspend(struct device
+               if (ret)
+                       return ret;
+       }
+-      ret = spi_master_suspend(master);
++      ret = spi_controller_suspend(host);
+       if (ret)
+               return ret;
+@@ -1238,8 +1238,8 @@ static int spi_qup_suspend(struct device
+ static int spi_qup_resume(struct device *device)
+ {
+-      struct spi_master *master = dev_get_drvdata(device);
+-      struct spi_qup *controller = spi_master_get_devdata(master);
++      struct spi_controller *host = dev_get_drvdata(device);
++      struct spi_qup *controller = spi_controller_get_devdata(host);
+       int ret;
+       ret = clk_prepare_enable(controller->iclk);
+@@ -1256,7 +1256,7 @@ static int spi_qup_resume(struct device
+       if (ret)
+               goto disable_clk;
+-      ret = spi_master_resume(master);
++      ret = spi_controller_resume(host);
+       if (ret)
+               goto disable_clk;
+@@ -1271,8 +1271,8 @@ disable_clk:
+ static int spi_qup_remove(struct platform_device *pdev)
+ {
+-      struct spi_master *master = dev_get_drvdata(&pdev->dev);
+-      struct spi_qup *controller = spi_master_get_devdata(master);
++      struct spi_controller *host = dev_get_drvdata(&pdev->dev);
++      struct spi_qup *controller = spi_controller_get_devdata(host);
+       int ret;
+       ret = pm_runtime_get_sync(&pdev->dev);
+@@ -1290,7 +1290,7 @@ static int spi_qup_remove(struct platfor
+                        ERR_PTR(ret));
+       }
+-      spi_qup_release_dma(master);
++      spi_qup_release_dma(host);
+       pm_runtime_put_noidle(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
diff --git a/queue-5.15/spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch b/queue-5.15/spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch
new file mode 100644 (file)
index 0000000..2cdcda2
--- /dev/null
@@ -0,0 +1,76 @@
+From stable+bounces-247023-greg=kroah.com@vger.kernel.org Thu May 14 01:04:22 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 15:34:13 -0400
+Subject: spi: spi-ti-qspi: Convert to platform remove callback returning void
+To: stable@vger.kernel.org
+Cc: "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>, "Mark Brown" <broonie@kernel.org>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260513193414.3938310-1-sashal@kernel.org>
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit 2f2802d1a59d79a3d00cb429841db502c2bbc3df ]
+
+The .remove() callback for a platform driver returns an int which makes
+many driver authors wrongly assume it's possible to do error handling by
+returning an error code. However the value returned is ignored (apart
+from emitting a warning) and this typically results in resource leaks.
+
+To improve here there is a quest to make the remove callback return
+void. In the first step of this quest all drivers are converted to
+.remove_new(), which already returns void. Eventually after all drivers
+are converted, .remove_new() will be renamed to .remove().
+
+Add an error message to the error path that returned an error before to
+replace the core's error message with more information. Apart from the
+different wording of the error message, this patch doesn't introduce a
+semantic difference.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Link: https://lore.kernel.org/r/20231105172649.3738556-2-u.kleine-koenig@pengutronix.de
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: 0c18a1bacbb1 ("spi: ti-qspi: fix controller deregistration")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-ti-qspi.c |   13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+--- a/drivers/spi/spi-ti-qspi.c
++++ b/drivers/spi/spi-ti-qspi.c
+@@ -907,21 +907,22 @@ free_master:
+       return ret;
+ }
+-static int ti_qspi_remove(struct platform_device *pdev)
++static void ti_qspi_remove(struct platform_device *pdev)
+ {
+       struct ti_qspi *qspi = platform_get_drvdata(pdev);
+       int rc;
+       rc = spi_master_suspend(qspi->master);
+-      if (rc)
+-              return rc;
++      if (rc) {
++              dev_alert(&pdev->dev, "spi_master_suspend() failed (%pe)\n",
++                        ERR_PTR(rc));
++              return;
++      }
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       ti_qspi_dma_cleanup(qspi);
+-
+-      return 0;
+ }
+ static const struct dev_pm_ops ti_qspi_pm_ops = {
+@@ -930,7 +931,7 @@ static const struct dev_pm_ops ti_qspi_p
+ static struct platform_driver ti_qspi_driver = {
+       .probe  = ti_qspi_probe,
+-      .remove = ti_qspi_remove,
++      .remove_new = ti_qspi_remove,
+       .driver = {
+               .name   = "ti-qspi",
+               .pm =   &ti_qspi_pm_ops,
diff --git a/queue-5.15/spi-st-ssc4-fix-controller-deregistration.patch b/queue-5.15/spi-st-ssc4-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..72fc56b
--- /dev/null
@@ -0,0 +1,56 @@
+From stable+bounces-249944-greg=kroah.com@vger.kernel.org Wed May 20 20:21:36 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 20 May 2026 10:27:57 -0400
+Subject: spi: st-ssc4: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Lee Jones <lee@kernel.org>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260520142757.3647294-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit 19857374010d06ca6a2f7c2c53464122eb804df0 ]
+
+Make sure to deregister the controller before disabling underlying
+resources like clocks during driver unbind.
+
+Fixes: 9e862375c542 ("spi: Add new driver for STMicroelectronics' SPI Controller")
+Cc: stable@vger.kernel.org     # 4.0
+Cc: Lee Jones <lee@kernel.org>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-18-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ changed spi_controller/host API calls to spi_master/master equivalents ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-st-ssc4.c |    8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-st-ssc4.c
++++ b/drivers/spi/spi-st-ssc4.c
+@@ -372,7 +372,7 @@ static int spi_st_probe(struct platform_
+       platform_set_drvdata(pdev, master);
+-      ret = devm_spi_register_master(&pdev->dev, master);
++      ret = spi_register_master(master);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register master\n");
+               goto rpm_disable;
+@@ -394,10 +394,16 @@ static int spi_st_remove(struct platform
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct spi_st *spi_st = spi_master_get_devdata(master);
++      spi_master_get(master);
++
++      spi_unregister_master(master);
++
+       pm_runtime_disable(&pdev->dev);
+       clk_disable_unprepare(spi_st->clk);
++      spi_master_put(master);
++
+       pinctrl_pm_select_sleep_state(&pdev->dev);
+       return 0;
diff --git a/queue-5.15/spi-sun4i-fix-controller-deregistration.patch b/queue-5.15/spi-sun4i-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..4cb3a34
--- /dev/null
@@ -0,0 +1,56 @@
+From stable+bounces-247010-greg=kroah.com@vger.kernel.org Wed May 13 23:59:30 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 14:20:50 -0400
+Subject: spi: sun4i: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Maxime Ripard <mripard@kernel.org>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260513182050.3919910-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit 42108a2f03e0fdeabe9d02d085bdb058baa1189f ]
+
+Make sure to deregister the controller before disabling underlying
+resources like clocks during driver unbind.
+
+Fixes: b5f6517948cc ("spi: sunxi: Add Allwinner A10 SPI controller driver")
+Cc: stable@vger.kernel.org     # 3.15
+Cc: Maxime Ripard <mripard@kernel.org>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-19-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ renamed `host`/`spi_controller` to `master`/`spi_master` and kept `int` return type with `return 0` in remove ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-sun4i.c |   10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-sun4i.c
++++ b/drivers/spi/spi-sun4i.c
+@@ -503,7 +503,7 @@ static int sun4i_spi_probe(struct platfo
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_idle(&pdev->dev);
+-      ret = devm_spi_register_master(&pdev->dev, master);
++      ret = spi_register_master(master);
+       if (ret) {
+               dev_err(&pdev->dev, "cannot register SPI master\n");
+               goto err_pm_disable;
+@@ -521,8 +521,16 @@ err_free_master:
+ static int sun4i_spi_remove(struct platform_device *pdev)
+ {
++      struct spi_master *master = platform_get_drvdata(pdev);
++
++      spi_master_get(master);
++
++      spi_unregister_master(master);
++
+       pm_runtime_force_suspend(&pdev->dev);
++      spi_master_put(master);
++
+       return 0;
+ }
diff --git a/queue-5.15/spi-sun6i-fix-controller-deregistration.patch b/queue-5.15/spi-sun6i-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..74d1568
--- /dev/null
@@ -0,0 +1,59 @@
+From stable+bounces-247096-greg=kroah.com@vger.kernel.org Thu May 14 09:44:22 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 May 2026 00:14:12 -0400
+Subject: spi: sun6i: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Maxime Ripard <mripard@kernel.org>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260514041412.4189652-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit d874a1c33aee0d88fb4ba2f8aeadaa9f1965209a ]
+
+Make sure to deregister the controller before disabling underlying
+resources like clocks during driver unbind.
+
+Fixes: 3558fe900e8a ("spi: sunxi: Add Allwinner A31 SPI controller driver")
+Cc: stable@vger.kernel.org     # 3.15
+Cc: Maxime Ripard <mripard@kernel.org>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-20-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ renamed spi_controller APIs to spi_master equivalents and kept int return type for sun6i_spi_remove ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-sun6i.c |    9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-sun6i.c
++++ b/drivers/spi/spi-sun6i.c
+@@ -688,7 +688,7 @@ static int sun6i_spi_probe(struct platfo
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+-      ret = devm_spi_register_master(&pdev->dev, master);
++      ret = spi_register_master(master);
+       if (ret) {
+               dev_err(&pdev->dev, "cannot register SPI master\n");
+               goto err_pm_disable;
+@@ -714,12 +714,19 @@ static int sun6i_spi_remove(struct platf
+ {
+       struct spi_master *master = platform_get_drvdata(pdev);
++      spi_master_get(master);
++
++      spi_unregister_master(master);
++
+       pm_runtime_force_suspend(&pdev->dev);
+       if (master->dma_tx)
+               dma_release_channel(master->dma_tx);
+       if (master->dma_rx)
+               dma_release_channel(master->dma_rx);
++
++      spi_master_put(master);
++
+       return 0;
+ }
diff --git a/queue-5.15/spi-syncuacer-fix-controller-deregistration.patch b/queue-5.15/spi-syncuacer-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..888b6aa
--- /dev/null
@@ -0,0 +1,56 @@
+From stable+bounces-247009-greg=kroah.com@vger.kernel.org Wed May 13 23:58:58 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 14:20:37 -0400
+Subject: spi: syncuacer: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Masahisa Kojima <masahisa.kojima@linaro.org>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260513182037.3918900-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit 75d849c3452e9611de031db45b3149ba9a99035f ]
+
+Make sure to deregister the controller before disabling underlying
+resources like clocks during driver unbind.
+
+Fixes: b0823ee35cf9 ("spi: Add spi driver for Socionext SynQuacer platform")
+Cc: stable@vger.kernel.org     # 5.3
+Cc: Masahisa Kojima <masahisa.kojima@linaro.org>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-21-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ renamed spi_controller/host to spi_master/master and kept int return type with `return 0;` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-synquacer.c |    8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-synquacer.c
++++ b/drivers/spi/spi-synquacer.c
+@@ -719,7 +719,7 @@ static int synquacer_spi_probe(struct pl
+       pm_runtime_set_active(sspi->dev);
+       pm_runtime_enable(sspi->dev);
+-      ret = devm_spi_register_master(sspi->dev, master);
++      ret = spi_register_master(master);
+       if (ret)
+               goto disable_pm;
+@@ -740,10 +740,16 @@ static int synquacer_spi_remove(struct p
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct synquacer_spi *sspi = spi_master_get_devdata(master);
++      spi_master_get(master);
++
++      spi_unregister_master(master);
++
+       pm_runtime_disable(sspi->dev);
+       clk_disable_unprepare(sspi->clk);
++      spi_master_put(master);
++
+       return 0;
+ }
diff --git a/queue-5.15/spi-tegra114-fix-controller-deregistration.patch b/queue-5.15/spi-tegra114-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..df1aa69
--- /dev/null
@@ -0,0 +1,59 @@
+From stable+bounces-247179-greg=kroah.com@vger.kernel.org Thu May 14 17:28:26 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 May 2026 07:58:05 -0400
+Subject: spi: tegra114: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Jingoo Han <jg1.han@samsung.com>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260514115805.188807-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit 9c9c27ff2058142d8f800de3186d6864184958de ]
+
+Make sure to deregister the controller before disabling underlying
+resources like clocks during driver unbind.
+
+Fixes: 5c8096439600 ("spi: tegra114: use devm_spi_register_master()")
+Cc: stable@vger.kernel.org     # 3.13
+Cc: Jingoo Han <jg1.han@samsung.com>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-22-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ renamed spi_controller/host APIs to spi_master/master equivalents and placed spi_master_put() before the existing return 0 in remove ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-tegra114.c |    8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-tegra114.c
++++ b/drivers/spi/spi-tegra114.c
+@@ -1417,7 +1417,7 @@ static int tegra_spi_probe(struct platfo
+       }
+       master->dev.of_node = pdev->dev.of_node;
+-      ret = devm_spi_register_master(&pdev->dev, master);
++      ret = spi_register_master(master);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "can not register to master err %d\n", ret);
+               goto exit_free_irq;
+@@ -1443,6 +1443,10 @@ static int tegra_spi_remove(struct platf
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct tegra_spi_data   *tspi = spi_master_get_devdata(master);
++      spi_master_get(master);
++
++      spi_unregister_master(master);
++
+       free_irq(tspi->irq, tspi);
+       if (tspi->tx_dma_chan)
+@@ -1455,6 +1459,8 @@ static int tegra_spi_remove(struct platf
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               tegra_spi_runtime_suspend(&pdev->dev);
++      spi_master_put(master);
++
+       return 0;
+ }
diff --git a/queue-5.15/spi-tegra20-sflash-fix-controller-deregistration.patch b/queue-5.15/spi-tegra20-sflash-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..6620c97
--- /dev/null
@@ -0,0 +1,58 @@
+From stable+bounces-247180-greg=kroah.com@vger.kernel.org Thu May 14 17:28:58 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 May 2026 07:58:49 -0400
+Subject: spi: tegra20-sflash: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Jingoo Han <jg1.han@samsung.com>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260514115849.189593-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit ad7310e983327f939dd6c4e801eab13238992572 ]
+
+Make sure to deregister the controller before disabling underlying
+resources like clocks during driver unbind.
+
+Fixes: f12f7318c44a ("spi: tegra20-sflash: use devm_spi_register_master()")
+Cc: stable@vger.kernel.org     # 3.13
+Cc: Jingoo Han <jg1.han@samsung.com>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-23-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ renamed spi_controller/host APIs to spi_master/master equivalents and switched devm_spi_register_master to spi_register_master ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-tegra20-sflash.c |    8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-tegra20-sflash.c
++++ b/drivers/spi/spi-tegra20-sflash.c
+@@ -507,7 +507,7 @@ static int tegra_sflash_probe(struct pla
+       pm_runtime_put(&pdev->dev);
+       master->dev.of_node = pdev->dev.of_node;
+-      ret = devm_spi_register_master(&pdev->dev, master);
++      ret = spi_register_master(master);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "can not register to master err %d\n", ret);
+               goto exit_pm_disable;
+@@ -530,12 +530,18 @@ static int tegra_sflash_remove(struct pl
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct tegra_sflash_data        *tsd = spi_master_get_devdata(master);
++      spi_master_get(master);
++
++      spi_unregister_master(master);
++
+       free_irq(tsd->irq, tsd);
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               tegra_sflash_runtime_suspend(&pdev->dev);
++      spi_master_put(master);
++
+       return 0;
+ }
diff --git a/queue-5.15/spi-ti-qspi-fix-controller-deregistration.patch b/queue-5.15/spi-ti-qspi-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..9b8acee
--- /dev/null
@@ -0,0 +1,70 @@
+From stable+bounces-247029-greg=kroah.com@vger.kernel.org Thu May 14 01:05:04 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 15:34:14 -0400
+Subject: spi: ti-qspi: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Sebastian Andrzej Siewior <bigeasy@linutronix.de>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260513193414.3938310-2-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit 0c18a1bacbb1d8b8aa34d3d004a2cb8226c8b1ea ]
+
+Make sure to deregister the controller before disabling underlying
+resources like clocks during driver unbind.
+
+Note that the controller is suspended before disabling and releasing
+resources since commit 3ac066e2227c ("spi: spi-ti-qspi: Suspend the
+queue before removing the device") which avoids issues like unclocked
+accesses but prevents SPI device drivers from doing I/O during
+deregistration.
+
+Fixes: 3b3a80019ff1 ("spi: ti-qspi: one only one interrupt handler")
+Cc: stable@vger.kernel.org     # 3.13
+Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-24-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ renamed spi_controller_* API calls to legacy spi_master_* equivalents and qspi->host to qspi->master ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-ti-qspi.c |   14 ++++++--------
+ 1 file changed, 6 insertions(+), 8 deletions(-)
+
+--- a/drivers/spi/spi-ti-qspi.c
++++ b/drivers/spi/spi-ti-qspi.c
+@@ -895,7 +895,7 @@ no_dma:
+       qspi->mmap_enabled = false;
+       qspi->current_cs = -1;
+-      ret = devm_spi_register_master(&pdev->dev, master);
++      ret = spi_register_master(master);
+       if (!ret)
+               return 0;
+@@ -910,19 +910,17 @@ free_master:
+ static void ti_qspi_remove(struct platform_device *pdev)
+ {
+       struct ti_qspi *qspi = platform_get_drvdata(pdev);
+-      int rc;
+-      rc = spi_master_suspend(qspi->master);
+-      if (rc) {
+-              dev_alert(&pdev->dev, "spi_master_suspend() failed (%pe)\n",
+-                        ERR_PTR(rc));
+-              return;
+-      }
++      spi_master_get(qspi->master);
++
++      spi_unregister_master(qspi->master);
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       ti_qspi_dma_cleanup(qspi);
++
++      spi_master_put(qspi->master);
+ }
+ static const struct dev_pm_ops ti_qspi_pm_ops = {
diff --git a/queue-5.15/spi-topcliff-pch-convert-to-platform-remove-callback-returning-void.patch b/queue-5.15/spi-topcliff-pch-convert-to-platform-remove-callback-returning-void.patch
new file mode 100644 (file)
index 0000000..2531a1b
--- /dev/null
@@ -0,0 +1,62 @@
+From stable+bounces-247738-greg=kroah.com@vger.kernel.org Fri May 15 18:06:53 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 May 2026 08:15:24 -0400
+Subject: spi: topcliff-pch: Convert to platform remove callback returning void
+To: stable@vger.kernel.org
+Cc: "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>, "Mark Brown" <broonie@kernel.org>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260515121525.3130058-1-sashal@kernel.org>
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit b082694f18bdff807b42a3bccc62c3a524168f23 ]
+
+The .remove() callback for a platform driver returns an int which makes
+many driver authors wrongly assume it's possible to do error handling by
+returning an error code. However the value returned is (mostly) ignored
+and this typically results in resource leaks. To improve here there is a
+quest to make the remove callback return void. In the first step of this
+quest all drivers are converted to .remove_new() which already returns
+void.
+
+Trivially convert this driver from always returning zero in the remove
+callback to the void returning variant.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Link: https://lore.kernel.org/r/20230303172041.2103336-83-u.kleine-koenig@pengutronix.de
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: 5d6f477d6fc0 ("spi: topcliff-pch: fix controller deregistration")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-topcliff-pch.c |    6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/drivers/spi/spi-topcliff-pch.c
++++ b/drivers/spi/spi-topcliff-pch.c
+@@ -1417,7 +1417,7 @@ err_pci_iomap:
+       return ret;
+ }
+-static int pch_spi_pd_remove(struct platform_device *plat_dev)
++static void pch_spi_pd_remove(struct platform_device *plat_dev)
+ {
+       struct pch_spi_board_data *board_dat = dev_get_platdata(&plat_dev->dev);
+       struct pch_spi_data *data = platform_get_drvdata(plat_dev);
+@@ -1455,8 +1455,6 @@ static int pch_spi_pd_remove(struct plat
+       pci_iounmap(board_dat->pdev, data->io_remap_addr);
+       spi_unregister_master(data->master);
+-
+-      return 0;
+ }
+ #ifdef CONFIG_PM
+ static int pch_spi_pd_suspend(struct platform_device *pd_dev,
+@@ -1537,7 +1535,7 @@ static struct platform_driver pch_spi_pd
+               .name = "pch-spi",
+       },
+       .probe = pch_spi_pd_probe,
+-      .remove = pch_spi_pd_remove,
++      .remove_new = pch_spi_pd_remove,
+       .suspend = pch_spi_pd_suspend,
+       .resume = pch_spi_pd_resume
+ };
diff --git a/queue-5.15/spi-topcliff-pch-fix-controller-deregistration.patch b/queue-5.15/spi-topcliff-pch-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..736a0a8
--- /dev/null
@@ -0,0 +1,48 @@
+From stable+bounces-247741-greg=kroah.com@vger.kernel.org Fri May 15 18:08:30 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 May 2026 08:15:25 -0400
+Subject: spi: topcliff-pch: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Masayuki Ohtake <masa-korg@dsn.okisemi.com>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260515121525.3130058-2-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit 5d6f477d6fc0767c57c5e1e6f55a1662820eef87 ]
+
+Make sure to deregister the controller before disabling and releasing
+underlying resources like interrupts and DMA during driver unbind.
+
+Fixes: e8b17b5b3f30 ("spi/topcliff: Add topcliff platform controller hub (PCH) spi bus driver")
+Cc: stable@vger.kernel.org     # 2.6.37
+Cc: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260414134319.978196-8-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ renamed spi_controller_*(data->host) calls to spi_master_*(data->master) ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-topcliff-pch.c |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-topcliff-pch.c
++++ b/drivers/spi/spi-topcliff-pch.c
+@@ -1450,11 +1450,16 @@ static void pch_spi_pd_remove(struct pla
+               free_irq(board_dat->pdev->irq, data);
+       }
++      spi_master_get(data->master);
++
++      spi_unregister_master(data->master);
++
+       if (use_dma)
+               pch_free_dma_buf(board_dat, data);
+       pci_iounmap(board_dat->pdev, data->io_remap_addr);
+-      spi_unregister_master(data->master);
++
++      spi_master_put(data->master);
+ }
+ #ifdef CONFIG_PM
+ static int pch_spi_pd_suspend(struct platform_device *pd_dev,
diff --git a/queue-5.15/spi-uniphier-fix-controller-deregistration.patch b/queue-5.15/spi-uniphier-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..806cb1f
--- /dev/null
@@ -0,0 +1,63 @@
+From stable+bounces-247195-greg=kroah.com@vger.kernel.org Thu May 14 18:11:34 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 May 2026 08:41:24 -0400
+Subject: spi: uniphier: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Keiji Hayashibara <hayashibara.keiji@socionext.com>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260514124124.212147-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit 0245435f777264ac45945ed2f325dd095a41d1af ]
+
+Make sure to deregister the controller before releasing underlying
+resources like DMA during driver unbind.
+
+Note that clocks were also disabled before the recent commit
+fdca270f8f87 ("spi: uniphier: Simplify clock handling with
+devm_clk_get_enabled()").
+
+Fixes: 5ba155a4d4cc ("spi: add SPI controller driver for UniPhier SoC")
+Cc: stable@vger.kernel.org     # 4.19
+Cc: Keiji Hayashibara <hayashibara.keiji@socionext.com>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-25-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ renamed spi_*_controller/host APIs to spi_*_master/master aliases and kept the pre-existing clk_disable_unprepare() after unregister ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-uniphier.c |    8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-uniphier.c
++++ b/drivers/spi/spi-uniphier.c
+@@ -751,7 +751,7 @@ static int uniphier_spi_probe(struct pla
+       master->max_dma_len = min(dma_tx_burst, dma_rx_burst);
+-      ret = devm_spi_register_master(&pdev->dev, master);
++      ret = spi_register_master(master);
+       if (ret)
+               goto out_release_dma;
+@@ -780,6 +780,10 @@ static int uniphier_spi_remove(struct pl
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
++      spi_master_get(master);
++
++      spi_unregister_master(master);
++
+       if (master->dma_tx)
+               dma_release_channel(master->dma_tx);
+       if (master->dma_rx)
+@@ -787,6 +791,8 @@ static int uniphier_spi_remove(struct pl
+       clk_disable_unprepare(priv->clk);
++      spi_master_put(master);
++
+       return 0;
+ }
diff --git a/queue-5.15/spi-zynq-qspi-fix-controller-deregistration.patch b/queue-5.15/spi-zynq-qspi-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..6f2b8d6
--- /dev/null
@@ -0,0 +1,78 @@
+From stable+bounces-247092-greg=kroah.com@vger.kernel.org Thu May 14 08:40:05 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 23:09:55 -0400
+Subject: spi: zynq-qspi: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260514030955.4116823-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit c9c012706c9fa8ca6d129a9161caf92ab625a3fd ]
+
+Make sure to deregister the controller before disabling it during driver
+unbind.
+
+Note that clocks were also disabled before the recent commit
+1f8fd9490e31 ("spi: zynq-qspi: Simplify clock handling with
+devm_clk_get_enabled()").
+
+Fixes: 67dca5e580f1 ("spi: spi-mem: Add support for Zynq QSPI controller")
+Cc: stable@vger.kernel.org     # 5.2: 8eb2fd00f65a
+Cc: stable@vger.kernel.org     # 5.2
+Cc: Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-27-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ kept int-returning remove() with manual clk_disable_unprepare() calls and routed probe error through existing clk_dis_all cascade instead of upstream's remove_ctlr label ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-zynq-qspi.c |   15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+--- a/drivers/spi/spi-zynq-qspi.c
++++ b/drivers/spi/spi-zynq-qspi.c
+@@ -652,7 +652,7 @@ static int zynq_qspi_probe(struct platfo
+       xqspi = spi_controller_get_devdata(ctlr);
+       xqspi->dev = dev;
+-      platform_set_drvdata(pdev, xqspi);
++      platform_set_drvdata(pdev, ctlr);
+       xqspi->regs = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(xqspi->regs)) {
+               ret = PTR_ERR(xqspi->regs);
+@@ -722,9 +722,9 @@ static int zynq_qspi_probe(struct platfo
+       /* QSPI controller initializations */
+       zynq_qspi_init_hw(xqspi, ctlr->num_chipselect);
+-      ret = devm_spi_register_controller(&pdev->dev, ctlr);
++      ret = spi_register_controller(ctlr);
+       if (ret) {
+-              dev_err(&pdev->dev, "spi_register_master failed\n");
++              dev_err(&pdev->dev, "failed to register controller\n");
+               goto clk_dis_all;
+       }
+@@ -752,13 +752,20 @@ remove_master:
+  */
+ static int zynq_qspi_remove(struct platform_device *pdev)
+ {
+-      struct zynq_qspi *xqspi = platform_get_drvdata(pdev);
++      struct spi_controller *ctlr = platform_get_drvdata(pdev);
++      struct zynq_qspi *xqspi = spi_controller_get_devdata(ctlr);
++
++      spi_controller_get(ctlr);
++
++      spi_unregister_controller(ctlr);
+       zynq_qspi_write(xqspi, ZYNQ_QSPI_ENABLE_OFFSET, 0);
+       clk_disable_unprepare(xqspi->refclk);
+       clk_disable_unprepare(xqspi->pclk);
++      spi_controller_put(ctlr);
++
+       return 0;
+ }
diff --git a/queue-5.15/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch b/queue-5.15/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch
new file mode 100644 (file)
index 0000000..8362e3f
--- /dev/null
@@ -0,0 +1,112 @@
+From stable+bounces-260822-greg=kroah.com@vger.kernel.org Sat Jun  6 02:04:15 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 16:34:00 -0400
+Subject: thunderbolt: property: Cap recursion depth in __tb_property_parse_dir()
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Mika Westerberg <mika.westerberg@linux.intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260605203400.2224060-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit 928abe19fbf0127003abcb1ea69cabc1c897d0ab ]
+
+A DIRECTORY entry's value field is used as the dir_offset for a
+recursive call into __tb_property_parse_dir() with no depth counter.
+A crafted peer that chains DIRECTORY entries into a back-reference
+loop drives the parser until the kernel stack is exhausted and the
+guard page fires.  Any untrusted XDomain peer (cable, dock, in-line
+inspector, adjacent host) that reaches the PROPERTIES_REQUEST
+control-plane exchange can trigger this without authentication.
+
+Thread a depth counter through tb_property_parse() and
+__tb_property_parse_dir(), and reject blocks that exceed
+TB_PROPERTY_MAX_DEPTH = 8.  That is comfortably larger than any
+observed legitimate XDomain layout.
+
+Operators who do not need XDomain host-to-host discovery can disable
+the path entirely with thunderbolt.xdomain=0 on the kernel command
+line.
+
+Fixes: cdae7c07e3e3 ("thunderbolt: Add support for XDomain properties")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-6
+Assisted-by: Codex:gpt-5-4
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/thunderbolt/property.c |   18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+--- a/drivers/thunderbolt/property.c
++++ b/drivers/thunderbolt/property.c
+@@ -35,10 +35,11 @@ struct tb_property_dir_entry {
+ };
+ #define TB_PROPERTY_ROOTDIR_MAGIC     0x55584401
++#define TB_PROPERTY_MAX_DEPTH         8
+ static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,
+       size_t block_len, unsigned int dir_offset, size_t dir_len,
+-      bool is_root);
++      bool is_root, unsigned int depth);
+ static inline void parse_dwdata(void *dst, const void *src, size_t dwords)
+ {
+@@ -99,7 +100,8 @@ tb_property_alloc(const char *key, enum
+ }
+ static struct tb_property *tb_property_parse(const u32 *block, size_t block_len,
+-                                      const struct tb_property_entry *entry)
++                                      const struct tb_property_entry *entry,
++                                      unsigned int depth)
+ {
+       char key[TB_PROPERTY_KEY_SIZE + 1];
+       struct tb_property *property;
+@@ -120,7 +122,7 @@ static struct tb_property *tb_property_p
+       switch (property->type) {
+       case TB_PROPERTY_TYPE_DIRECTORY:
+               dir = __tb_property_parse_dir(block, block_len, entry->value,
+-                                            entry->length, false);
++                                            entry->length, false, depth + 1);
+               if (!dir) {
+                       kfree(property);
+                       return NULL;
+@@ -165,13 +167,17 @@ static struct tb_property *tb_property_p
+ }
+ static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,
+-      size_t block_len, unsigned int dir_offset, size_t dir_len, bool is_root)
++      size_t block_len, unsigned int dir_offset, size_t dir_len, bool is_root,
++      unsigned int depth)
+ {
+       const struct tb_property_entry *entries;
+       size_t i, content_len, nentries;
+       unsigned int content_offset;
+       struct tb_property_dir *dir;
++      if (depth > TB_PROPERTY_MAX_DEPTH)
++              return NULL;
++
+       dir = kzalloc(sizeof(*dir), GFP_KERNEL);
+       if (!dir)
+               return NULL;
+@@ -206,7 +212,7 @@ static struct tb_property_dir *__tb_prop
+       for (i = 0; i < nentries; i++) {
+               struct tb_property *property;
+-              property = tb_property_parse(block, block_len, &entries[i]);
++              property = tb_property_parse(block, block_len, &entries[i], depth);
+               if (!property) {
+                       tb_property_free_dir(dir);
+                       return NULL;
+@@ -243,7 +249,7 @@ struct tb_property_dir *tb_property_pars
+               return NULL;
+       return __tb_property_parse_dir(block, block_len, 0, rootdir->length,
+-                                     true);
++                                     true, 0);
+ }
+ /**
diff --git a/queue-5.15/tracing-probes-limit-size-of-event-probe-to-3k.patch b/queue-5.15/tracing-probes-limit-size-of-event-probe-to-3k.patch
new file mode 100644 (file)
index 0000000..cf37e72
--- /dev/null
@@ -0,0 +1,70 @@
+From stable+bounces-247823-greg=kroah.com@vger.kernel.org Fri May 15 20:52:22 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 May 2026 11:20:51 -0400
+Subject: tracing/probes: Limit size of event probe to 3K
+To: stable@vger.kernel.org
+Cc: Steven Rostedt <rostedt@goodmis.org>, Mathieu Desnoyers <mathieu.desnoyers@efficios.com>, "Masami Hiramatsu (Google)" <mhiramat@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260515152051.3277784-1-sashal@kernel.org>
+
+From: Steven Rostedt <rostedt@goodmis.org>
+
+[ Upstream commit b2aa3b4d64e460ac606f386c24e7d8a873ce6f1a ]
+
+There currently isn't a max limit an event probe can be. One could make an
+event greater than PAGE_SIZE, which makes the event useless because if
+it's bigger than the max event that can be recorded into the ring buffer,
+then it will never be recorded.
+
+A event probe should never need to be greater than 3K, so make that the
+max size. As long as the max is less than the max that can be recorded
+onto the ring buffer, it should be fine.
+
+Cc: stable@vger.kernel.org
+Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Fixes: 93ccae7a22274 ("tracing/kprobes: Support basic types on dynamic events")
+Link: https://patch.msgid.link/20260428122302.706610ba@gandalf.local.home
+Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
+[ adjusted context for missing later-kernel infrastructure and used `goto out` instead of `goto fail` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/trace/trace_probe.c |    6 ++++++
+ kernel/trace/trace_probe.h |    4 +++-
+ 2 files changed, 9 insertions(+), 1 deletion(-)
+
+--- a/kernel/trace/trace_probe.c
++++ b/kernel/trace/trace_probe.c
+@@ -647,6 +647,12 @@ static int traceprobe_parse_probe_arg_bo
+       parg->offset = *size;
+       *size += parg->type->size * (parg->count ?: 1);
++      if (*size > MAX_PROBE_EVENT_SIZE) {
++              ret = -E2BIG;
++              trace_probe_log_err(offset, EVENT_TOO_BIG);
++              goto out;
++      }
++
+       ret = -ENOMEM;
+       if (parg->count) {
+               len = strlen(parg->type->fmttype) + 6;
+--- a/kernel/trace/trace_probe.h
++++ b/kernel/trace/trace_probe.h
+@@ -33,6 +33,7 @@
+ #define MAX_ARRAY_LEN         64
+ #define MAX_ARG_NAME_LEN      32
+ #define MAX_STRING_SIZE               PATH_MAX
++#define MAX_PROBE_EVENT_SIZE  3072
+ /* Reserved field names */
+ #define FIELD_STRING_IP               "__probe_ip"
+@@ -455,7 +456,8 @@ extern int traceprobe_define_arg_fields(
+       C(FAIL_REG_PROBE,       "Failed to register probe event"),\
+       C(DIFF_PROBE_TYPE,      "Probe type is different from existing probe"),\
+       C(DIFF_ARG_TYPE,        "Argument type or name is different from existing probe"),\
+-      C(SAME_PROBE,           "There is already the exact same probe event"),
++      C(SAME_PROBE,           "There is already the exact same probe event"),\
++      C(EVENT_TOO_BIG,        "Event too big (too many fields?)"),
+ #undef C
+ #define C(a, b)               TP_ERR_##a
diff --git a/queue-5.15/tty-serial-qcom-geni-serial-align-define-values.patch b/queue-5.15/tty-serial-qcom-geni-serial-align-define-values.patch
new file mode 100644 (file)
index 0000000..0a20779
--- /dev/null
@@ -0,0 +1,115 @@
+From stable+bounces-260865-greg=kroah.com@vger.kernel.org Sat Jun  6 17:49:55 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  6 Jun 2026 08:18:53 -0400
+Subject: tty: serial: qcom-geni-serial: align #define values
+To: stable@vger.kernel.org
+Cc: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>, Konrad Dybcio <konrad.dybcio@linaro.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606121854.2850880-2-sashal@kernel.org>
+
+From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+[ Upstream commit 6cde11dbf4b65170eeefba48df730c93d75e01a3 ]
+
+Keep the #define symbols aligned for better readability.
+
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
+Link: https://lore.kernel.org/r/20221229155030.418800-5-brgl@bgdev.pl
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: ca2584d841b6 ("serial: qcom-geni: fix UART_RX_PAR_EN bit position")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/qcom_geni_serial.c |   60 +++++++++++++++++-----------------
+ 1 file changed, 30 insertions(+), 30 deletions(-)
+
+--- a/drivers/tty/serial/qcom_geni_serial.c
++++ b/drivers/tty/serial/qcom_geni_serial.c
+@@ -35,57 +35,57 @@
+ #define SE_UART_MANUAL_RFR            0x2ac
+ /* SE_UART_TRANS_CFG */
+-#define UART_TX_PAR_EN                BIT(0)
+-#define UART_CTS_MASK         BIT(1)
++#define UART_TX_PAR_EN                        BIT(0)
++#define UART_CTS_MASK                 BIT(1)
+ /* SE_UART_TX_STOP_BIT_LEN */
+-#define TX_STOP_BIT_LEN_1     0
+-#define TX_STOP_BIT_LEN_2     2
++#define TX_STOP_BIT_LEN_1             0
++#define TX_STOP_BIT_LEN_2             2
+ /* SE_UART_RX_TRANS_CFG */
+-#define UART_RX_PAR_EN                BIT(3)
++#define UART_RX_PAR_EN                        BIT(3)
+ /* SE_UART_RX_WORD_LEN */
+-#define RX_WORD_LEN_MASK      GENMASK(9, 0)
++#define RX_WORD_LEN_MASK              GENMASK(9, 0)
+ /* SE_UART_RX_STALE_CNT */
+-#define RX_STALE_CNT          GENMASK(23, 0)
++#define RX_STALE_CNT                  GENMASK(23, 0)
+ /* SE_UART_TX_PARITY_CFG/RX_PARITY_CFG */
+-#define PAR_CALC_EN           BIT(0)
+-#define PAR_EVEN              0x00
+-#define PAR_ODD                       0x01
+-#define PAR_SPACE             0x10
++#define PAR_CALC_EN                   BIT(0)
++#define PAR_EVEN                      0x00
++#define PAR_ODD                               0x01
++#define PAR_SPACE                     0x10
+ /* SE_UART_MANUAL_RFR register fields */
+-#define UART_MANUAL_RFR_EN    BIT(31)
+-#define UART_RFR_NOT_READY    BIT(1)
+-#define UART_RFR_READY                BIT(0)
++#define UART_MANUAL_RFR_EN            BIT(31)
++#define UART_RFR_NOT_READY            BIT(1)
++#define UART_RFR_READY                        BIT(0)
+ /* UART M_CMD OP codes */
+-#define UART_START_TX         0x1
++#define UART_START_TX                 0x1
+ /* UART S_CMD OP codes */
+-#define UART_START_READ               0x1
++#define UART_START_READ                       0x1
+-#define UART_OVERSAMPLING     32
+-#define STALE_TIMEOUT         16
+-#define DEFAULT_BITS_PER_CHAR 10
+-#define GENI_UART_CONS_PORTS  1
+-#define GENI_UART_PORTS               3
+-#define DEF_FIFO_DEPTH_WORDS  16
+-#define DEF_TX_WM             2
+-#define DEF_FIFO_WIDTH_BITS   32
+-#define UART_RX_WM            2
++#define UART_OVERSAMPLING             32
++#define STALE_TIMEOUT                 16
++#define DEFAULT_BITS_PER_CHAR         10
++#define GENI_UART_CONS_PORTS          1
++#define GENI_UART_PORTS                       3
++#define DEF_FIFO_DEPTH_WORDS          16
++#define DEF_TX_WM                     2
++#define DEF_FIFO_WIDTH_BITS           32
++#define UART_RX_WM                    2
+ /* SE_UART_LOOPBACK_CFG */
+-#define RX_TX_SORTED  BIT(0)
+-#define CTS_RTS_SORTED        BIT(1)
+-#define RX_TX_CTS_RTS_SORTED  (RX_TX_SORTED | CTS_RTS_SORTED)
++#define RX_TX_SORTED                  BIT(0)
++#define CTS_RTS_SORTED                        BIT(1)
++#define RX_TX_CTS_RTS_SORTED          (RX_TX_SORTED | CTS_RTS_SORTED)
+ /* UART pin swap value */
+-#define DEFAULT_IO_MACRO_IO0_IO1_MASK         GENMASK(3, 0)
++#define DEFAULT_IO_MACRO_IO0_IO1_MASK GENMASK(3, 0)
+ #define IO_MACRO_IO0_SEL              0x3
+-#define DEFAULT_IO_MACRO_IO2_IO3_MASK         GENMASK(15, 4)
++#define DEFAULT_IO_MACRO_IO2_IO3_MASK GENMASK(15, 4)
+ #define IO_MACRO_IO2_IO3_SWAP         0x4640
+ /* We always configure 4 bytes per FIFO word */
diff --git a/queue-5.15/tty-serial-qcom-geni-serial-remove-unused-symbols.patch b/queue-5.15/tty-serial-qcom-geni-serial-remove-unused-symbols.patch
new file mode 100644 (file)
index 0000000..c52d1b6
--- /dev/null
@@ -0,0 +1,73 @@
+From sashal@kernel.org Sat Jun  6 17:48:57 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  6 Jun 2026 08:18:52 -0400
+Subject: tty: serial: qcom-geni-serial: remove unused symbols
+To: stable@vger.kernel.org
+Cc: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>, Konrad Dybcio <konrad.dybcio@linaro.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606121854.2850880-1-sashal@kernel.org>
+
+From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+[ Upstream commit 68c6bd92c86cbc4937834c79963b27c77ee3bf51 ]
+
+Drop all unused symbols from the driver.
+
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
+Link: https://lore.kernel.org/r/20221229155030.418800-4-brgl@bgdev.pl
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: ca2584d841b6 ("serial: qcom-geni: fix UART_RX_PAR_EN bit position")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/qcom_geni_serial.c |   15 ---------------
+ 1 file changed, 15 deletions(-)
+
+--- a/drivers/tty/serial/qcom_geni_serial.c
++++ b/drivers/tty/serial/qcom_geni_serial.c
+@@ -38,20 +38,11 @@
+ #define UART_TX_PAR_EN                BIT(0)
+ #define UART_CTS_MASK         BIT(1)
+-/* SE_UART_TX_WORD_LEN */
+-#define TX_WORD_LEN_MSK               GENMASK(9, 0)
+-
+ /* SE_UART_TX_STOP_BIT_LEN */
+-#define TX_STOP_BIT_LEN_MSK   GENMASK(23, 0)
+ #define TX_STOP_BIT_LEN_1     0
+-#define TX_STOP_BIT_LEN_1_5   1
+ #define TX_STOP_BIT_LEN_2     2
+-/* SE_UART_TX_TRANS_LEN */
+-#define TX_TRANS_LEN_MSK      GENMASK(23, 0)
+-
+ /* SE_UART_RX_TRANS_CFG */
+-#define UART_RX_INS_STATUS_BIT        BIT(2)
+ #define UART_RX_PAR_EN                BIT(3)
+ /* SE_UART_RX_WORD_LEN */
+@@ -62,12 +53,9 @@
+ /* SE_UART_TX_PARITY_CFG/RX_PARITY_CFG */
+ #define PAR_CALC_EN           BIT(0)
+-#define PAR_MODE_MSK          GENMASK(2, 1)
+-#define PAR_MODE_SHFT         1
+ #define PAR_EVEN              0x00
+ #define PAR_ODD                       0x01
+ #define PAR_SPACE             0x10
+-#define PAR_MARK              0x11
+ /* SE_UART_MANUAL_RFR register fields */
+ #define UART_MANUAL_RFR_EN    BIT(31)
+@@ -76,11 +64,8 @@
+ /* UART M_CMD OP codes */
+ #define UART_START_TX         0x1
+-#define UART_START_BREAK      0x4
+-#define UART_STOP_BREAK               0x5
+ /* UART S_CMD OP codes */
+ #define UART_START_READ               0x1
+-#define UART_PARAM            0x1
+ #define UART_OVERSAMPLING     32
+ #define STALE_TIMEOUT         16
diff --git a/queue-5.15/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch b/queue-5.15/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch
new file mode 100644 (file)
index 0000000..6b0c3e2
--- /dev/null
@@ -0,0 +1,85 @@
+From sashal@kernel.org Sat Jun  6 00:01:20 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 14:31:15 -0400
+Subject: tty: serial: samsung: Remove redundant port lock acquisition in rx helpers
+To: stable@vger.kernel.org
+Cc: Tudor Ambarus <tudor.ambarus@linaro.org>, stable <stable@kernel.org>, John Ogness <john.ogness@linutronix.de>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260605183115.2054750-3-sashal@kernel.org>
+
+From: Tudor Ambarus <tudor.ambarus@linaro.org>
+
+[ Upstream commit a3bb136bff5e6a5e48cdd813246c9c4686feaaa9 ]
+
+Sashiko identified a deadlock when the console flow is engaged [1].
+
+When console flow control is enabled (UPF_CONS_FLOW),
+s3c24xx_serial_stop_tx() calls s3c24xx_serial_rx_enable() and
+s3c24xx_serial_start_tx() calls s3c24xx_serial_rx_disable().
+
+The serial core framework invokes the .stop_tx() and .start_tx()
+callbacks with the port->lock spinlock already held. Furthermore, all
+internal driver paths that invoke stop_tx (such as the DMA TX
+completion handler s3c24xx_serial_tx_dma_complete() or the PIO TX IRQ
+handler s3c24xx_serial_tx_irq()) also acquire port->lock prior to
+calling it. (Note that s3c24xx_serial_start_tx() is only invoked by the
+serial core).
+
+However, s3c24xx_serial_rx_enable() and s3c24xx_serial_rx_disable()
+unconditionally attempt to acquire port->lock again using
+uart_port_lock_irqsave(). Since spinlocks are not recursive, this
+causes a deadlock on the same CPU when console flow control is engaged.
+
+Remove the redundant lock acquisition from both rx helper functions.
+
+Cc: stable <stable@kernel.org>
+Fixes: b497549a035c ("[ARM] S3C24XX: Split serial driver into core and per-cpu drivers")
+Reported-by: John Ogness <john.ogness@linutronix.de>
+Closes: https://sashiko.dev/#/patchset/20260506121606.5805-1-john.ogness%40linutronix.de [1]
+Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
+Link: https://patch.msgid.link/20260515-samsung-tty-flow-control-deadlock-v1-1-93255edbc9bc@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/samsung_tty.c |    8 --------
+ 1 file changed, 8 deletions(-)
+
+--- a/drivers/tty/serial/samsung_tty.c
++++ b/drivers/tty/serial/samsung_tty.c
+@@ -242,12 +242,9 @@ static int s3c24xx_serial_txempty_nofifo
+ static void s3c24xx_serial_rx_enable(struct uart_port *port)
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+-      unsigned long flags;
+       int count = 10000;
+       u32 ucon, ufcon;
+-      uart_port_lock_irqsave(port, &flags);
+-
+       while (--count && !s3c24xx_serial_txempty_nofifo(port))
+               udelay(100);
+@@ -260,23 +257,18 @@ static void s3c24xx_serial_rx_enable(str
+       wr_regl(port, S3C2410_UCON, ucon);
+       ourport->rx_enabled = 1;
+-      uart_port_unlock_irqrestore(port, flags);
+ }
+ static void s3c24xx_serial_rx_disable(struct uart_port *port)
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+-      unsigned long flags;
+       u32 ucon;
+-      uart_port_lock_irqsave(port, &flags);
+-
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~S3C2410_UCON_RXIRQMODE;
+       wr_regl(port, S3C2410_UCON, ucon);
+       ourport->rx_enabled = 0;
+-      uart_port_unlock_irqrestore(port, flags);
+ }
+ static void s3c24xx_serial_stop_tx(struct uart_port *port)
diff --git a/queue-5.15/tty-serial-samsung-use-u32-for-register-interactions.patch b/queue-5.15/tty-serial-samsung-use-u32-for-register-interactions.patch
new file mode 100644 (file)
index 0000000..06433f8
--- /dev/null
@@ -0,0 +1,216 @@
+From sashal@kernel.org Sat Jun  6 00:01:19 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 14:31:14 -0400
+Subject: tty: serial: samsung: use u32 for register interactions
+To: stable@vger.kernel.org
+Cc: Tudor Ambarus <tudor.ambarus@linaro.org>, Sam Protsenko <semen.protsenko@linaro.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260605183115.2054750-2-sashal@kernel.org>
+
+From: Tudor Ambarus <tudor.ambarus@linaro.org>
+
+[ Upstream commit 032a725c16add79332d774348d7ad7d0d4b86479 ]
+
+All registers of the IP have 32 bits. Use u32 variables when reading
+or writing from/to the registers. The purpose of those variables becomes
+clearer.
+
+Reviewed-by: Sam Protsenko <semen.protsenko@linaro.org>
+Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
+Link: https://lore.kernel.org/r/20240119104526.1221243-9-tudor.ambarus@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: a3bb136bff5e ("tty: serial: samsung: Remove redundant port lock acquisition in rx helpers")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/samsung_tty.c |   44 ++++++++++++++++++---------------------
+ 1 file changed, 21 insertions(+), 23 deletions(-)
+
+--- a/drivers/tty/serial/samsung_tty.c
++++ b/drivers/tty/serial/samsung_tty.c
+@@ -243,8 +243,8 @@ static void s3c24xx_serial_rx_enable(str
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       unsigned long flags;
+-      unsigned int ucon, ufcon;
+       int count = 10000;
++      u32 ucon, ufcon;
+       uart_port_lock_irqsave(port, &flags);
+@@ -267,7 +267,7 @@ static void s3c24xx_serial_rx_disable(st
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       unsigned long flags;
+-      unsigned int ucon;
++      u32 ucon;
+       uart_port_lock_irqsave(port, &flags);
+@@ -664,7 +664,7 @@ static void s3c64xx_start_rx_dma(struct
+ static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
+ {
+       struct uart_port *port = &ourport->port;
+-      unsigned int ucon;
++      u32 ucon;
+       /* set Rx mode to DMA mode */
+       ucon = rd_regl(port, S3C2410_UCON);
+@@ -687,7 +687,7 @@ static void enable_rx_dma(struct s3c24xx
+ static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
+ {
+       struct uart_port *port = &ourport->port;
+-      unsigned int ucon;
++      u32 ucon;
+       /* set Rx mode to DMA mode */
+       ucon = rd_regl(port, S3C2410_UCON);
+@@ -712,13 +712,14 @@ static void s3c24xx_serial_rx_drain_fifo
+ static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id)
+ {
+-      unsigned int utrstat, received;
+       struct s3c24xx_uart_port *ourport = dev_id;
+       struct uart_port *port = &ourport->port;
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+       struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
+       struct tty_port *t = &port->state->port;
+       struct dma_tx_state state;
++      unsigned int received;
++      u32 utrstat;
+       utrstat = rd_regl(port, S3C2410_UTRSTAT);
+       rd_regl(port, S3C2410_UFSTAT);
+@@ -1000,7 +1001,7 @@ static unsigned int s3c24xx_serial_tx_em
+ /* no modem control lines */
+ static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
+ {
+-      unsigned int umstat = rd_reg(port, S3C2410_UMSTAT);
++      u32 umstat = rd_reg(port, S3C2410_UMSTAT);
+       if (umstat & S3C2410_UMSTAT_CTS)
+               return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+@@ -1023,7 +1024,7 @@ static void s3c24xx_serial_set_mctrl(str
+ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
+ {
+       unsigned long flags;
+-      unsigned int ucon;
++      u32 ucon;
+       uart_port_lock_irqsave(port, &flags);
+@@ -1204,7 +1205,7 @@ static void apple_s5l_serial_shutdown(st
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+-      unsigned int ucon;
++      u32 ucon;
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK |
+@@ -1272,7 +1273,7 @@ static int s3c64xx_serial_startup(struct
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       unsigned long flags;
+-      unsigned int ufcon;
++      u32 ufcon;
+       int ret;
+       wr_regl(port, S3C64XX_UINTM, 0xf);
+@@ -1317,7 +1318,7 @@ static int apple_s5l_serial_startup(stru
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       unsigned long flags;
+-      unsigned int ufcon;
++      u32 ufcon;
+       int ret;
+       wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS);
+@@ -1559,9 +1560,8 @@ static void s3c24xx_serial_set_termios(s
+       struct clk *clk = ERR_PTR(-EINVAL);
+       unsigned long flags;
+       unsigned int baud, quot, clk_sel = 0;
+-      unsigned int ulcon;
+-      unsigned int umcon;
+       unsigned int udivslot = 0;
++      u32 ulcon, umcon;
+       /*
+        * We don't support modem control lines.
+@@ -2147,7 +2147,7 @@ static int s3c24xx_serial_init_port(stru
+               wr_regl(port, S3C64XX_UINTSP, 0xf);
+               break;
+       case TYPE_APPLE_S5L: {
+-              unsigned int ucon;
++              u32 ucon;
+               ucon = rd_regl(port, S3C2410_UCON);
+               ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK |
+@@ -2366,7 +2366,7 @@ static int s3c24xx_serial_resume_noirq(s
+               /* restore IRQ mask */
+               switch (ourport->info->type) {
+               case TYPE_S3C6400: {
+-                      unsigned int uintm = 0xf;
++                      u32 uintm = 0xf;
+                       if (ourport->tx_enabled)
+                               uintm &= ~S3C64XX_UINTM_TXD_MSK;
+@@ -2382,7 +2382,7 @@ static int s3c24xx_serial_resume_noirq(s
+                       break;
+               }
+               case TYPE_APPLE_S5L: {
+-                      unsigned int ucon;
++                      u32 ucon;
+                       int ret;
+                       ret = clk_prepare_enable(ourport->clk);
+@@ -2445,7 +2445,7 @@ static const struct dev_pm_ops s3c24xx_s
+ static struct uart_port *cons_uart;
+ static int
+-s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
++s3c24xx_serial_console_txrdy(struct uart_port *port, u32 ufcon)
+ {
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       unsigned long ufstat, utrstat;
+@@ -2464,7 +2464,7 @@ s3c24xx_serial_console_txrdy(struct uart
+ }
+ static bool
+-s3c24xx_port_configured(unsigned int ucon)
++s3c24xx_port_configured(u32 ucon)
+ {
+       /* consider the serial port configured if the tx/rx mode set */
+       return (ucon & 0xf) != 0;
+@@ -2491,8 +2491,8 @@ static int s3c24xx_serial_get_poll_char(
+ static void s3c24xx_serial_put_poll_char(struct uart_port *port,
+               unsigned char c)
+ {
+-      unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
+-      unsigned int ucon = rd_regl(port, S3C2410_UCON);
++      u32 ufcon = rd_regl(port, S3C2410_UFCON);
++      u32 ucon = rd_regl(port, S3C2410_UCON);
+       /* not possible to xmit on unconfigured port */
+       if (!s3c24xx_port_configured(ucon))
+@@ -2508,7 +2508,7 @@ static void s3c24xx_serial_put_poll_char
+ static void
+ s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
+ {
+-      unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
++      u32 ufcon = rd_regl(port, S3C2410_UFCON);
+       while (!s3c24xx_serial_console_txrdy(port, ufcon))
+               cpu_relax();
+@@ -2533,11 +2533,9 @@ s3c24xx_serial_get_options(struct uart_p
+                          int *parity, int *bits)
+ {
+       struct clk *clk;
+-      unsigned int ulcon;
+-      unsigned int ucon;
+-      unsigned int ubrdiv;
+       unsigned long rate;
+       unsigned int clk_sel;
++      u32 ulcon, ucon, ubrdiv;
+       char clk_name[MAX_CLK_NAME_LENGTH];
+       ulcon  = rd_regl(port, S3C2410_ULCON);
diff --git a/queue-5.15/usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch b/queue-5.15/usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch
new file mode 100644 (file)
index 0000000..069cc42
--- /dev/null
@@ -0,0 +1,48 @@
+From stable+bounces-260693-greg=kroah.com@vger.kernel.org Fri Jun  5 18:35:53 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 09:05:37 -0400
+Subject: usb: cdns3: plat: fix leaked usb2_phy initialization on usb3_phy acquisition failure
+To: stable@vger.kernel.org
+Cc: Peter Chen <peter.chen@cixtech.com>, stable <stable@kernel.org>, sashiko-bot <sashiko-bot@kernel.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260605130538.413416-1-sashal@kernel.org>
+
+From: Peter Chen <peter.chen@cixtech.com>
+
+[ Upstream commit e6970cda63fd4b4546aeed9d0e2f53a7c95cd09c ]
+
+Move usb2_phy initialization after usb3_phy acquisition.
+
+Fixes: f738957277ba ("usb: cdns3: Split core.c into cdns3-plat and core.c file")
+Cc: stable <stable@kernel.org>
+Reported-by: sashiko-bot <sashiko-bot@kernel.org>
+Closes: https://lore.kernel.org/linux-devicetree/agKaEePSFknhDBg2@nchen-desktop/T/#m21e1d9c1574eb127ce03c0c2a1a49002ce435b52
+Signed-off-by: Peter Chen <peter.chen@cixtech.com>
+Link: https://patch.msgid.link/20260513085310.2217547-2-peter.chen@cixtech.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/cdns3/cdns3-plat.c |    8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/cdns3/cdns3-plat.c
++++ b/drivers/usb/cdns3/cdns3-plat.c
+@@ -120,14 +120,14 @@ static int cdns3_plat_probe(struct platf
+       if (IS_ERR(cdns->usb2_phy))
+               return PTR_ERR(cdns->usb2_phy);
+-      ret = phy_init(cdns->usb2_phy);
+-      if (ret)
+-              return ret;
+-
+       cdns->usb3_phy = devm_phy_optional_get(dev, "cdns3,usb3-phy");
+       if (IS_ERR(cdns->usb3_phy))
+               return PTR_ERR(cdns->usb3_phy);
++      ret = phy_init(cdns->usb2_phy);
++      if (ret)
++              return ret;
++
+       ret = phy_init(cdns->usb3_phy);
+       if (ret)
+               goto err_phy3_init;
diff --git a/queue-5.15/usb-dwc3-move-guid-programming-after-phy-initialization.patch b/queue-5.15/usb-dwc3-move-guid-programming-after-phy-initialization.patch
new file mode 100644 (file)
index 0000000..7afa8a6
--- /dev/null
@@ -0,0 +1,63 @@
+From sashal@kernel.org Wed May 13 19:23:37 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 09:53:34 -0400
+Subject: usb: dwc3: Move GUID programming after PHY initialization
+To: stable@vger.kernel.org
+Cc: Selvarasu Ganesan <selvarasu.g@samsung.com>, stable <stable@kernel.org>, Pritam Manohar Sutar <pritam.sutar@samsung.com>, Thinh Nguyen <Thinh.Nguyen@synopsys.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260513135334.3740565-1-sashal@kernel.org>
+
+From: Selvarasu Ganesan <selvarasu.g@samsung.com>
+
+[ Upstream commit aad35f9c926ec220b0742af1ada45666ae667956 ]
+
+The Linux Version Code is currently written to the GUID register before
+PHY initialization. Certain PHY implementations (such as Synopsys eUSB
+PHY performing link_sw_reset) clear the GUID register to its default
+value during initialization, causing the kernel version information to
+be lost.
+
+Move the GUID register programming to occur after PHY initialization
+completes to ensure the Linux version information persists.
+
+Fixes: fa0ea13e9f1c ("usb: dwc3: core: write LINUX_VERSION_CODE to our GUID register")
+Cc: stable <stable@kernel.org>
+Reported-by: Pritam Manohar Sutar <pritam.sutar@samsung.com>
+Signed-off-by: Selvarasu Ganesan <selvarasu.g@samsung.com>
+Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+Link: https://patch.msgid.link/20260417063314.2359-1-selvarasu.g@samsung.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[ adapted dwc3_writel(dwc, ...) to dwc3_writel(dwc->regs, ...) ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/dwc3/core.c |   12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/dwc3/core.c
++++ b/drivers/usb/dwc3/core.c
+@@ -978,12 +978,6 @@ static int dwc3_core_init(struct dwc3 *d
+       hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
+-      /*
+-       * Write Linux Version Code to our GUID register so it's easy to figure
+-       * out which kernel version a bug was found.
+-       */
+-      dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
+-
+       ret = dwc3_phy_setup(dwc);
+       if (ret)
+               goto err0;
+@@ -1023,6 +1017,12 @@ static int dwc3_core_init(struct dwc3 *d
+       if (ret)
+               goto err1;
++      /*
++       * Write Linux Version Code to our GUID register so it's easy to figure
++       * out which kernel version a bug was found.
++       */
++      dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
++
+       dwc3_core_setup_global_control(dwc);
+       dwc3_core_num_eps(dwc);
diff --git a/queue-5.15/usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch b/queue-5.15/usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch
new file mode 100644 (file)
index 0000000..797663a
--- /dev/null
@@ -0,0 +1,84 @@
+From sashal@kernel.org Sat Jun  6 00:47:04 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 15:17:01 -0400
+Subject: usb: dwc3: xilinx: fix error handling in zynqmp init error paths
+To: stable@vger.kernel.org
+Cc: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>, Thinh Nguyen <Thinh.Nguyen@synopsys.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260605191701.2128791-1-sashal@kernel.org>
+
+From: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
+
+[ Upstream commit c1a0ecbf32c4b397353204e2ec94c5bb9f3300ed ]
+
+Fix error handling and resource cleanup i.e remove invalid
+phy_exit() after failed phy_init(), route failures through
+proper cleanup paths and return 0 explicitly on success.
+
+Fixes: 84770f028fab ("usb: dwc3: Add driver for Xilinx platforms")
+Cc: stable@vger.kernel.org
+Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
+Link: https://patch.msgid.link/20260519115529.2980421-1-radhey.shyam.pandey@amd.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/dwc3/dwc3-xilinx.c |   20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+--- a/drivers/usb/dwc3/dwc3-xilinx.c
++++ b/drivers/usb/dwc3/dwc3-xilinx.c
+@@ -165,15 +165,13 @@ static int dwc3_xlnx_init_zynqmp(struct
+       }
+       ret = phy_init(usb3_phy);
+-      if (ret < 0) {
+-              phy_exit(usb3_phy);
++      if (ret < 0)
+               goto err;
+-      }
+       ret = reset_control_deassert(apbrst);
+       if (ret < 0) {
+               dev_err(dev, "Failed to release APB reset\n");
+-              goto err;
++              goto err_phy_exit;
+       }
+       /* Set PIPE Power Present signal in FPD Power Present Register*/
+@@ -185,20 +183,18 @@ static int dwc3_xlnx_init_zynqmp(struct
+       ret = reset_control_deassert(crst);
+       if (ret < 0) {
+               dev_err(dev, "Failed to release core reset\n");
+-              goto err;
++              goto err_phy_exit;
+       }
+       ret = reset_control_deassert(hibrst);
+       if (ret < 0) {
+               dev_err(dev, "Failed to release hibernation reset\n");
+-              goto err;
++              goto err_phy_exit;
+       }
+       ret = phy_power_on(usb3_phy);
+-      if (ret < 0) {
+-              phy_exit(usb3_phy);
+-              goto err;
+-      }
++      if (ret < 0)
++              goto err_phy_exit;
+ skip_usb3_phy:
+       /*
+@@ -212,6 +208,10 @@ skip_usb3_phy:
+               writel(reg, priv_data->regs + XLNX_USB_TRAFFIC_ROUTE_CONFIG);
+       }
++      return 0;
++
++err_phy_exit:
++      phy_exit(usb3_phy);
+ err:
+       return ret;
+ }
diff --git a/queue-5.15/usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch b/queue-5.15/usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch
new file mode 100644 (file)
index 0000000..9f7a1aa
--- /dev/null
@@ -0,0 +1,58 @@
+From sashal@kernel.org Sat Jun  6 01:08:30 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 15:38:26 -0400
+Subject: usb: gadget: f_hid: fix device reference leak in hidg_alloc()
+To: stable@vger.kernel.org
+Cc: Guangshuo Li <lgs201920130244@gmail.com>, stable <stable@kernel.org>, Johan Hovold <johan@kernel.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260605193826.2169399-2-sashal@kernel.org>
+
+From: Guangshuo Li <lgs201920130244@gmail.com>
+
+[ Upstream commit 4f88d65def6f3c90121601b4f62a4c967f3063a6 ]
+
+hidg_alloc() initializes hidg->dev with device_initialize() before
+calling dev_set_name(). If dev_set_name() fails, the function currently
+jumps to err_unlock and returns without calling put_device().
+
+This leaves the device reference unbalanced and prevents hidg_release()
+from being called. Calling put_device() here is also safe, since
+hidg_release() only frees resources owned by hidg.
+
+The issue was identified by a static analysis tool I developed and
+confirmed by manual review.
+
+Route the dev_set_name() failure path through err_put_device so the
+device reference is dropped properly.
+
+Fixes: 89ff3dfac604 ("usb: gadget: f_hid: fix f_hidg lifetime vs cdev")
+Cc: stable <stable@kernel.org>
+Reviewed-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
+Reviewed-by: Johan Hovold johan@kernel.org
+Link: https://patch.msgid.link/20260413142119.2977716-1-lgs201920130244@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/f_hid.c |    3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/usb/gadget/function/f_hid.c
++++ b/drivers/usb/gadget/function/f_hid.c
+@@ -1278,7 +1278,7 @@ static struct usb_function *hidg_alloc(s
+       hidg->dev.devt = MKDEV(major, opts->minor);
+       ret = dev_set_name(&hidg->dev, "hidg%d", opts->minor);
+       if (ret)
+-              goto err_unlock;
++              goto err_put_device;
+       hidg->bInterfaceSubClass = opts->subclass;
+       hidg->bInterfaceProtocol = opts->protocol;
+@@ -1313,7 +1313,6 @@ static struct usb_function *hidg_alloc(s
+ err_put_device:
+       put_device(&hidg->dev);
+-err_unlock:
+       mutex_unlock(&opts->lock);
+       return ERR_PTR(ret);
+ }
diff --git a/queue-5.15/usb-gadget-f_hid-tidy-error-handling-in-hidg_alloc.patch b/queue-5.15/usb-gadget-f_hid-tidy-error-handling-in-hidg_alloc.patch
new file mode 100644 (file)
index 0000000..9a5d706
--- /dev/null
@@ -0,0 +1,87 @@
+From sashal@kernel.org Sat Jun  6 01:08:30 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 15:38:25 -0400
+Subject: usb: gadget: f_hid: tidy error handling in hidg_alloc
+To: stable@vger.kernel.org
+Cc: John Keeping <john@metanate.com>, Lee Jones <lee@kernel.org>, Andrzej Pietrasiewicz <andrzej.p@collabora.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260605193826.2169399-1-sashal@kernel.org>
+
+From: John Keeping <john@metanate.com>
+
+[ Upstream commit 944fe915d00d3cb1bacb1e77cabfb6dc82e6f8b8 ]
+
+Unify error handling at the end of the function, reducing the risk of
+missing something on one of the error paths.
+
+Moving the increment of opts->refcnt later means there is no need to
+decrement it on the error path and is safe as this is guarded by
+opts->lock which is held for this entire section.
+
+Tested-by: Lee Jones <lee@kernel.org>
+Reviewed-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
+Reviewed-by: Lee Jones <lee@kernel.org>
+Signed-off-by: John Keeping <john@metanate.com>
+Link: https://lore.kernel.org/r/20221122123523.3068034-4-john@metanate.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 4f88d65def6f ("usb: gadget: f_hid: fix device reference leak in hidg_alloc()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/f_hid.c |   21 +++++++++++----------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+--- a/drivers/usb/gadget/function/f_hid.c
++++ b/drivers/usb/gadget/function/f_hid.c
+@@ -1265,7 +1265,6 @@ static struct usb_function *hidg_alloc(s
+       opts = container_of(fi, struct f_hid_opts, func_inst);
+       mutex_lock(&opts->lock);
+-      ++opts->refcnt;
+       spin_lock_init(&hidg->write_spinlock);
+       spin_lock_init(&hidg->read_spinlock);
+@@ -1278,11 +1277,8 @@ static struct usb_function *hidg_alloc(s
+       hidg->dev.class = hidg_class;
+       hidg->dev.devt = MKDEV(major, opts->minor);
+       ret = dev_set_name(&hidg->dev, "hidg%d", opts->minor);
+-      if (ret) {
+-              --opts->refcnt;
+-              mutex_unlock(&opts->lock);
+-              return ERR_PTR(ret);
+-      }
++      if (ret)
++              goto err_unlock;
+       hidg->bInterfaceSubClass = opts->subclass;
+       hidg->bInterfaceProtocol = opts->protocol;
+@@ -1293,14 +1289,13 @@ static struct usb_function *hidg_alloc(s
+                                           opts->report_desc_length,
+                                           GFP_KERNEL);
+               if (!hidg->report_desc) {
+-                      put_device(&hidg->dev);
+-                      --opts->refcnt;
+-                      mutex_unlock(&opts->lock);
+-                      return ERR_PTR(-ENOMEM);
++                      ret = -ENOMEM;
++                      goto err_put_device;
+               }
+       }
+       hidg->use_out_ep = !opts->no_out_endpoint;
++      ++opts->refcnt;
+       mutex_unlock(&opts->lock);
+       hidg->func.name    = "hid";
+@@ -1315,6 +1310,12 @@ static struct usb_function *hidg_alloc(s
+       hidg->qlen         = 4;
+       return &hidg->func;
++
++err_put_device:
++      put_device(&hidg->dev);
++err_unlock:
++      mutex_unlock(&opts->lock);
++      return ERR_PTR(ret);
+ }
+ DECLARE_USB_FUNCTION_INIT(hid, hidg_alloc_inst, hidg_alloc);
diff --git a/queue-5.15/usb-typec-tcpm-reset-internal-port-states-on-soft-reset-ams.patch b/queue-5.15/usb-typec-tcpm-reset-internal-port-states-on-soft-reset-ams.patch
new file mode 100644 (file)
index 0000000..5db92c1
--- /dev/null
@@ -0,0 +1,90 @@
+From sashal@kernel.org Wed May 13 18:18:29 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 08:48:25 -0400
+Subject: usb: typec: tcpm: reset internal port states on soft reset AMS
+To: stable@vger.kernel.org
+Cc: Amit Sunil Dhamne <amitsd@google.com>, stable <stable@kernel.org>, Badhri Jagan Sridharan <badhri@google.com>, Heikki Krogerus <heikki.krogerus@linux.intel.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260513124826.3711905-1-sashal@kernel.org>
+
+From: Amit Sunil Dhamne <amitsd@google.com>
+
+[ Upstream commit 2909f0d4994fb4306bf116df5ccee797791fce2c ]
+
+Reset internal port states (such as vdm_sm_running and
+explicit_contract) on soft reset AMS as the port needs to negotiate a
+new contract. The consequence of leaving the states in as-is cond are as
+follows:
+  * port is in SRC power role and an explicit contract is negotiated
+    with the port partner (in sink role)
+  * port partner sends a Soft Reset AMS while VDM State Machine is
+    running
+  * port accepts the Soft Reset request and the port advertises src caps
+  * port partner sends a Request message but since the explicit_contract
+    and vdm_sm_running are true from previous negotiation, the port ends
+    up sending Soft Reset instead of Accept msg.
+
+Stub Log:
+[  203.653942] AMS DISCOVER_IDENTITY start
+[  203.653947] PD TX, header: 0x176f
+[  203.655901] PD TX complete, status: 0
+[  203.657470] PD RX, header: 0x124f [1]
+[  203.657477] Rx VDM cmd 0xff008081 type 2 cmd 1 len 1
+[  203.657482] AMS DISCOVER_IDENTITY finished
+[  203.657484] cc:=4
+[  204.155698] PD RX, header: 0x144f [1]
+[  204.155718] Rx VDM cmd 0xeeee8001 type 0 cmd 1 len 1
+[  204.155741] PD TX, header: 0x196f
+[  204.157622] PD TX complete, status: 0
+[  204.160060] PD RX, header: 0x4d [1]
+[  204.160066] state change SRC_READY -> SOFT_RESET [rev2 SOFT_RESET_AMS]
+[  204.160076] PD TX, header: 0x163
+[  204.162486] PD TX complete, status: 0
+[  204.162832] AMS SOFT_RESET_AMS finished
+[  204.162840] cc:=4
+[  204.162891] AMS POWER_NEGOTIATION start
+[  204.162896] state change SOFT_RESET -> AMS_START [rev2 POWER_NEGOTIATION]
+[  204.162908] state change AMS_START -> SRC_SEND_CAPABILITIES [rev2 POWER_NEGOTIATION]
+[  204.162913] PD TX, header: 0x1361
+[  204.165529] PD TX complete, status: 0
+[  204.165571] pending state change SRC_SEND_CAPABILITIES -> SRC_SEND_CAPABILITIES_TIMEOUT @ 60 ms [rev2 POWER_NEGOTIATION]
+[  204.166996] PD RX, header: 0x1242 [1]
+[  204.167009] state change SRC_SEND_CAPABILITIES -> SRC_SOFT_RESET_WAIT_SNK_TX [rev2 POWER_NEGOTIATION]
+[  204.167019] AMS POWER_NEGOTIATION finished
+[  204.167020] cc:=4
+[  204.167083] AMS SOFT_RESET_AMS start
+[  204.167086] state change SRC_SOFT_RESET_WAIT_SNK_TX -> SOFT_RESET_SEND [rev2 SOFT_RESET_AMS]
+[  204.167092] PD TX, header: 0x16d
+[  204.168824] PD TX complete, status: 0
+[  204.168854] pending state change SOFT_RESET_SEND -> HARD_RESET_SEND @ 60 ms [rev2 SOFT_RESET_AMS]
+[  204.171876] PD RX, header: 0x43 [1]
+[  204.171879] AMS SOFT_RESET_AMS finished
+
+This causes COMMON.PROC.PD.11.2 check failure for
+TEST.PD.VDM.SRC.2_Rev2Src test on the PD compliance tester.
+
+Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
+Fixes: 8d3a0578ad1a ("usb: typec: tcpm: Respond Wait if VDM state machine is running")
+Fixes: f0690a25a140 ("staging: typec: USB Type-C Port Manager (tcpm)")
+Cc: stable <stable@kernel.org>
+Reviewed-by: Badhri Jagan Sridharan <badhri@google.com>
+Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Link: https://patch.msgid.link/20260414-fix-soft-reset-v1-1-01d7cb9764e2@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[ kept `tcpm_pd_send_control(port, PD_CTRL_ACCEPT)` call unchanged ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/tcpm/tcpm.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/usb/typec/tcpm/tcpm.c
++++ b/drivers/usb/typec/tcpm/tcpm.c
+@@ -4576,6 +4576,8 @@ static void run_state_machine(struct tcp
+               port->message_id = 0;
+               port->rx_msgid = -1;
+               tcpm_pd_send_control(port, PD_CTRL_ACCEPT);
++              port->vdm_sm_running = false;
++              port->explicit_contract = false;
+               tcpm_ams_finish(port);
+               if (port->pwr_role == TYPEC_SOURCE) {
+                       port->upcoming_state = SRC_SEND_CAPABILITIES;
diff --git a/queue-5.15/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch b/queue-5.15/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch
new file mode 100644 (file)
index 0000000..96b6dad
--- /dev/null
@@ -0,0 +1,69 @@
+From stable+bounces-260824-greg=kroah.com@vger.kernel.org Sat Jun  6 02:04:37 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 16:34:10 -0400
+Subject: usb: typec: ucsi: Check if power role change actually happened before handling
+To: stable@vger.kernel.org
+Cc: Myrrh Periwinkle <myrrhperiwinkle@qtmlabs.xyz>, stable <stable@kernel.org>, Sergey Senozhatsky <senozhatsky@chromium.org>, Heikki Krogerus <heikki.krogerus@linux.intel.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260605203410.2224712-1-sashal@kernel.org>
+
+From: Myrrh Periwinkle <myrrhperiwinkle@qtmlabs.xyz>
+
+[ Upstream commit b80e7d34c7ea6a564525119d6138fbb577a23dba ]
+
+The CrOS EC may send a connector status change event with the power
+direction changed flag set even if the power direction hasn't actually
+changed after initiating a SET_PDR command internally [1]. In practice
+this happens on every system suspend due to other changes performed by
+the EC [2][3][4], causing suspend to fail.
+
+Fix this by checking if the power role change actually happened before
+handling it.
+
+[1]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=1689;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794
+[2]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=3923;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794
+[3]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=5094;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794
+[4]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=2229;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794
+
+Cc: stable <stable@kernel.org>
+Fixes: 7616f006db07 ("usb: typec: ucsi: Update power_supply on power role change")
+Signed-off-by: Myrrh Periwinkle <myrrhperiwinkle@qtmlabs.xyz>
+Reported-and-tested-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Link: https://patch.msgid.link/20260519-ucsi-fix-2-v1-1-6f1239535187@qtmlabs.xyz
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c |    7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -669,7 +669,7 @@ static void ucsi_handle_connector_change
+       struct ucsi *ucsi = con->ucsi;
+       struct ucsi_connector_status pre_ack_status;
+       struct ucsi_connector_status post_ack_status;
+-      enum typec_role role;
++      enum typec_role role, prev_role;
+       enum usb_role u_role = USB_ROLE_NONE;
+       u16 inferred_changes;
+       u16 changed_flags;
+@@ -706,6 +706,8 @@ static void ucsi_handle_connector_change
+        * short transitional changes.
+        */
++      prev_role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR);
++
+       /* 1. First UCSI_GET_CONNECTOR_STATUS */
+       command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num);
+       ret = ucsi_send_command(ucsi, command, &pre_ack_status,
+@@ -783,7 +785,8 @@ static void ucsi_handle_connector_change
+               ucsi_port_psy_changed(con);
+       }
+-      if (con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) {
++      if ((con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) &&
++          role != prev_role) {
+               typec_set_pwr_role(con->port, role);
+               /* Complete pending power role swap */
diff --git a/queue-5.15/use-less-confusing-names-for-iov_iter-direction-initializers.patch b/queue-5.15/use-less-confusing-names-for-iov_iter-direction-initializers.patch
new file mode 100644 (file)
index 0000000..c191567
--- /dev/null
@@ -0,0 +1,1624 @@
+From stable+bounces-256875-greg=kroah.com@vger.kernel.org Sat May 30 17:12:20 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 07:40:43 -0400
+Subject: use less confusing names for iov_iter direction initializers
+To: stable@vger.kernel.org
+Cc: Al Viro <viro@zeniv.linux.org.uk>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530114046.1945359-1-sashal@kernel.org>
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+[ Upstream commit de4eda9de2d957ef2d6a8365a01e26a435e958cb ]
+
+READ/WRITE proved to be actively confusing - the meanings are
+"data destination, as used with read(2)" and "data source, as
+used with write(2)", but people keep interpreting those as
+"we read data from it" and "we write data to it", i.e. exactly
+the wrong way.
+
+Call them ITER_DEST and ITER_SOURCE - at least that is harder
+to misinterpret...
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Stable-dep-of: a4f0b001782b ("vsock/virtio: reset connection on receiving queue overflow")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kernel/cpu/microcode/intel.c    |    4 ++--
+ crypto/testmgr.c                         |    4 ++--
+ drivers/block/drbd/drbd_main.c           |    2 +-
+ drivers/block/drbd/drbd_receiver.c       |    2 +-
+ drivers/block/loop.c                     |   14 +++++++-------
+ drivers/block/nbd.c                      |   10 +++++-----
+ drivers/char/random.c                    |    4 ++--
+ drivers/fsi/fsi-sbefifo.c                |    6 +++---
+ drivers/infiniband/ulp/rtrs/rtrs-clt.c   |    2 +-
+ drivers/isdn/mISDN/l1oip_core.c          |    2 +-
+ drivers/misc/vmw_vmci/vmci_queue_pair.c  |    6 +++---
+ drivers/net/ppp/ppp_generic.c            |    2 +-
+ drivers/nvme/host/tcp.c                  |    4 ++--
+ drivers/nvme/target/io-cmd-file.c        |    4 ++--
+ drivers/nvme/target/tcp.c                |    2 +-
+ drivers/scsi/sg.c                        |    2 +-
+ drivers/target/iscsi/iscsi_target_util.c |    4 ++--
+ drivers/target/target_core_file.c        |    2 +-
+ drivers/usb/usbip/usbip_common.c         |    2 +-
+ drivers/vhost/net.c                      |    6 +++---
+ drivers/vhost/scsi.c                     |   10 +++++-----
+ drivers/vhost/vhost.c                    |    6 +++---
+ drivers/vhost/vringh.c                   |    4 ++--
+ drivers/vhost/vsock.c                    |    4 ++--
+ drivers/xen/pvcalls-back.c               |    8 ++++----
+ fs/9p/vfs_addr.c                         |    4 ++--
+ fs/9p/vfs_dir.c                          |    2 +-
+ fs/9p/xattr.c                            |    4 ++--
+ fs/afs/cmservice.c                       |    2 +-
+ fs/afs/dir.c                             |    2 +-
+ fs/afs/file.c                            |    4 ++--
+ fs/afs/internal.h                        |    4 ++--
+ fs/afs/rxrpc.c                           |   10 +++++-----
+ fs/afs/write.c                           |    4 ++--
+ fs/aio.c                                 |    4 ++--
+ fs/ceph/addr.c                           |    2 +-
+ fs/ceph/file.c                           |    4 ++--
+ fs/cifs/connect.c                        |    6 +++---
+ fs/cifs/file.c                           |    4 ++--
+ fs/cifs/smb2ops.c                        |    4 ++--
+ fs/cifs/transport.c                      |    6 +++---
+ fs/fuse/ioctl.c                          |    4 ++--
+ fs/nfsd/vfs.c                            |    4 ++--
+ fs/ocfs2/cluster/tcp.c                   |    2 +-
+ fs/orangefs/inode.c                      |    8 ++++----
+ fs/read_write.c                          |   12 ++++++------
+ fs/seq_file.c                            |    2 +-
+ fs/splice.c                              |   10 +++++-----
+ include/linux/uio.h                      |    3 +++
+ mm/madvise.c                             |    2 +-
+ mm/page_io.c                             |    2 +-
+ mm/process_vm_access.c                   |    2 +-
+ net/9p/client.c                          |    2 +-
+ net/bluetooth/6lowpan.c                  |    2 +-
+ net/bluetooth/a2mp.c                     |    2 +-
+ net/bluetooth/smp.c                      |    2 +-
+ net/ceph/messenger_v1.c                  |    4 ++--
+ net/ceph/messenger_v2.c                  |   14 +++++++-------
+ net/compat.c                             |    2 +-
+ net/ipv4/tcp.c                           |    4 ++--
+ net/netfilter/ipvs/ip_vs_sync.c          |    2 +-
+ net/smc/smc_clc.c                        |    6 +++---
+ net/socket.c                             |   12 ++++++------
+ net/sunrpc/socklib.c                     |    6 +++---
+ net/sunrpc/svcsock.c                     |    4 ++--
+ net/sunrpc/xprtsock.c                    |    6 +++---
+ net/tipc/topsrv.c                        |    2 +-
+ net/tls/tls_device.c                     |    4 ++--
+ net/xfrm/espintcp.c                      |    2 +-
+ security/keys/keyctl.c                   |    4 ++--
+ 70 files changed, 158 insertions(+), 155 deletions(-)
+
+--- a/arch/x86/kernel/cpu/microcode/intel.c
++++ b/arch/x86/kernel/cpu/microcode/intel.c
+@@ -940,7 +940,7 @@ static enum ucode_state request_microcod
+       kvec.iov_base = (void *)firmware->data;
+       kvec.iov_len = firmware->size;
+-      iov_iter_kvec(&iter, WRITE, &kvec, 1, firmware->size);
++      iov_iter_kvec(&iter, ITER_SOURCE, &kvec, 1, firmware->size);
+       ret = generic_load_microcode(cpu, &iter);
+       release_firmware(firmware);
+@@ -959,7 +959,7 @@ request_microcode_user(int cpu, const vo
+       iov.iov_base = (void __user *)buf;
+       iov.iov_len = size;
+-      iov_iter_init(&iter, WRITE, &iov, 1, size);
++      iov_iter_init(&iter, ITER_SOURCE, &iov, 1, size);
+       return generic_load_microcode(cpu, &iter);
+ }
+--- a/crypto/testmgr.c
++++ b/crypto/testmgr.c
+@@ -750,7 +750,7 @@ static int build_cipher_test_sglists(str
+       struct iov_iter input;
+       int err;
+-      iov_iter_kvec(&input, WRITE, inputs, nr_inputs, src_total_len);
++      iov_iter_kvec(&input, ITER_SOURCE, inputs, nr_inputs, src_total_len);
+       err = build_test_sglist(&tsgls->src, cfg->src_divs, alignmask,
+                               cfg->inplace ?
+                                       max(dst_total_len, src_total_len) :
+@@ -1133,7 +1133,7 @@ static int build_hash_sglist(struct test
+       kv.iov_base = (void *)vec->plaintext;
+       kv.iov_len = vec->psize;
+-      iov_iter_kvec(&input, WRITE, &kv, 1, vec->psize);
++      iov_iter_kvec(&input, ITER_SOURCE, &kv, 1, vec->psize);
+       return build_test_sglist(tsgl, cfg->src_divs, alignmask, vec->psize,
+                                &input, divs);
+ }
+--- a/drivers/block/drbd/drbd_main.c
++++ b/drivers/block/drbd/drbd_main.c
+@@ -1843,7 +1843,7 @@ int drbd_send(struct drbd_connection *co
+       /* THINK  if (signal_pending) return ... ? */
+-      iov_iter_kvec(&msg.msg_iter, WRITE, &iov, 1, size);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iov, 1, size);
+       if (sock == connection->data.socket) {
+               rcu_read_lock();
+--- a/drivers/block/drbd/drbd_receiver.c
++++ b/drivers/block/drbd/drbd_receiver.c
+@@ -507,7 +507,7 @@ static int drbd_recv_short(struct socket
+       struct msghdr msg = {
+               .msg_flags = (flags ? flags : MSG_WAITALL | MSG_NOSIGNAL)
+       };
+-      iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, size);
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, size);
+       return sock_recvmsg(sock, &msg, msg.msg_flags);
+ }
+--- a/drivers/block/loop.c
++++ b/drivers/block/loop.c
+@@ -310,7 +310,7 @@ static int lo_write_bvec(struct file *fi
+       struct iov_iter i;
+       ssize_t bw;
+-      iov_iter_bvec(&i, WRITE, bvec, 1, bvec->bv_len);
++      iov_iter_bvec(&i, ITER_SOURCE, bvec, 1, bvec->bv_len);
+       file_start_write(file);
+       bw = vfs_iter_write(file, &i, ppos, 0);
+@@ -388,7 +388,7 @@ static int lo_read_simple(struct loop_de
+       ssize_t len;
+       rq_for_each_segment(bvec, rq, iter) {
+-              iov_iter_bvec(&i, READ, &bvec, 1, bvec.bv_len);
++              iov_iter_bvec(&i, ITER_DEST, &bvec, 1, bvec.bv_len);
+               len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0);
+               if (len < 0)
+                       return len;
+@@ -429,7 +429,7 @@ static int lo_read_transfer(struct loop_
+               b.bv_offset = 0;
+               b.bv_len = bvec.bv_len;
+-              iov_iter_bvec(&i, READ, &b, 1, b.bv_len);
++              iov_iter_bvec(&i, ITER_DEST, &b, 1, b.bv_len);
+               len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0);
+               if (len < 0) {
+                       ret = len;
+@@ -551,7 +551,7 @@ static void lo_rw_aio_complete(struct ki
+ }
+ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
+-                   loff_t pos, bool rw)
++                   loff_t pos, int rw)
+ {
+       struct iov_iter iter;
+       struct req_iterator rq_iter;
+@@ -607,7 +607,7 @@ static int lo_rw_aio(struct loop_device
+       cmd->iocb.ki_flags = IOCB_DIRECT;
+       cmd->iocb.ki_ioprio = req_get_ioprio(rq);
+-      if (rw == WRITE)
++      if (rw == ITER_SOURCE)
+               ret = call_write_iter(file, &cmd->iocb, &iter);
+       else
+               ret = call_read_iter(file, &cmd->iocb, &iter);
+@@ -651,14 +651,14 @@ static int do_req_filebacked(struct loop
+               if (lo->transfer)
+                       return lo_write_transfer(lo, rq, pos);
+               else if (cmd->use_aio)
+-                      return lo_rw_aio(lo, cmd, pos, WRITE);
++                      return lo_rw_aio(lo, cmd, pos, ITER_SOURCE);
+               else
+                       return lo_write_simple(lo, rq, pos);
+       case REQ_OP_READ:
+               if (lo->transfer)
+                       return lo_read_transfer(lo, rq, pos);
+               else if (cmd->use_aio)
+-                      return lo_rw_aio(lo, cmd, pos, READ);
++                      return lo_rw_aio(lo, cmd, pos, ITER_DEST);
+               else
+                       return lo_read_simple(lo, rq, pos);
+       default:
+--- a/drivers/block/nbd.c
++++ b/drivers/block/nbd.c
+@@ -562,7 +562,7 @@ static int nbd_send_cmd(struct nbd_devic
+       u32 nbd_cmd_flags = 0;
+       int sent = nsock->sent, skip = 0;
+-      iov_iter_kvec(&from, WRITE, &iov, 1, sizeof(request));
++      iov_iter_kvec(&from, ITER_SOURCE, &iov, 1, sizeof(request));
+       type = req_to_nbd_cmd_type(req);
+       if (type == U32_MAX)
+@@ -648,7 +648,7 @@ send_pages:
+                       dev_dbg(nbd_to_dev(nbd), "request %p: sending %d bytes data\n",
+                               req, bvec.bv_len);
+-                      iov_iter_bvec(&from, WRITE, &bvec, 1, bvec.bv_len);
++                      iov_iter_bvec(&from, ITER_SOURCE, &bvec, 1, bvec.bv_len);
+                       if (skip) {
+                               if (skip >= iov_iter_count(&from)) {
+                                       skip -= iov_iter_count(&from);
+@@ -700,7 +700,7 @@ static int nbd_read_reply(struct nbd_dev
+       int result;
+       reply->magic = 0;
+-      iov_iter_kvec(&to, READ, &iov, 1, sizeof(*reply));
++      iov_iter_kvec(&to, ITER_DEST, &iov, 1, sizeof(*reply));
+       result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL);
+       if (result < 0) {
+               if (!nbd_disconnected(nbd->config))
+@@ -777,7 +777,7 @@ static struct nbd_cmd *nbd_handle_reply(
+               struct iov_iter to;
+               rq_for_each_segment(bvec, req, iter) {
+-                      iov_iter_bvec(&to, READ, &bvec, 1, bvec.bv_len);
++                      iov_iter_bvec(&to, ITER_DEST, &bvec, 1, bvec.bv_len);
+                       result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL);
+                       if (result < 0) {
+                               dev_err(disk_to_dev(nbd->disk), "Receive data failed (result %d)\n",
+@@ -1228,7 +1228,7 @@ static void send_disconnects(struct nbd_
+       for (i = 0; i < config->num_connections; i++) {
+               struct nbd_sock *nsock = config->socks[i];
+-              iov_iter_kvec(&from, WRITE, &iov, 1, sizeof(request));
++              iov_iter_kvec(&from, ITER_SOURCE, &iov, 1, sizeof(request));
+               mutex_lock(&nsock->tx_lock);
+               ret = sock_xmit(nbd, i, 1, &from, 0, NULL);
+               if (ret < 0)
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -1236,7 +1236,7 @@ SYSCALL_DEFINE3(getrandom, char __user *
+                       return ret;
+       }
+-      ret = import_single_range(READ, ubuf, len, &iov, &iter);
++      ret = import_single_range(ITER_DEST, ubuf, len, &iov, &iter);
+       if (unlikely(ret))
+               return ret;
+       return get_random_bytes_user(&iter);
+@@ -1347,7 +1347,7 @@ static long random_ioctl(struct file *f,
+                       return -EINVAL;
+               if (get_user(len, p++))
+                       return -EFAULT;
+-              ret = import_single_range(WRITE, p, len, &iov, &iter);
++              ret = import_single_range(ITER_SOURCE, p, len, &iov, &iter);
+               if (unlikely(ret))
+                       return ret;
+               ret = write_pool_user(&iter);
+--- a/drivers/fsi/fsi-sbefifo.c
++++ b/drivers/fsi/fsi-sbefifo.c
+@@ -640,7 +640,7 @@ static void sbefifo_collect_async_ffdc(s
+       }
+         ffdc_iov.iov_base = ffdc;
+       ffdc_iov.iov_len = SBEFIFO_MAX_FFDC_SIZE;
+-        iov_iter_kvec(&ffdc_iter, READ, &ffdc_iov, 1, SBEFIFO_MAX_FFDC_SIZE);
++        iov_iter_kvec(&ffdc_iter, ITER_DEST, &ffdc_iov, 1, SBEFIFO_MAX_FFDC_SIZE);
+       cmd[0] = cpu_to_be32(2);
+       cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_SBE_FFDC);
+       rc = sbefifo_do_command(sbefifo, cmd, 2, &ffdc_iter);
+@@ -737,7 +737,7 @@ int sbefifo_submit(struct device *dev, c
+       rbytes = (*resp_len) * sizeof(__be32);
+       resp_iov.iov_base = response;
+       resp_iov.iov_len = rbytes;
+-        iov_iter_kvec(&resp_iter, READ, &resp_iov, 1, rbytes);
++        iov_iter_kvec(&resp_iter, ITER_DEST, &resp_iov, 1, rbytes);
+       /* Perform the command */
+       mutex_lock(&sbefifo->lock);
+@@ -817,7 +817,7 @@ static ssize_t sbefifo_user_read(struct
+       /* Prepare iov iterator */
+       resp_iov.iov_base = buf;
+       resp_iov.iov_len = len;
+-      iov_iter_init(&resp_iter, READ, &resp_iov, 1, len);
++      iov_iter_init(&resp_iter, ITER_DEST, &resp_iov, 1, len);
+       /* Perform the command */
+       mutex_lock(&sbefifo->lock);
+--- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c
++++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
+@@ -968,7 +968,7 @@ static void rtrs_clt_init_req(struct rtr
+       refcount_set(&req->ref, 1);
+       req->mp_policy = clt_path->clt->mp_policy;
+-      iov_iter_kvec(&iter, WRITE, vec, 1, usr_len);
++      iov_iter_kvec(&iter, ITER_SOURCE, vec, 1, usr_len);
+       len = _copy_from_iter(req->iu->buf, usr_len, &iter);
+       WARN_ON(len != usr_len);
+--- a/drivers/isdn/mISDN/l1oip_core.c
++++ b/drivers/isdn/mISDN/l1oip_core.c
+@@ -706,7 +706,7 @@ l1oip_socket_thread(void *data)
+               printk(KERN_DEBUG "%s: socket created and open\n",
+                      __func__);
+       while (!signal_pending(current)) {
+-              iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, recvbuf_size);
++              iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, recvbuf_size);
+               recvlen = sock_recvmsg(socket, &msg, 0);
+               if (recvlen > 0) {
+                       l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen);
+--- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
++++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
+@@ -3032,7 +3032,7 @@ ssize_t vmci_qpair_enqueue(struct vmci_q
+       if (!qpair || !buf)
+               return VMCI_ERROR_INVALID_ARGS;
+-      iov_iter_kvec(&from, WRITE, &v, 1, buf_size);
++      iov_iter_kvec(&from, ITER_SOURCE, &v, 1, buf_size);
+       qp_lock(qpair);
+@@ -3076,7 +3076,7 @@ ssize_t vmci_qpair_dequeue(struct vmci_q
+       if (!qpair || !buf)
+               return VMCI_ERROR_INVALID_ARGS;
+-      iov_iter_kvec(&to, READ, &v, 1, buf_size);
++      iov_iter_kvec(&to, ITER_DEST, &v, 1, buf_size);
+       qp_lock(qpair);
+@@ -3121,7 +3121,7 @@ ssize_t vmci_qpair_peek(struct vmci_qp *
+       if (!qpair || !buf)
+               return VMCI_ERROR_INVALID_ARGS;
+-      iov_iter_kvec(&to, READ, &v, 1, buf_size);
++      iov_iter_kvec(&to, ITER_DEST, &v, 1, buf_size);
+       qp_lock(qpair);
+--- a/drivers/net/ppp/ppp_generic.c
++++ b/drivers/net/ppp/ppp_generic.c
+@@ -492,7 +492,7 @@ static ssize_t ppp_read(struct file *fil
+       ret = -EFAULT;
+       iov.iov_base = buf;
+       iov.iov_len = count;
+-      iov_iter_init(&to, READ, &iov, 1, count);
++      iov_iter_init(&to, ITER_DEST, &iov, 1, count);
+       if (skb_copy_datagram_iter(skb, 0, &to, skb->len))
+               goto outf;
+       ret = skb->len;
+--- a/drivers/nvme/host/tcp.c
++++ b/drivers/nvme/host/tcp.c
+@@ -297,7 +297,7 @@ static inline void nvme_tcp_advance_req(
+       if (!iov_iter_count(&req->iter) &&
+           req->data_sent < req->data_len) {
+               req->curr_bio = req->curr_bio->bi_next;
+-              nvme_tcp_init_iter(req, WRITE);
++              nvme_tcp_init_iter(req, ITER_SOURCE);
+       }
+ }
+@@ -775,7 +775,7 @@ static int nvme_tcp_recv_data(struct nvm
+                               nvme_tcp_init_recv_ctx(queue);
+                               return -EIO;
+                       }
+-                      nvme_tcp_init_iter(req, READ);
++                      nvme_tcp_init_iter(req, ITER_DEST);
+               }
+               /* we can read only from what is left in this bio */
+--- a/drivers/nvme/target/io-cmd-file.c
++++ b/drivers/nvme/target/io-cmd-file.c
+@@ -92,10 +92,10 @@ static ssize_t nvmet_file_submit_bvec(st
+               if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
+                       ki_flags |= IOCB_DSYNC;
+               call_iter = req->ns->file->f_op->write_iter;
+-              rw = WRITE;
++              rw = ITER_SOURCE;
+       } else {
+               call_iter = req->ns->file->f_op->read_iter;
+-              rw = READ;
++              rw = ITER_DEST;
+       }
+       iov_iter_bvec(&iter, rw, req->f.bvec, nr_segs, count);
+--- a/drivers/nvme/target/tcp.c
++++ b/drivers/nvme/target/tcp.c
+@@ -351,7 +351,7 @@ static void nvmet_tcp_build_pdu_iovec(st
+               sg_offset = 0;
+       }
+-      iov_iter_bvec(&cmd->recv_msg.msg_iter, READ, cmd->iov,
++      iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov,
+                     nr_pages, cmd->pdu_len);
+ }
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -1721,7 +1721,7 @@ sg_start_req(Sg_request *srp, unsigned c
+       Sg_scatter_hold *rsv_schp = &sfp->reserve;
+       struct request_queue *q = sfp->parentdp->device->request_queue;
+       struct rq_map_data *md, map_data;
+-      int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? WRITE : READ;
++      int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? ITER_SOURCE : ITER_DEST;
+       unsigned char *long_cmdp = NULL;
+       SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
+--- a/drivers/target/iscsi/iscsi_target_util.c
++++ b/drivers/target/iscsi/iscsi_target_util.c
+@@ -1231,7 +1231,7 @@ int rx_data(
+               return -1;
+       memset(&msg, 0, sizeof(struct msghdr));
+-      iov_iter_kvec(&msg.msg_iter, READ, iov, iov_count, data);
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, iov, iov_count, data);
+       while (msg_data_left(&msg)) {
+               rx_loop = sock_recvmsg(conn->sock, &msg, MSG_WAITALL);
+@@ -1267,7 +1267,7 @@ int tx_data(
+       memset(&msg, 0, sizeof(struct msghdr));
+-      iov_iter_kvec(&msg.msg_iter, WRITE, iov, iov_count, data);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, iov_count, data);
+       while (msg_data_left(&msg)) {
+               int tx_loop = sock_sendmsg(conn->sock, &msg);
+--- a/drivers/target/target_core_file.c
++++ b/drivers/target/target_core_file.c
+@@ -472,7 +472,7 @@ fd_execute_write_same(struct se_cmd *cmd
+               len += se_dev->dev_attrib.block_size;
+       }
+-      iov_iter_bvec(&iter, WRITE, bvec, nolb, len);
++      iov_iter_bvec(&iter, ITER_SOURCE, bvec, nolb, len);
+       ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos, 0);
+       kfree(bvec);
+--- a/drivers/usb/usbip/usbip_common.c
++++ b/drivers/usb/usbip/usbip_common.c
+@@ -309,7 +309,7 @@ int usbip_recv(struct socket *sock, void
+       if (!sock || !buf || !size)
+               return -EINVAL;
+-      iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, size);
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, size);
+       usbip_dbg_xmit("enter\n");
+--- a/drivers/vhost/net.c
++++ b/drivers/vhost/net.c
+@@ -615,7 +615,7 @@ static size_t init_iov_iter(struct vhost
+       /* Skip header. TODO: support TSO. */
+       size_t len = iov_length(vq->iov, out);
+-      iov_iter_init(iter, WRITE, vq->iov, out, len);
++      iov_iter_init(iter, ITER_SOURCE, vq->iov, out, len);
+       iov_iter_advance(iter, hdr_size);
+       return iov_iter_count(iter);
+@@ -1193,14 +1193,14 @@ static void handle_rx(struct vhost_net *
+                       msg.msg_control = vhost_net_buf_consume(&nvq->rxq);
+               /* On overrun, truncate and discard */
+               if (unlikely(headcount > UIO_MAXIOV)) {
+-                      iov_iter_init(&msg.msg_iter, READ, vq->iov, 1, 1);
++                      iov_iter_init(&msg.msg_iter, ITER_DEST, vq->iov, 1, 1);
+                       err = sock->ops->recvmsg(sock, &msg,
+                                                1, MSG_DONTWAIT | MSG_TRUNC);
+                       pr_debug("Discarded rx packet: len %zd\n", sock_len);
+                       continue;
+               }
+               /* We don't need to be notified again. */
+-              iov_iter_init(&msg.msg_iter, READ, vq->iov, in, vhost_len);
++              iov_iter_init(&msg.msg_iter, ITER_DEST, vq->iov, in, vhost_len);
+               fixup = msg.msg_iter;
+               if (unlikely((vhost_hlen))) {
+                       /* We will supply the header ourselves
+--- a/drivers/vhost/scsi.c
++++ b/drivers/vhost/scsi.c
+@@ -558,7 +558,7 @@ static void vhost_scsi_complete_cmd_work
+               memcpy(v_rsp.sense, cmd->tvc_sense_buf,
+                      se_cmd->scsi_sense_length);
+-              iov_iter_init(&iov_iter, READ, &cmd->tvc_resp_iov,
++              iov_iter_init(&iov_iter, ITER_DEST, &cmd->tvc_resp_iov,
+                             cmd->tvc_in_iovs, sizeof(v_rsp));
+               ret = copy_to_iter(&v_rsp, sizeof(v_rsp), &iov_iter);
+               if (likely(ret == sizeof(v_rsp))) {
+@@ -863,7 +863,7 @@ vhost_scsi_get_desc(struct vhost_scsi *v
+        * point at the start of the outgoing WRITE payload, if
+        * DMA_TO_DEVICE is set.
+        */
+-      iov_iter_init(&vc->out_iter, WRITE, vq->iov, vc->out, vc->out_size);
++      iov_iter_init(&vc->out_iter, ITER_SOURCE, vq->iov, vc->out, vc->out_size);
+       ret = 0;
+ done:
+@@ -1016,7 +1016,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *
+                       data_direction = DMA_FROM_DEVICE;
+                       exp_data_len = vc.in_size - vc.rsp_size;
+-                      iov_iter_init(&in_iter, READ, &vq->iov[vc.out], vc.in,
++                      iov_iter_init(&in_iter, ITER_DEST, &vq->iov[vc.out], vc.in,
+                                     vc.rsp_size + exp_data_len);
+                       iov_iter_advance(&in_iter, vc.rsp_size);
+                       data_iter = in_iter;
+@@ -1146,7 +1146,7 @@ vhost_scsi_send_tmf_resp(struct vhost_sc
+       memset(&rsp, 0, sizeof(rsp));
+       rsp.response = tmf_resp_code;
+-      iov_iter_init(&iov_iter, READ, resp_iov, in_iovs, sizeof(rsp));
++      iov_iter_init(&iov_iter, ITER_DEST, resp_iov, in_iovs, sizeof(rsp));
+       ret = copy_to_iter(&rsp, sizeof(rsp), &iov_iter);
+       if (likely(ret == sizeof(rsp)))
+@@ -1241,7 +1241,7 @@ vhost_scsi_send_an_resp(struct vhost_scs
+       memset(&rsp, 0, sizeof(rsp));   /* event_actual = 0 */
+       rsp.response = VIRTIO_SCSI_S_OK;
+-      iov_iter_init(&iov_iter, READ, &vq->iov[vc->out], vc->in, sizeof(rsp));
++      iov_iter_init(&iov_iter, ITER_DEST, &vq->iov[vc->out], vc->in, sizeof(rsp));
+       ret = copy_to_iter(&rsp, sizeof(rsp), &iov_iter);
+       if (likely(ret == sizeof(rsp)))
+--- a/drivers/vhost/vhost.c
++++ b/drivers/vhost/vhost.c
+@@ -841,7 +841,7 @@ static int vhost_copy_to_user(struct vho
+                                    VHOST_ACCESS_WO);
+               if (ret < 0)
+                       goto out;
+-              iov_iter_init(&t, WRITE, vq->iotlb_iov, ret, size);
++              iov_iter_init(&t, ITER_SOURCE, vq->iotlb_iov, ret, size);
+               ret = copy_to_iter(from, size, &t);
+               if (ret == size)
+                       ret = 0;
+@@ -880,7 +880,7 @@ static int vhost_copy_from_user(struct v
+                              (unsigned long long) size);
+                       goto out;
+               }
+-              iov_iter_init(&f, READ, vq->iotlb_iov, ret, size);
++              iov_iter_init(&f, ITER_DEST, vq->iotlb_iov, ret, size);
+               ret = copy_from_iter(to, size, &f);
+               if (ret == size)
+                       ret = 0;
+@@ -2137,7 +2137,7 @@ static int get_indirect(struct vhost_vir
+                       vq_err(vq, "Translation failure %d in indirect.\n", ret);
+               return ret;
+       }
+-      iov_iter_init(&from, READ, vq->indirect, ret, len);
++      iov_iter_init(&from, ITER_DEST, vq->indirect, ret, len);
+       count = len / sizeof desc;
+       /* Buffers are chained via a 16 bit next field, so
+        * we can have at most 2^16 of these. */
+--- a/drivers/vhost/vringh.c
++++ b/drivers/vhost/vringh.c
+@@ -1160,7 +1160,7 @@ static inline int copy_from_iotlb(const
+       if (ret < 0)
+               return ret;
+-      iov_iter_bvec(&iter, READ, iov, ret, len);
++      iov_iter_bvec(&iter, ITER_DEST, iov, ret, len);
+       ret = copy_from_iter(dst, len, &iter);
+@@ -1179,7 +1179,7 @@ static inline int copy_to_iotlb(const st
+       if (ret < 0)
+               return ret;
+-      iov_iter_bvec(&iter, WRITE, iov, ret, len);
++      iov_iter_bvec(&iter, ITER_SOURCE, iov, ret, len);
+       return copy_to_iter(src, len, &iter);
+ }
+--- a/drivers/vhost/vsock.c
++++ b/drivers/vhost/vsock.c
+@@ -166,7 +166,7 @@ vhost_transport_do_send_pkt(struct vhost
+                       break;
+               }
+-              iov_iter_init(&iov_iter, READ, &vq->iov[out], in, iov_len);
++              iov_iter_init(&iov_iter, ITER_DEST, &vq->iov[out], in, iov_len);
+               payload_len = pkt->len - pkt->off;
+               /* If the packet is greater than the space available in the
+@@ -372,7 +372,7 @@ vhost_vsock_alloc_pkt(struct vhost_virtq
+               return NULL;
+       len = iov_length(vq->iov, out);
+-      iov_iter_init(&iov_iter, WRITE, vq->iov, out, len);
++      iov_iter_init(&iov_iter, ITER_SOURCE, vq->iov, out, len);
+       nbytes = copy_from_iter(&pkt->hdr, sizeof(pkt->hdr), &iov_iter);
+       if (nbytes != sizeof(pkt->hdr)) {
+--- a/drivers/xen/pvcalls-back.c
++++ b/drivers/xen/pvcalls-back.c
+@@ -129,13 +129,13 @@ static bool pvcalls_conn_back_read(void
+       if (masked_prod < masked_cons) {
+               vec[0].iov_base = data->in + masked_prod;
+               vec[0].iov_len = wanted;
+-              iov_iter_kvec(&msg.msg_iter, READ, vec, 1, wanted);
++              iov_iter_kvec(&msg.msg_iter, ITER_DEST, vec, 1, wanted);
+       } else {
+               vec[0].iov_base = data->in + masked_prod;
+               vec[0].iov_len = array_size - masked_prod;
+               vec[1].iov_base = data->in;
+               vec[1].iov_len = wanted - vec[0].iov_len;
+-              iov_iter_kvec(&msg.msg_iter, READ, vec, 2, wanted);
++              iov_iter_kvec(&msg.msg_iter, ITER_DEST, vec, 2, wanted);
+       }
+       atomic_set(&map->read, 0);
+@@ -188,13 +188,13 @@ static bool pvcalls_conn_back_write(stru
+       if (pvcalls_mask(prod, array_size) > pvcalls_mask(cons, array_size)) {
+               vec[0].iov_base = data->out + pvcalls_mask(cons, array_size);
+               vec[0].iov_len = size;
+-              iov_iter_kvec(&msg.msg_iter, WRITE, vec, 1, size);
++              iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, vec, 1, size);
+       } else {
+               vec[0].iov_base = data->out + pvcalls_mask(cons, array_size);
+               vec[0].iov_len = array_size - pvcalls_mask(cons, array_size);
+               vec[1].iov_base = data->out;
+               vec[1].iov_len = size - vec[0].iov_len;
+-              iov_iter_kvec(&msg.msg_iter, WRITE, vec, 2, size);
++              iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, vec, 2, size);
+       }
+       atomic_set(&map->write, 0);
+--- a/fs/9p/vfs_addr.c
++++ b/fs/9p/vfs_addr.c
+@@ -50,7 +50,7 @@ static int v9fs_fid_readpage(void *data,
+       if (retval == 0)
+               return retval;
+-      iov_iter_bvec(&to, READ, &bvec, 1, PAGE_SIZE);
++      iov_iter_bvec(&to, ITER_DEST, &bvec, 1, PAGE_SIZE);
+       retval = p9_client_read(fid, page_offset(page), &to, &err);
+       if (err) {
+@@ -163,7 +163,7 @@ static int v9fs_vfs_writepage_locked(str
+       bvec.bv_page = page;
+       bvec.bv_offset = 0;
+       bvec.bv_len = len;
+-      iov_iter_bvec(&from, WRITE, &bvec, 1, len);
++      iov_iter_bvec(&from, ITER_SOURCE, &bvec, 1, len);
+       /* We should have writeback_fid always set */
+       BUG_ON(!v9inode->writeback_fid);
+--- a/fs/9p/vfs_dir.c
++++ b/fs/9p/vfs_dir.c
+@@ -108,7 +108,7 @@ static int v9fs_dir_readdir(struct file
+               if (rdir->tail == rdir->head) {
+                       struct iov_iter to;
+                       int n;
+-                      iov_iter_kvec(&to, READ, &kvec, 1, buflen);
++                      iov_iter_kvec(&to, ITER_DEST, &kvec, 1, buflen);
+                       n = p9_client_read(file->private_data, ctx->pos, &to,
+                                          &err);
+                       if (err)
+--- a/fs/9p/xattr.c
++++ b/fs/9p/xattr.c
+@@ -32,7 +32,7 @@ ssize_t v9fs_fid_xattr_get(struct p9_fid
+       struct iov_iter to;
+       int err;
+-      iov_iter_kvec(&to, READ, &kvec, 1, buffer_size);
++      iov_iter_kvec(&to, ITER_DEST, &kvec, 1, buffer_size);
+       attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
+       if (IS_ERR(attr_fid)) {
+@@ -117,7 +117,7 @@ int v9fs_fid_xattr_set(struct p9_fid *fi
+       struct iov_iter from;
+       int retval, err;
+-      iov_iter_kvec(&from, WRITE, &kvec, 1, value_len);
++      iov_iter_kvec(&from, ITER_SOURCE, &kvec, 1, value_len);
+       p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu flags = %d\n",
+                name, value_len, flags);
+--- a/fs/afs/cmservice.c
++++ b/fs/afs/cmservice.c
+@@ -298,7 +298,7 @@ static int afs_deliver_cb_callback(struc
+               if (call->count2 != call->count && call->count2 != 0)
+                       return afs_protocol_error(call, afs_eproto_cb_count);
+               call->iter = &call->def_iter;
+-              iov_iter_discard(&call->def_iter, READ, call->count2 * 3 * 4);
++              iov_iter_discard(&call->def_iter, ITER_DEST, call->count2 * 3 * 4);
+               call->unmarshall++;
+               fallthrough;
+--- a/fs/afs/dir.c
++++ b/fs/afs/dir.c
+@@ -315,7 +315,7 @@ expand:
+       req->actual_len = i_size; /* May change */
+       req->len = nr_pages * PAGE_SIZE; /* We can ask for more than there is */
+       req->data_version = dvnode->status.data_version; /* May change */
+-      iov_iter_xarray(&req->def_iter, READ, &dvnode->vfs_inode.i_mapping->i_pages,
++      iov_iter_xarray(&req->def_iter, ITER_DEST, &dvnode->vfs_inode.i_mapping->i_pages,
+                       0, i_size);
+       req->iter = &req->def_iter;
+--- a/fs/afs/file.c
++++ b/fs/afs/file.c
+@@ -305,7 +305,7 @@ static void afs_req_issue_op(struct netf
+       fsreq->vnode    = vnode;
+       fsreq->iter     = &fsreq->def_iter;
+-      iov_iter_xarray(&fsreq->def_iter, READ,
++      iov_iter_xarray(&fsreq->def_iter, ITER_DEST,
+                       &fsreq->vnode->vfs_inode.i_mapping->i_pages,
+                       fsreq->pos, fsreq->len);
+@@ -327,7 +327,7 @@ static int afs_symlink_readpage(struct p
+       fsreq->len      = PAGE_SIZE;
+       fsreq->vnode    = vnode;
+       fsreq->iter     = &fsreq->def_iter;
+-      iov_iter_xarray(&fsreq->def_iter, READ, &page->mapping->i_pages,
++      iov_iter_xarray(&fsreq->def_iter, ITER_DEST, &page->mapping->i_pages,
+                       fsreq->pos, fsreq->len);
+       ret = afs_fetch_data(fsreq->vnode, fsreq);
+--- a/fs/afs/internal.h
++++ b/fs/afs/internal.h
+@@ -1296,7 +1296,7 @@ static inline void afs_extract_begin(str
+       call->iov_len = size;
+       call->kvec[0].iov_base = buf;
+       call->kvec[0].iov_len = size;
+-      iov_iter_kvec(&call->def_iter, READ, call->kvec, 1, size);
++      iov_iter_kvec(&call->def_iter, ITER_DEST, call->kvec, 1, size);
+ }
+ static inline void afs_extract_to_tmp(struct afs_call *call)
+@@ -1314,7 +1314,7 @@ static inline void afs_extract_to_tmp64(
+ static inline void afs_extract_discard(struct afs_call *call, size_t size)
+ {
+       call->iov_len = size;
+-      iov_iter_discard(&call->def_iter, READ, size);
++      iov_iter_discard(&call->def_iter, ITER_DEST, size);
+ }
+ static inline void afs_extract_to_buf(struct afs_call *call, size_t size)
+--- a/fs/afs/rxrpc.c
++++ b/fs/afs/rxrpc.c
+@@ -358,7 +358,7 @@ void afs_make_call(struct afs_addr_curso
+       msg.msg_name            = NULL;
+       msg.msg_namelen         = 0;
+-      iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, call->request_size);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, 1, call->request_size);
+       msg.msg_control         = NULL;
+       msg.msg_controllen      = 0;
+       msg.msg_flags           = MSG_WAITALL | (call->write_iter ? MSG_MORE : 0);
+@@ -399,7 +399,7 @@ error_do_abort:
+                                       RX_USER_ABORT, ret, "KSD");
+       } else {
+               len = 0;
+-              iov_iter_kvec(&msg.msg_iter, READ, NULL, 0, 0);
++              iov_iter_kvec(&msg.msg_iter, ITER_DEST, NULL, 0, 0);
+               rxrpc_kernel_recv_data(call->net->socket, rxcall,
+                                      &msg.msg_iter, &len, false,
+                                      &call->abort_code, &call->service_id);
+@@ -484,7 +484,7 @@ static void afs_deliver_to_call(struct a
+              ) {
+               if (state == AFS_CALL_SV_AWAIT_ACK) {
+                       len = 0;
+-                      iov_iter_kvec(&call->def_iter, READ, NULL, 0, 0);
++                      iov_iter_kvec(&call->def_iter, ITER_DEST, NULL, 0, 0);
+                       ret = rxrpc_kernel_recv_data(call->net->socket,
+                                                    call->rxcall, &call->def_iter,
+                                                    &len, false, &remote_abort,
+@@ -821,7 +821,7 @@ void afs_send_empty_reply(struct afs_cal
+       msg.msg_name            = NULL;
+       msg.msg_namelen         = 0;
+-      iov_iter_kvec(&msg.msg_iter, WRITE, NULL, 0, 0);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, NULL, 0, 0);
+       msg.msg_control         = NULL;
+       msg.msg_controllen      = 0;
+       msg.msg_flags           = 0;
+@@ -861,7 +861,7 @@ void afs_send_simple_reply(struct afs_ca
+       iov[0].iov_len          = len;
+       msg.msg_name            = NULL;
+       msg.msg_namelen         = 0;
+-      iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, 1, len);
+       msg.msg_control         = NULL;
+       msg.msg_controllen      = 0;
+       msg.msg_flags           = 0;
+--- a/fs/afs/write.c
++++ b/fs/afs/write.c
+@@ -601,7 +601,7 @@ static ssize_t afs_write_back_from_locke
+       if (start < i_size) {
+               _debug("write back %x @%llx [%llx]", len, start, i_size);
+-              iov_iter_xarray(&iter, WRITE, &mapping->i_pages, start, len);
++              iov_iter_xarray(&iter, ITER_SOURCE, &mapping->i_pages, start, len);
+               ret = afs_store_data(vnode, &iter, start, false);
+       } else {
+               _debug("write discard %x @%llx [%llx]", len, start, i_size);
+@@ -972,7 +972,7 @@ int afs_launder_page(struct page *page)
+               bv[0].bv_page = page;
+               bv[0].bv_offset = f;
+               bv[0].bv_len = t - f;
+-              iov_iter_bvec(&iter, WRITE, bv, 1, bv[0].bv_len);
++              iov_iter_bvec(&iter, ITER_SOURCE, bv, 1, bv[0].bv_len);
+               trace_afs_page_dirty(vnode, tracepoint_string("launder"), page);
+               ret = afs_store_data(vnode, &iter, page_offset(page) + f, true);
+--- a/fs/aio.c
++++ b/fs/aio.c
+@@ -1546,7 +1546,7 @@ static int aio_read(struct kiocb *req, c
+       if (unlikely(!file->f_op->read_iter))
+               return -EINVAL;
+-      ret = aio_setup_rw(READ, iocb, &iovec, vectored, compat, &iter);
++      ret = aio_setup_rw(ITER_DEST, iocb, &iovec, vectored, compat, &iter);
+       if (ret < 0)
+               return ret;
+       ret = rw_verify_area(READ, file, &req->ki_pos, iov_iter_count(&iter));
+@@ -1574,7 +1574,7 @@ static int aio_write(struct kiocb *req,
+       if (unlikely(!file->f_op->write_iter))
+               return -EINVAL;
+-      ret = aio_setup_rw(WRITE, iocb, &iovec, vectored, compat, &iter);
++      ret = aio_setup_rw(ITER_SOURCE, iocb, &iovec, vectored, compat, &iter);
+       if (ret < 0)
+               return ret;
+       ret = rw_verify_area(WRITE, file, &req->ki_pos, iov_iter_count(&iter));
+--- a/fs/ceph/addr.c
++++ b/fs/ceph/addr.c
+@@ -263,7 +263,7 @@ static void ceph_netfs_issue_op(struct n
+       }
+       dout("%s: pos=%llu orig_len=%zu len=%llu\n", __func__, subreq->start, subreq->len, len);
+-      iov_iter_xarray(&iter, READ, &rreq->mapping->i_pages, subreq->start, len);
++      iov_iter_xarray(&iter, ITER_DEST, &rreq->mapping->i_pages, subreq->start, len);
+       err = iov_iter_get_pages_alloc(&iter, &pages, len, &page_off);
+       if (err < 0) {
+               dout("%s: iov_ter_get_pages_alloc returned %d\n", __func__, err);
+--- a/fs/ceph/file.c
++++ b/fs/ceph/file.c
+@@ -1111,7 +1111,7 @@ static void ceph_aio_complete_req(struct
+                               aio_req->total_len = rc + zlen;
+                       }
+-                      iov_iter_bvec(&i, READ, osd_data->bvec_pos.bvecs,
++                      iov_iter_bvec(&i, ITER_DEST, osd_data->bvec_pos.bvecs,
+                                     osd_data->num_bvecs, len);
+                       iov_iter_advance(&i, rc);
+                       iov_iter_zero(zlen, &i);
+@@ -1347,7 +1347,7 @@ ceph_direct_read_write(struct kiocb *ioc
+                               int zlen = min_t(size_t, len - ret,
+                                                size - pos - ret);
+-                              iov_iter_bvec(&i, READ, bvecs, num_pages, len);
++                              iov_iter_bvec(&i, ITER_DEST, bvecs, num_pages, len);
+                               iov_iter_advance(&i, ret);
+                               iov_iter_zero(zlen, &i);
+                               ret += zlen;
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -621,7 +621,7 @@ cifs_read_from_socket(struct TCP_Server_
+ {
+       struct msghdr smb_msg = {};
+       struct kvec iov = {.iov_base = buf, .iov_len = to_read};
+-      iov_iter_kvec(&smb_msg.msg_iter, READ, &iov, 1, to_read);
++      iov_iter_kvec(&smb_msg.msg_iter, ITER_DEST, &iov, 1, to_read);
+       return cifs_readv_from_socket(server, &smb_msg);
+ }
+@@ -636,7 +636,7 @@ cifs_discard_from_socket(struct TCP_Serv
+        *  and cifs_readv_from_socket sets msg_control and msg_controllen
+        *  so little to initialize in struct msghdr
+        */
+-      iov_iter_discard(&smb_msg.msg_iter, READ, to_read);
++      iov_iter_discard(&smb_msg.msg_iter, ITER_DEST, to_read);
+       return cifs_readv_from_socket(server, &smb_msg);
+ }
+@@ -648,7 +648,7 @@ cifs_read_page_from_socket(struct TCP_Se
+       struct msghdr smb_msg = {};
+       struct bio_vec bv = {
+               .bv_page = page, .bv_len = to_read, .bv_offset = page_offset};
+-      iov_iter_bvec(&smb_msg.msg_iter, READ, &bv, 1, to_read);
++      iov_iter_bvec(&smb_msg.msg_iter, ITER_DEST, &bv, 1, to_read);
+       return cifs_readv_from_socket(server, &smb_msg);
+ }
+--- a/fs/cifs/file.c
++++ b/fs/cifs/file.c
+@@ -3265,7 +3265,7 @@ static ssize_t __cifs_writev(
+               ctx->iter = *from;
+               ctx->len = len;
+       } else {
+-              rc = setup_aio_ctx_iter(ctx, from, WRITE);
++              rc = setup_aio_ctx_iter(ctx, from, ITER_SOURCE);
+               if (rc) {
+                       kref_put(&ctx->refcount, cifs_aio_ctx_release);
+                       return rc;
+@@ -4010,7 +4010,7 @@ static ssize_t __cifs_readv(
+               ctx->iter = *to;
+               ctx->len = len;
+       } else {
+-              rc = setup_aio_ctx_iter(ctx, to, READ);
++              rc = setup_aio_ctx_iter(ctx, to, ITER_DEST);
+               if (rc) {
+                       kref_put(&ctx->refcount, cifs_aio_ctx_release);
+                       return rc;
+--- a/fs/cifs/smb2ops.c
++++ b/fs/cifs/smb2ops.c
+@@ -4960,13 +4960,13 @@ handle_read_data(struct TCP_Server_Info
+                       return 0;
+               }
+-              iov_iter_bvec(&iter, WRITE, bvec, npages, data_len);
++              iov_iter_bvec(&iter, ITER_SOURCE, bvec, npages, data_len);
+       } else if (buf_len >= data_offset + data_len) {
+               /* read response payload is in buf */
+               WARN_ONCE(npages > 0, "read data can be either in buf or in pages");
+               iov.iov_base = buf + data_offset;
+               iov.iov_len = data_len;
+-              iov_iter_kvec(&iter, WRITE, &iov, 1, data_len);
++              iov_iter_kvec(&iter, ITER_SOURCE, &iov, 1, data_len);
+       } else {
+               /* read response payload cannot be in both buf and pages */
+               WARN_ONCE(1, "buf can not contain only a part of read data");
+--- a/fs/cifs/transport.c
++++ b/fs/cifs/transport.c
+@@ -349,7 +349,7 @@ __smb_send_rqst(struct TCP_Server_Info *
+                       .iov_base = &rfc1002_marker,
+                       .iov_len  = 4
+               };
+-              iov_iter_kvec(&smb_msg.msg_iter, WRITE, &hiov, 1, 4);
++              iov_iter_kvec(&smb_msg.msg_iter, ITER_SOURCE, &hiov, 1, 4);
+               rc = smb_send_kvec(server, &smb_msg, &sent);
+               if (rc < 0)
+                       goto unmask;
+@@ -370,7 +370,7 @@ __smb_send_rqst(struct TCP_Server_Info *
+                       size += iov[i].iov_len;
+               }
+-              iov_iter_kvec(&smb_msg.msg_iter, WRITE, iov, n_vec, size);
++              iov_iter_kvec(&smb_msg.msg_iter, ITER_SOURCE, iov, n_vec, size);
+               rc = smb_send_kvec(server, &smb_msg, &sent);
+               if (rc < 0)
+@@ -386,7 +386,7 @@ __smb_send_rqst(struct TCP_Server_Info *
+                       rqst_page_get_length(&rqst[j], i, &bvec.bv_len,
+                                            &bvec.bv_offset);
+-                      iov_iter_bvec(&smb_msg.msg_iter, WRITE,
++                      iov_iter_bvec(&smb_msg.msg_iter, ITER_SOURCE,
+                                     &bvec, 1, bvec.bv_len);
+                       rc = smb_send_kvec(server, &smb_msg, &sent);
+                       if (rc < 0)
+--- a/fs/fuse/ioctl.c
++++ b/fs/fuse/ioctl.c
+@@ -264,7 +264,7 @@ long fuse_do_ioctl(struct file *file, un
+               ap.args.in_pages = true;
+               err = -EFAULT;
+-              iov_iter_init(&ii, WRITE, in_iov, in_iovs, in_size);
++              iov_iter_init(&ii, ITER_SOURCE, in_iov, in_iovs, in_size);
+               for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_pages); i++) {
+                       c = copy_page_from_iter(ap.pages[i], 0, PAGE_SIZE, &ii);
+                       if (c != PAGE_SIZE && iov_iter_count(&ii))
+@@ -331,7 +331,7 @@ long fuse_do_ioctl(struct file *file, un
+               goto out;
+       err = -EFAULT;
+-      iov_iter_init(&ii, READ, out_iov, out_iovs, transferred);
++      iov_iter_init(&ii, ITER_DEST, out_iov, out_iovs, transferred);
+       for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_pages); i++) {
+               c = copy_page_to_iter(ap.pages[i], 0, PAGE_SIZE, &ii);
+               if (c != PAGE_SIZE && iov_iter_count(&ii))
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -1027,7 +1027,7 @@ __be32 nfsd_readv(struct svc_rqst *rqstp
+       ssize_t host_err;
+       trace_nfsd_read_vector(rqstp, fhp, offset, *count);
+-      iov_iter_kvec(&iter, READ, vec, vlen, *count);
++      iov_iter_kvec(&iter, ITER_DEST, vec, vlen, *count);
+       host_err = vfs_iter_read(file, &iter, &ppos, 0);
+       return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err);
+ }
+@@ -1117,7 +1117,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, s
+       if (stable && !use_wgather)
+               flags |= RWF_SYNC;
+-      iov_iter_kvec(&iter, WRITE, vec, vlen, *cnt);
++      iov_iter_kvec(&iter, ITER_SOURCE, vec, vlen, *cnt);
+       since = READ_ONCE(file->f_wb_err);
+       if (verf)
+               nfsd_copy_write_verifier(verf, nn);
+--- a/fs/ocfs2/cluster/tcp.c
++++ b/fs/ocfs2/cluster/tcp.c
+@@ -900,7 +900,7 @@ static int o2net_recv_tcp_msg(struct soc
+ {
+       struct kvec vec = { .iov_len = len, .iov_base = data, };
+       struct msghdr msg = { .msg_flags = MSG_DONTWAIT, };
+-      iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, len);
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, &vec, 1, len);
+       return sock_recvmsg(sock, &msg, MSG_DONTWAIT);
+ }
+--- a/fs/orangefs/inode.c
++++ b/fs/orangefs/inode.c
+@@ -53,7 +53,7 @@ static int orangefs_writepage_locked(str
+       bv.bv_len = wlen;
+       bv.bv_offset = off % PAGE_SIZE;
+       WARN_ON(wlen == 0);
+-      iov_iter_bvec(&iter, WRITE, &bv, 1, wlen);
++      iov_iter_bvec(&iter, ITER_SOURCE, &bv, 1, wlen);
+       ret = wait_for_direct_io(ORANGEFS_IO_WRITE, inode, &off, &iter, wlen,
+           len, wr, NULL, NULL);
+@@ -111,7 +111,7 @@ static int orangefs_writepages_work(stru
+               else
+                       ow->bv[i].bv_offset = 0;
+       }
+-      iov_iter_bvec(&iter, WRITE, ow->bv, ow->npages, ow->len);
++      iov_iter_bvec(&iter, ITER_SOURCE, ow->bv, ow->npages, ow->len);
+       WARN_ON(ow->off >= len);
+       if (ow->off + ow->len > len)
+@@ -269,7 +269,7 @@ static void orangefs_readahead(struct re
+       offset = readahead_pos(rac);
+       i_pages = &rac->mapping->i_pages;
+-      iov_iter_xarray(&iter, READ, i_pages, offset, readahead_length(rac));
++      iov_iter_xarray(&iter, ITER_DEST, i_pages, offset, readahead_length(rac));
+       /* read in the pages. */
+       if ((ret = wait_for_direct_io(ORANGEFS_IO_READ, inode,
+@@ -302,7 +302,7 @@ static int orangefs_readpage(struct file
+       bv.bv_page = page;
+       bv.bv_len = PAGE_SIZE;
+       bv.bv_offset = 0;
+-      iov_iter_bvec(&iter, READ, &bv, 1, PAGE_SIZE);
++      iov_iter_bvec(&iter, ITER_DEST, &bv, 1, PAGE_SIZE);
+       ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, &off, &iter,
+           PAGE_SIZE, inode->i_size, NULL, NULL, file);
+--- a/fs/read_write.c
++++ b/fs/read_write.c
+@@ -399,7 +399,7 @@ static ssize_t new_sync_read(struct file
+       init_sync_kiocb(&kiocb, filp);
+       kiocb.ki_pos = (ppos ? *ppos : 0);
+-      iov_iter_init(&iter, READ, &iov, 1, len);
++      iov_iter_init(&iter, ITER_DEST, &iov, 1, len);
+       ret = call_read_iter(filp, &kiocb, &iter);
+       BUG_ON(ret == -EIOCBQUEUED);
+@@ -439,7 +439,7 @@ ssize_t __kernel_read(struct file *file,
+       init_sync_kiocb(&kiocb, file);
+       kiocb.ki_pos = pos ? *pos : 0;
+-      iov_iter_kvec(&iter, READ, &iov, 1, iov.iov_len);
++      iov_iter_kvec(&iter, ITER_DEST, &iov, 1, iov.iov_len);
+       ret = file->f_op->read_iter(&kiocb, &iter);
+       if (ret > 0) {
+               if (pos)
+@@ -502,7 +502,7 @@ static ssize_t new_sync_write(struct fil
+       init_sync_kiocb(&kiocb, filp);
+       kiocb.ki_pos = (ppos ? *ppos : 0);
+-      iov_iter_init(&iter, WRITE, &iov, 1, len);
++      iov_iter_init(&iter, ITER_SOURCE, &iov, 1, len);
+       ret = call_write_iter(filp, &kiocb, &iter);
+       BUG_ON(ret == -EIOCBQUEUED);
+@@ -535,7 +535,7 @@ ssize_t __kernel_write(struct file *file
+       init_sync_kiocb(&kiocb, file);
+       kiocb.ki_pos = pos ? *pos : 0;
+-      iov_iter_kvec(&iter, WRITE, &iov, 1, iov.iov_len);
++      iov_iter_kvec(&iter, ITER_SOURCE, &iov, 1, iov.iov_len);
+       ret = file->f_op->write_iter(&kiocb, &iter);
+       if (ret > 0) {
+               if (pos)
+@@ -905,7 +905,7 @@ static ssize_t vfs_readv(struct file *fi
+       struct iov_iter iter;
+       ssize_t ret;
+-      ret = import_iovec(READ, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
++      ret = import_iovec(ITER_DEST, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
+       if (ret >= 0) {
+               ret = do_iter_read(file, &iter, pos, flags);
+               kfree(iov);
+@@ -922,7 +922,7 @@ static ssize_t vfs_writev(struct file *f
+       struct iov_iter iter;
+       ssize_t ret;
+-      ret = import_iovec(WRITE, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
++      ret = import_iovec(ITER_SOURCE, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
+       if (ret >= 0) {
+               file_start_write(file);
+               ret = do_iter_write(file, &iter, pos, flags);
+--- a/fs/seq_file.c
++++ b/fs/seq_file.c
+@@ -156,7 +156,7 @@ ssize_t seq_read(struct file *file, char
+       ssize_t ret;
+       init_sync_kiocb(&kiocb, file);
+-      iov_iter_init(&iter, READ, &iov, 1, size);
++      iov_iter_init(&iter, ITER_DEST, &iov, 1, size);
+       kiocb.ki_pos = *ppos;
+       ret = seq_read_iter(&kiocb, &iter);
+--- a/fs/splice.c
++++ b/fs/splice.c
+@@ -304,7 +304,7 @@ ssize_t generic_file_splice_read(struct
+       unsigned int i_head;
+       int ret;
+-      iov_iter_pipe(&to, READ, pipe, len);
++      iov_iter_pipe(&to, ITER_DEST, pipe, len);
+       i_head = to.head;
+       init_sync_kiocb(&kiocb, in);
+       kiocb.ki_pos = *ppos;
+@@ -685,7 +685,7 @@ iter_file_splice_write(struct pipe_inode
+                       n++;
+               }
+-              iov_iter_bvec(&from, WRITE, array, n, sd.total_len - left);
++              iov_iter_bvec(&from, ITER_SOURCE, array, n, sd.total_len - left);
+               ret = vfs_iter_write(out, &from, &sd.pos, 0);
+               if (ret <= 0)
+                       break;
+@@ -1296,9 +1296,9 @@ static int vmsplice_type(struct fd f, in
+       if (!f.file)
+               return -EBADF;
+       if (f.file->f_mode & FMODE_WRITE) {
+-              *type = WRITE;
++              *type = ITER_SOURCE;
+       } else if (f.file->f_mode & FMODE_READ) {
+-              *type = READ;
++              *type = ITER_DEST;
+       } else {
+               fdput(f);
+               return -EBADF;
+@@ -1347,7 +1347,7 @@ SYSCALL_DEFINE4(vmsplice, int, fd, const
+       if (!iov_iter_count(&iter))
+               error = 0;
+-      else if (iov_iter_rw(&iter) == WRITE)
++      else if (type == ITER_SOURCE)
+               error = vmsplice_to_pipe(f.file, &iter, flags);
+       else
+               error = vmsplice_to_user(f.file, &iter, flags);
+--- a/include/linux/uio.h
++++ b/include/linux/uio.h
+@@ -27,6 +27,9 @@ enum iter_type {
+       ITER_DISCARD,
+ };
++#define ITER_SOURCE   1       // == WRITE
++#define ITER_DEST     0       // == READ
++
+ struct iov_iter_state {
+       size_t iov_offset;
+       size_t count;
+--- a/mm/madvise.c
++++ b/mm/madvise.c
+@@ -1251,7 +1251,7 @@ SYSCALL_DEFINE5(process_madvise, int, pi
+               goto out;
+       }
+-      ret = import_iovec(READ, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
++      ret = import_iovec(ITER_DEST, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
+       if (ret < 0)
+               goto out;
+--- a/mm/page_io.c
++++ b/mm/page_io.c
+@@ -252,7 +252,7 @@ int __swap_writepage(struct page *page,
+               };
+               struct iov_iter from;
+-              iov_iter_bvec(&from, WRITE, &bv, 1, PAGE_SIZE);
++              iov_iter_bvec(&from, ITER_SOURCE, &bv, 1, PAGE_SIZE);
+               init_sync_kiocb(&kiocb, swap_file);
+               kiocb.ki_pos = page_file_offset(page);
+--- a/mm/process_vm_access.c
++++ b/mm/process_vm_access.c
+@@ -263,7 +263,7 @@ static ssize_t process_vm_rw(pid_t pid,
+       struct iovec *iov_r;
+       struct iov_iter iter;
+       ssize_t rc;
+-      int dir = vm_write ? WRITE : READ;
++      int dir = vm_write ? ITER_SOURCE : ITER_DEST;
+       if (flags != 0)
+               return -EINVAL;
+--- a/net/9p/client.c
++++ b/net/9p/client.c
+@@ -2096,7 +2096,7 @@ int p9_client_readdir(struct p9_fid *fid
+       struct kvec kv = {.iov_base = data, .iov_len = count};
+       struct iov_iter to;
+-      iov_iter_kvec(&to, READ, &kv, 1, count);
++      iov_iter_kvec(&to, ITER_DEST, &kv, 1, count);
+       p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
+                fid->fid, offset, count);
+--- a/net/bluetooth/6lowpan.c
++++ b/net/bluetooth/6lowpan.c
+@@ -449,7 +449,7 @@ static int send_pkt(struct l2cap_chan *c
+       iv.iov_len = skb->len;
+       memset(&msg, 0, sizeof(msg));
+-      iov_iter_kvec(&msg.msg_iter, WRITE, &iv, 1, skb->len);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iv, 1, skb->len);
+       err = l2cap_chan_send(chan, &msg, skb->len);
+       if (err > 0) {
+--- a/net/bluetooth/a2mp.c
++++ b/net/bluetooth/a2mp.c
+@@ -56,7 +56,7 @@ static void a2mp_send(struct amp_mgr *mg
+       memset(&msg, 0, sizeof(msg));
+-      iov_iter_kvec(&msg.msg_iter, WRITE, &iv, 1, total_len);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iv, 1, total_len);
+       l2cap_chan_send(chan, &msg, total_len);
+--- a/net/bluetooth/smp.c
++++ b/net/bluetooth/smp.c
+@@ -605,7 +605,7 @@ static void smp_send_cmd(struct l2cap_co
+       memset(&msg, 0, sizeof(msg));
+-      iov_iter_kvec(&msg.msg_iter, WRITE, iv, 2, 1 + len);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iv, 2, 1 + len);
+       l2cap_chan_send(chan, &msg, 1 + len);
+--- a/net/ceph/messenger_v1.c
++++ b/net/ceph/messenger_v1.c
+@@ -30,7 +30,7 @@ static int ceph_tcp_recvmsg(struct socke
+       if (!buf)
+               msg.msg_flags |= MSG_TRUNC;
+-      iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, len);
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, len);
+       r = sock_recvmsg(sock, &msg, msg.msg_flags);
+       if (r == -EAGAIN)
+               r = 0;
+@@ -49,7 +49,7 @@ static int ceph_tcp_recvpage(struct sock
+       int r;
+       BUG_ON(page_offset + length > PAGE_SIZE);
+-      iov_iter_bvec(&msg.msg_iter, READ, &bvec, 1, length);
++      iov_iter_bvec(&msg.msg_iter, ITER_DEST, &bvec, 1, length);
+       r = sock_recvmsg(sock, &msg, msg.msg_flags);
+       if (r == -EAGAIN)
+               r = 0;
+--- a/net/ceph/messenger_v2.c
++++ b/net/ceph/messenger_v2.c
+@@ -167,7 +167,7 @@ static int do_try_sendpage(struct socket
+                                                 bv.bv_offset, bv.bv_len,
+                                                 CEPH_MSG_FLAGS);
+               } else {
+-                      iov_iter_bvec(&msg.msg_iter, WRITE, &bv, 1, bv.bv_len);
++                      iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bv, 1, bv.bv_len);
+                       ret = sock_sendmsg(sock, &msg);
+               }
+               if (ret <= 0) {
+@@ -224,7 +224,7 @@ static void reset_in_kvecs(struct ceph_c
+       WARN_ON(iov_iter_count(&con->v2.in_iter));
+       con->v2.in_kvec_cnt = 0;
+-      iov_iter_kvec(&con->v2.in_iter, READ, con->v2.in_kvecs, 0, 0);
++      iov_iter_kvec(&con->v2.in_iter, ITER_DEST, con->v2.in_kvecs, 0, 0);
+ }
+ static void set_in_bvec(struct ceph_connection *con, const struct bio_vec *bv)
+@@ -232,7 +232,7 @@ static void set_in_bvec(struct ceph_conn
+       WARN_ON(iov_iter_count(&con->v2.in_iter));
+       con->v2.in_bvec = *bv;
+-      iov_iter_bvec(&con->v2.in_iter, READ, &con->v2.in_bvec, 1, bv->bv_len);
++      iov_iter_bvec(&con->v2.in_iter, ITER_DEST, &con->v2.in_bvec, 1, bv->bv_len);
+ }
+ static void set_in_skip(struct ceph_connection *con, int len)
+@@ -240,7 +240,7 @@ static void set_in_skip(struct ceph_conn
+       WARN_ON(iov_iter_count(&con->v2.in_iter));
+       dout("%s con %p len %d\n", __func__, con, len);
+-      iov_iter_discard(&con->v2.in_iter, READ, len);
++      iov_iter_discard(&con->v2.in_iter, ITER_DEST, len);
+ }
+ static void add_out_kvec(struct ceph_connection *con, void *buf, int len)
+@@ -264,7 +264,7 @@ static void reset_out_kvecs(struct ceph_
+       con->v2.out_kvec_cnt = 0;
+-      iov_iter_kvec(&con->v2.out_iter, WRITE, con->v2.out_kvecs, 0, 0);
++      iov_iter_kvec(&con->v2.out_iter, ITER_SOURCE, con->v2.out_kvecs, 0, 0);
+       con->v2.out_iter_sendpage = false;
+ }
+@@ -276,7 +276,7 @@ static void set_out_bvec(struct ceph_con
+       con->v2.out_bvec = *bv;
+       con->v2.out_iter_sendpage = zerocopy;
+-      iov_iter_bvec(&con->v2.out_iter, WRITE, &con->v2.out_bvec, 1,
++      iov_iter_bvec(&con->v2.out_iter, ITER_SOURCE, &con->v2.out_bvec, 1,
+                     con->v2.out_bvec.bv_len);
+ }
+@@ -289,7 +289,7 @@ static void set_out_bvec_zero(struct cep
+       con->v2.out_bvec.bv_offset = 0;
+       con->v2.out_bvec.bv_len = min(con->v2.out_zero, (int)PAGE_SIZE);
+       con->v2.out_iter_sendpage = true;
+-      iov_iter_bvec(&con->v2.out_iter, WRITE, &con->v2.out_bvec, 1,
++      iov_iter_bvec(&con->v2.out_iter, ITER_SOURCE, &con->v2.out_bvec, 1,
+                     con->v2.out_bvec.bv_len);
+ }
+--- a/net/compat.c
++++ b/net/compat.c
+@@ -98,7 +98,7 @@ int get_compat_msghdr(struct msghdr *kms
+       if (err)
+               return err;
+-      err = import_iovec(save_addr ? READ : WRITE, compat_ptr(ptr), len,
++      err = import_iovec(save_addr ? ITER_DEST : ITER_SOURCE, compat_ptr(ptr), len,
+                          UIO_FASTIOV, iov, &kmsg->msg_iter);
+       return err < 0 ? err : 0;
+ }
+--- a/net/ipv4/tcp.c
++++ b/net/ipv4/tcp.c
+@@ -1886,7 +1886,7 @@ static int receive_fallback_to_copy(stru
+       if (copy_address != zc->copybuf_address)
+               return -EINVAL;
+-      err = import_single_range(READ, (void __user *)copy_address,
++      err = import_single_range(ITER_DEST, (void __user *)copy_address,
+                                 inq, &iov, &msg.msg_iter);
+       if (err)
+               return err;
+@@ -1920,7 +1920,7 @@ static int tcp_copy_straggler_data(struc
+       if (copy_address != zc->copybuf_address)
+               return -EINVAL;
+-      err = import_single_range(READ, (void __user *)copy_address,
++      err = import_single_range(ITER_DEST, (void __user *)copy_address,
+                                 copylen, &iov, &msg.msg_iter);
+       if (err)
+               return err;
+--- a/net/netfilter/ipvs/ip_vs_sync.c
++++ b/net/netfilter/ipvs/ip_vs_sync.c
+@@ -1617,7 +1617,7 @@ ip_vs_receive(struct socket *sock, char
+       EnterFunction(7);
+       /* Receive a packet */
+-      iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, buflen);
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, buflen);
+       len = sock_recvmsg(sock, &msg, MSG_DONTWAIT);
+       if (len < 0)
+               return len;
+--- a/net/smc/smc_clc.c
++++ b/net/smc/smc_clc.c
+@@ -361,7 +361,7 @@ int smc_clc_wait_msg(struct smc_sock *sm
+        */
+       krflags = MSG_PEEK | MSG_WAITALL;
+       clc_sk->sk_rcvtimeo = timeout;
+-      iov_iter_kvec(&msg.msg_iter, READ, &vec, 1,
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, &vec, 1,
+                       sizeof(struct smc_clc_msg_hdr));
+       len = sock_recvmsg(smc->clcsock, &msg, krflags);
+       if (signal_pending(current)) {
+@@ -408,7 +408,7 @@ int smc_clc_wait_msg(struct smc_sock *sm
+       } else {
+               recvlen = datlen;
+       }
+-      iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen);
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, &vec, 1, recvlen);
+       krflags = MSG_WAITALL;
+       len = sock_recvmsg(smc->clcsock, &msg, krflags);
+       if (len < recvlen || !smc_clc_msg_hdr_valid(clcm, check_trl)) {
+@@ -425,7 +425,7 @@ int smc_clc_wait_msg(struct smc_sock *sm
+               /* receive remaining proposal message */
+               recvlen = datlen > SMC_CLC_RECV_BUF_LEN ?
+                                               SMC_CLC_RECV_BUF_LEN : datlen;
+-              iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen);
++              iov_iter_kvec(&msg.msg_iter, ITER_DEST, &vec, 1, recvlen);
+               len = sock_recvmsg(smc->clcsock, &msg, krflags);
+               if (len < recvlen) {
+                       smc->sk.sk_err = EPROTO;
+--- a/net/socket.c
++++ b/net/socket.c
+@@ -761,7 +761,7 @@ EXPORT_SYMBOL(sock_sendmsg);
+ int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
+                  struct kvec *vec, size_t num, size_t size)
+ {
+-      iov_iter_kvec(&msg->msg_iter, WRITE, vec, num, size);
++      iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, vec, num, size);
+       return sock_sendmsg(sock, msg);
+ }
+ EXPORT_SYMBOL(kernel_sendmsg);
+@@ -787,7 +787,7 @@ int kernel_sendmsg_locked(struct sock *s
+       if (!sock->ops->sendmsg_locked)
+               return sock_no_sendmsg_locked(sk, msg, size);
+-      iov_iter_kvec(&msg->msg_iter, WRITE, vec, num, size);
++      iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, vec, num, size);
+       return sock->ops->sendmsg_locked(sk, msg, msg_data_left(msg));
+ }
+@@ -1008,7 +1008,7 @@ int kernel_recvmsg(struct socket *sock,
+                  struct kvec *vec, size_t num, size_t size, int flags)
+ {
+       msg->msg_control_is_user = false;
+-      iov_iter_kvec(&msg->msg_iter, READ, vec, num, size);
++      iov_iter_kvec(&msg->msg_iter, ITER_DEST, vec, num, size);
+       return sock_recvmsg(sock, msg, flags);
+ }
+ EXPORT_SYMBOL(kernel_recvmsg);
+@@ -2049,7 +2049,7 @@ int __sys_sendto(int fd, void __user *bu
+       struct iovec iov;
+       int fput_needed;
+-      err = import_single_range(WRITE, buff, len, &iov, &msg.msg_iter);
++      err = import_single_range(ITER_SOURCE, buff, len, &iov, &msg.msg_iter);
+       if (unlikely(err))
+               return err;
+       sock = sockfd_lookup_light(fd, &err, &fput_needed);
+@@ -2110,7 +2110,7 @@ int __sys_recvfrom(int fd, void __user *
+       int err, err2;
+       int fput_needed;
+-      err = import_single_range(READ, ubuf, size, &iov, &msg.msg_iter);
++      err = import_single_range(ITER_DEST, ubuf, size, &iov, &msg.msg_iter);
+       if (unlikely(err))
+               return err;
+       sock = sockfd_lookup_light(fd, &err, &fput_needed);
+@@ -2381,7 +2381,7 @@ static int copy_msghdr_from_user(struct
+       if (err)
+               return err;
+-      err = import_iovec(save_addr ? READ : WRITE,
++      err = import_iovec(save_addr ? ITER_DEST : ITER_SOURCE,
+                           msg.msg_iov, msg.msg_iovlen,
+                           UIO_FASTIOV, iov, &kmsg->msg_iter);
+       return err < 0 ? err : 0;
+--- a/net/sunrpc/socklib.c
++++ b/net/sunrpc/socklib.c
+@@ -213,7 +213,7 @@ static inline int xprt_sendmsg(struct so
+ static int xprt_send_kvec(struct socket *sock, struct msghdr *msg,
+                         struct kvec *vec, size_t seek)
+ {
+-      iov_iter_kvec(&msg->msg_iter, WRITE, vec, 1, vec->iov_len);
++      iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, vec, 1, vec->iov_len);
+       return xprt_sendmsg(sock, msg, seek);
+ }
+@@ -226,7 +226,7 @@ static int xprt_send_pagedata(struct soc
+       if (err < 0)
+               return err;
+-      iov_iter_bvec(&msg->msg_iter, WRITE, xdr->bvec, xdr_buf_pagecount(xdr),
++      iov_iter_bvec(&msg->msg_iter, ITER_SOURCE, xdr->bvec, xdr_buf_pagecount(xdr),
+                     xdr->page_len + xdr->page_base);
+       return xprt_sendmsg(sock, msg, base + xdr->page_base);
+ }
+@@ -249,7 +249,7 @@ static int xprt_send_rm_and_kvec(struct
+       };
+       size_t len = iov[0].iov_len + iov[1].iov_len;
+-      iov_iter_kvec(&msg->msg_iter, WRITE, iov, 2, len);
++      iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, iov, 2, len);
+       return xprt_sendmsg(sock, msg, base);
+ }
+--- a/net/sunrpc/svcsock.c
++++ b/net/sunrpc/svcsock.c
+@@ -260,7 +260,7 @@ static ssize_t svc_tcp_read_msg(struct s
+       rqstp->rq_respages = &rqstp->rq_pages[i];
+       rqstp->rq_next_page = rqstp->rq_respages + 1;
+-      iov_iter_bvec(&msg.msg_iter, READ, bvec, i, buflen);
++      iov_iter_bvec(&msg.msg_iter, ITER_DEST, bvec, i, buflen);
+       if (seek) {
+               iov_iter_advance(&msg.msg_iter, seek);
+               buflen -= seek;
+@@ -871,7 +871,7 @@ static ssize_t svc_tcp_read_marker(struc
+               want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
+               iov.iov_base = ((char *)&svsk->sk_marker) + svsk->sk_tcplen;
+               iov.iov_len  = want;
+-              iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, want);
++              iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, want);
+               len = sock_recvmsg(svsk->sk_sock, &msg, MSG_DONTWAIT);
+               if (len < 0)
+                       return len;
+--- a/net/sunrpc/xprtsock.c
++++ b/net/sunrpc/xprtsock.c
+@@ -363,7 +363,7 @@ static ssize_t
+ xs_read_kvec(struct socket *sock, struct msghdr *msg, int flags,
+               struct kvec *kvec, size_t count, size_t seek)
+ {
+-      iov_iter_kvec(&msg->msg_iter, READ, kvec, 1, count);
++      iov_iter_kvec(&msg->msg_iter, ITER_DEST, kvec, 1, count);
+       return xs_sock_recvmsg(sock, msg, flags, seek);
+ }
+@@ -372,7 +372,7 @@ xs_read_bvec(struct socket *sock, struct
+               struct bio_vec *bvec, unsigned long nr, size_t count,
+               size_t seek)
+ {
+-      iov_iter_bvec(&msg->msg_iter, READ, bvec, nr, count);
++      iov_iter_bvec(&msg->msg_iter, ITER_DEST, bvec, nr, count);
+       return xs_sock_recvmsg(sock, msg, flags, seek);
+ }
+@@ -380,7 +380,7 @@ static ssize_t
+ xs_read_discard(struct socket *sock, struct msghdr *msg, int flags,
+               size_t count)
+ {
+-      iov_iter_discard(&msg->msg_iter, READ, count);
++      iov_iter_discard(&msg->msg_iter, ITER_DEST, count);
+       return sock_recvmsg(sock, msg, flags);
+ }
+--- a/net/tipc/topsrv.c
++++ b/net/tipc/topsrv.c
+@@ -396,7 +396,7 @@ static int tipc_conn_rcv_from_sock(struc
+       iov.iov_base = &s;
+       iov.iov_len = sizeof(s);
+       msg.msg_name = NULL;
+-      iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, iov.iov_len);
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, iov.iov_len);
+       ret = sock_recvmsg(con->sock, &msg, MSG_DONTWAIT);
+       if (ret == -EWOULDBLOCK)
+               return -EWOULDBLOCK;
+--- a/net/tls/tls_device.c
++++ b/net/tls/tls_device.c
+@@ -571,7 +571,7 @@ int tls_device_sendpage(struct sock *sk,
+       kaddr = kmap(page);
+       iov.iov_base = kaddr + offset;
+       iov.iov_len = size;
+-      iov_iter_kvec(&msg_iter, WRITE, &iov, 1, size);
++      iov_iter_kvec(&msg_iter, ITER_SOURCE, &iov, 1, size);
+       rc = tls_push_data(sk, &msg_iter, size,
+                          flags, TLS_RECORD_TYPE_DATA);
+       kunmap(page);
+@@ -646,7 +646,7 @@ static int tls_device_push_pending_recor
+ {
+       struct iov_iter msg_iter;
+-      iov_iter_kvec(&msg_iter, WRITE, NULL, 0, 0);
++      iov_iter_kvec(&msg_iter, ITER_SOURCE, NULL, 0, 0);
+       return tls_push_data(sk, &msg_iter, 0, flags, TLS_RECORD_TYPE_DATA);
+ }
+--- a/net/xfrm/espintcp.c
++++ b/net/xfrm/espintcp.c
+@@ -362,7 +362,7 @@ static int espintcp_sendmsg(struct sock
+       *((__be16 *)buf) = cpu_to_be16(msglen);
+       pfx_iov.iov_base = buf;
+       pfx_iov.iov_len = sizeof(buf);
+-      iov_iter_kvec(&pfx_iter, WRITE, &pfx_iov, 1, pfx_iov.iov_len);
++      iov_iter_kvec(&pfx_iter, ITER_SOURCE, &pfx_iov, 1, pfx_iov.iov_len);
+       err = sk_msg_memcopy_from_iter(sk, &pfx_iter, &emsg->skmsg,
+                                      pfx_iov.iov_len);
+--- a/security/keys/keyctl.c
++++ b/security/keys/keyctl.c
+@@ -1256,7 +1256,7 @@ long keyctl_instantiate_key(key_serial_t
+               struct iov_iter from;
+               int ret;
+-              ret = import_single_range(WRITE, (void __user *)_payload, plen,
++              ret = import_single_range(ITER_SOURCE, (void __user *)_payload, plen,
+                                         &iov, &from);
+               if (unlikely(ret))
+                       return ret;
+@@ -1288,7 +1288,7 @@ long keyctl_instantiate_key_iov(key_seri
+       if (!_payload_iov)
+               ioc = 0;
+-      ret = import_iovec(WRITE, _payload_iov, ioc,
++      ret = import_iovec(ITER_SOURCE, _payload_iov, ioc,
+                                   ARRAY_SIZE(iovstack), &iov, &from);
+       if (ret < 0)
+               return ret;
diff --git a/queue-5.15/wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch b/queue-5.15/wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch
new file mode 100644 (file)
index 0000000..965d3bd
--- /dev/null
@@ -0,0 +1,55 @@
+From stable+bounces-246852-greg=kroah.com@vger.kernel.org Wed May 13 18:53:15 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 09:11:14 -0400
+Subject: wifi: brcmfmac: Fix potential use-after-free issue when stopping watchdog task
+To: stable@vger.kernel.org
+Cc: Marek Szyprowski <m.szyprowski@samsung.com>, Arend van Spriel <arend.vanspriel@broadcom.com>, Johannes Berg <johannes.berg@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260513131114.3723069-1-sashal@kernel.org>
+
+From: Marek Szyprowski <m.szyprowski@samsung.com>
+
+[ Upstream commit c623b63580880cc742255eaed3d79804c1b91143 ]
+
+Watchdog task might end between send_sig() and kthread_stop() calls, what
+results in the use-after-free issue. Fix this by increasing watchdog task
+reference count before calling send_sig() and dropping it by switching to
+kthread_stop_put().
+
+Cc: stable@vger.kernel.org
+Fixes: 373c83a801f1 ("brcmfmac: stop watchdog before detach and free everything")
+Fixes: a9ffda88be74 ("brcm80211: fmac: abstract bus_stop interface function pointer")
+Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Link: https://patch.msgid.link/20260416093339.2066829-1-m.szyprowski@samsung.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+[ replaced kthread_stop_put() with open-coded kthread_stop() + put_task_struct() ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+@@ -2474,8 +2474,10 @@ static void brcmf_sdio_bus_stop(struct d
+       brcmf_dbg(TRACE, "Enter\n");
+       if (bus->watchdog_tsk) {
++              get_task_struct(bus->watchdog_tsk);
+               send_sig(SIGTERM, bus->watchdog_tsk, 1);
+               kthread_stop(bus->watchdog_tsk);
++              put_task_struct(bus->watchdog_tsk);
+               bus->watchdog_tsk = NULL;
+       }
+@@ -4549,8 +4551,10 @@ void brcmf_sdio_remove(struct brcmf_sdio
+       if (bus) {
+               /* Stop watchdog task */
+               if (bus->watchdog_tsk) {
++                      get_task_struct(bus->watchdog_tsk);
+                       send_sig(SIGTERM, bus->watchdog_tsk, 1);
+                       kthread_stop(bus->watchdog_tsk);
++                      put_task_struct(bus->watchdog_tsk);
+                       bus->watchdog_tsk = NULL;
+               }
diff --git a/queue-5.15/xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch b/queue-5.15/xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch
new file mode 100644 (file)
index 0000000..713384b
--- /dev/null
@@ -0,0 +1,132 @@
+From stable+bounces-246957-greg=kroah.com@vger.kernel.org Wed May 13 22:40:29 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 13:09:42 -0400
+Subject: xfrm: ah: account for ESN high bits in async callbacks
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Steffen Klassert <steffen.klassert@secunet.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260513170942.3829179-3-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit ec54093e6a8f87e800bb6aa15eb7fc1e33faa524 ]
+
+AH allocates its temporary auth/ICV layout differently when ESN is enabled:
+the async ahash setup appends a 4-byte seqhi slot before the ICV or
+auth_data area, but the async completion callbacks still reconstruct the
+temporary layout as if seqhi were absent.
+
+With an async AH implementation selected, that makes AH copy or compare
+the wrong bytes on both the IPv4 and IPv6 paths. In UML repro on IPv4 AH
+with ESN and forced async hmac(sha1), ping fails with 100% packet loss,
+and the callback logs show the pre-fix drift:
+
+  ah4 output_done: esn=1 err=0 icv_off=20 expected_off=24
+  ah4 input_done: esn=1 auth_off=20 expected_auth_off=24 icv_off=32 expected_icv_off=36
+
+Reconstruct the callback-side layout the same way the setup path built it
+by skipping the ESN seqhi slot before locating the saved auth_data or ICV.
+Per RFC 4302, the ESN high-order 32 bits participate in the AH ICV
+computation, so the async callbacks must account for the seqhi slot.
+
+Post-fix, the same IPv4 AH+ESN+forced-async-hmac(sha1) UML repro shows
+the corrected offset (ah4 output_done: esn=1 err=0 icv_off=24
+expected_off=24) and ping succeeds; net/ipv4/ah4.o and net/ipv6/ah6.o
+build clean at W=1. IPv6 AH+ESN was not exercised at runtime, and the
+change has not been tested against a real async hardware AH engine.
+
+Fixes: d4d573d0334d ("{IPv4,xfrm} Add ESN support for AH egress part")
+Fixes: d8b2a8600b0e ("{IPv4,xfrm} Add ESN support for AH ingress part")
+Fixes: 26dd70c3fad3 ("{IPv6,xfrm} Add ESN support for AH egress part")
+Fixes: 8d6da6f32557 ("{IPv6,xfrm} Add ESN support for AH ingress part")
+Cc: stable@vger.kernel.org
+Assisted-by: Codex:gpt-5-4
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv4/ah4.c |   14 ++++++++++++--
+ net/ipv6/ah6.c |   14 ++++++++++++--
+ 2 files changed, 24 insertions(+), 4 deletions(-)
+
+--- a/net/ipv4/ah4.c
++++ b/net/ipv4/ah4.c
+@@ -124,9 +124,14 @@ static void ah_output_done(struct crypto
+       struct iphdr *top_iph = ip_hdr(skb);
+       struct ip_auth_hdr *ah = ip_auth_hdr(skb);
+       int ihl = ip_hdrlen(skb);
++      int seqhi_len = 0;
++      __be32 *seqhi;
++      if (x->props.flags & XFRM_STATE_ESN)
++              seqhi_len = sizeof(*seqhi);
+       iph = AH_SKB_CB(skb)->tmp;
+-      icv = ah_tmp_icv(iph, ihl);
++      seqhi = (__be32 *)((char *)iph + ihl);
++      icv = ah_tmp_icv(seqhi, seqhi_len);
+       memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
+       top_iph->tos = iph->tos;
+@@ -270,12 +275,17 @@ static void ah_input_done(struct crypto_
+       struct ip_auth_hdr *ah = ip_auth_hdr(skb);
+       int ihl = ip_hdrlen(skb);
+       int ah_hlen = (ah->hdrlen + 2) << 2;
++      int seqhi_len = 0;
++      __be32 *seqhi;
+       if (err)
+               goto out;
++      if (x->props.flags & XFRM_STATE_ESN)
++              seqhi_len = sizeof(*seqhi);
+       work_iph = AH_SKB_CB(skb)->tmp;
+-      auth_data = ah_tmp_auth(work_iph, ihl);
++      seqhi = (__be32 *)((char *)work_iph + ihl);
++      auth_data = ah_tmp_auth(seqhi, seqhi_len);
+       icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
+       err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
+--- a/net/ipv6/ah6.c
++++ b/net/ipv6/ah6.c
+@@ -320,14 +320,19 @@ static void ah6_output_done(struct crypt
+       struct ipv6hdr *top_iph = ipv6_hdr(skb);
+       struct ip_auth_hdr *ah = ip_auth_hdr(skb);
+       struct tmp_ext *iph_ext;
++      int seqhi_len = 0;
++      __be32 *seqhi;
+       extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
+       if (extlen)
+               extlen += sizeof(*iph_ext);
++      if (x->props.flags & XFRM_STATE_ESN)
++              seqhi_len = sizeof(*seqhi);
+       iph_base = AH_SKB_CB(skb)->tmp;
+       iph_ext = ah_tmp_ext(iph_base);
+-      icv = ah_tmp_icv(iph_ext, extlen);
++      seqhi = (__be32 *)((char *)iph_ext + extlen);
++      icv = ah_tmp_icv(seqhi, seqhi_len);
+       memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
+       memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
+@@ -474,13 +479,18 @@ static void ah6_input_done(struct crypto
+       struct ip_auth_hdr *ah = ip_auth_hdr(skb);
+       int hdr_len = skb_network_header_len(skb);
+       int ah_hlen = ipv6_authlen(ah);
++      int seqhi_len = 0;
++      __be32 *seqhi;
+       if (err)
+               goto out;
++      if (x->props.flags & XFRM_STATE_ESN)
++              seqhi_len = sizeof(*seqhi);
+       work_iph = AH_SKB_CB(skb)->tmp;
+       auth_data = ah_tmp_auth(work_iph, hdr_len);
+-      icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
++      seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
++      icv = ah_tmp_icv(seqhi, seqhi_len);
+       err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
+       if (err)
diff --git a/queue-5.15/xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch b/queue-5.15/xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch
new file mode 100644 (file)
index 0000000..3e93852
--- /dev/null
@@ -0,0 +1,119 @@
+From stable+bounces-246976-greg=kroah.com@vger.kernel.org Wed May 13 23:25:23 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 13:44:48 -0400
+Subject: xfrm: defensively unhash xfrm_state lists in __xfrm_state_delete
+To: stable@vger.kernel.org
+Cc: Michal Kosiorek <mkosiorek121@gmail.com>, Steffen Klassert <steffen.klassert@secunet.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260513174448.3896129-1-sashal@kernel.org>
+
+From: Michal Kosiorek <mkosiorek121@gmail.com>
+
+[ Upstream commit 14acf9652e5690de3c7486c6db5fb8dafd0a32a3 ]
+
+KASAN reproduces a slab-use-after-free in __xfrm_state_delete()'s
+hlist_del_rcu calls under syzkaller load on linux-6.12.y stable
+(reproduced on 6.12.47, also reachable via the same code path on
+torvalds/master and on the ipsec tree). Nine unique signatures cluster
+in the xfrm_state lifecycle, the load-bearing one being:
+
+  BUG: KASAN: slab-use-after-free in __hlist_del include/linux/list.h:990 [inline]
+  BUG: KASAN: slab-use-after-free in hlist_del_rcu include/linux/rculist.h:516 [inline]
+  BUG: KASAN: slab-use-after-free in __xfrm_state_delete net/xfrm/xfrm_state.c
+  Write of size 8 at addr ffff8881198bcb70 by task kworker/u8:9/435
+
+  Workqueue: netns cleanup_net
+  Call Trace:
+   __hlist_del / hlist_del_rcu
+   __xfrm_state_delete
+   xfrm_state_delete
+   xfrm_state_flush
+   xfrm_state_fini
+   ops_exit_list
+   cleanup_net
+
+The other observed signatures hit the same slab object from
+__xfrm_state_lookup, xfrm_alloc_spi, __xfrm_state_insert and an OOB
+write variant of __xfrm_state_delete, all on the byseq/byspi
+hash chains.
+
+__xfrm_state_delete() guards its byseq and byspi unhashes with
+value-based predicates:
+
+       if (x->km.seq)
+               hlist_del_rcu(&x->byseq);
+       if (x->id.spi)
+               hlist_del_rcu(&x->byspi);
+
+while everywhere else in the file (e.g. state_cache, state_cache_input)
+the safer hlist_unhashed() check is used. xfrm_alloc_spi() sets
+x->id.spi = newspi inside xfrm_state_lock and then immediately inserts
+into byspi, but a path that observes x->id.spi != 0 outside of
+xfrm_state_lock can still skip-or-hit the byspi unhash inconsistently
+with whether x is actually on the list. The same holds for x->km.seq
+versus byseq, and the bydst/bysrc unhashes have no predicate at all,
+so a second __xfrm_state_delete() on the same object writes through
+LIST_POISON pprev.
+
+The defensive change here:
+
+  - Use hlist_del_init_rcu() instead of hlist_del_rcu() on bydst,
+    bysrc, byseq and byspi so a second deletion is a no-op rather
+    than a write through LIST_POISON pprev. The byseq/byspi nodes
+    are already initialised in xfrm_state_alloc().
+  - Test hlist_unhashed() rather than the value predicate for
+    byseq/byspi, so the unhash decision tracks list state rather than
+    mutable scalar fields.
+
+Empirical verification: applied this patch on top of v6.12.47, rebuilt,
+and re-ran the same syzkaller harness for 1h16m on a previously-crashy
+configuration that produced ~100 hits each of slab-use-after-free
+Read in xfrm_alloc_spi / Read in __xfrm_state_lookup / Write in
+__xfrm_state_delete. After the patch, 7.1M execs across 32 VMs at
+~1550 exec/sec produced zero xfrm_state UAF/OOB hits. /proc/slabinfo
+confirms the xfrm_state slab is actively allocated and freed during
+the run (~143 KiB resident), so the fuzzer is still exercising those
+code paths -- they just no longer crash.
+
+Reproduction:
+
+  - Linux 6.12.47 x86_64 + KASAN_GENERIC + KASAN_INLINE + KCOV
+  - syzkaller @ 746545b8b1e4c3a128db8652b340d3df90ce61db
+  - 32 QEMU/KVM VMs x 2 vCPU on AWS c5.metal bare metal
+  - 9 unique signatures collected in ~9h, all within xfrm_state
+    lifecycle
+
+Fixes: fe9f1d8779cb ("xfrm: add state hashtable keyed by seq")
+Fixes: 7b4dc3600e48 ("[XFRM]: Do not add a state whose SPI is zero to the SPI hash.")
+Reported-by: Michal Kosiorek <mkosiorek121@gmail.com>
+Tested-by: Michal Kosiorek <mkosiorek121@gmail.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Michal Kosiorek <mkosiorek121@gmail.com>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+[ dropped state_cache/state_cache_input unhash hunks and xfrm_nat_keepalive_state_updated() call ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/xfrm/xfrm_state.c |   12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/net/xfrm/xfrm_state.c
++++ b/net/xfrm/xfrm_state.c
+@@ -681,12 +681,12 @@ int __xfrm_state_delete(struct xfrm_stat
+               x->km.state = XFRM_STATE_DEAD;
+               spin_lock(&net->xfrm.xfrm_state_lock);
+               list_del(&x->km.all);
+-              hlist_del_rcu(&x->bydst);
+-              hlist_del_rcu(&x->bysrc);
+-              if (x->km.seq)
+-                      hlist_del_rcu(&x->byseq);
+-              if (x->id.spi)
+-                      hlist_del_rcu(&x->byspi);
++              hlist_del_init_rcu(&x->bydst);
++              hlist_del_init_rcu(&x->bysrc);
++              if (!hlist_unhashed(&x->byseq))
++                      hlist_del_init_rcu(&x->byseq);
++              if (!hlist_unhashed(&x->byspi))
++                      hlist_del_init_rcu(&x->byspi);
+               net->xfrm.state_num--;
+               spin_unlock(&net->xfrm.xfrm_state_lock);