From: Greg Kroah-Hartman Date: Tue, 16 Jun 2026 05:41:01 +0000 (+0530) Subject: 5.15-stable patches X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d8fce6a1e9b517e3e3b06f86dace21356a87cbe2;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches 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 --- 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 index 0000000000..bfa3c73612 --- /dev/null +++ b/queue-5.15/arm64-tlb-flush-walk-cache-when-unsharing-pmd-tables.patch @@ -0,0 +1,55 @@ +From stable+bounces-259522-greg=kroah.com@vger.kernel.org Mon Jun 1 16:21:23 2026 +From: Sasha Levin +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 , Catalin Marinas , Sasha Levin +Message-ID: <20260601105116.381170-1-sashal@kernel.org> + +From: Zeng Heng + +[ 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 +Fixes: 8ce720d5bd91 ("mm/hugetlb: fix excessive IPI broadcasts when unsharing PMD tables using mmu_gather") +Cc: +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..00727c15df --- /dev/null +++ b/queue-5.15/bluetooth-consolidate-code-around-sk_alloc-into-a-helper-function.patch @@ -0,0 +1,204 @@ +From stable+bounces-256822-greg=kroah.com@vger.kernel.org Sat May 30 05:13:46 2026 +From: Sasha Levin +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 , Sasha Levin +Message-ID: <20260529233826.1908632-1-sashal@kernel.org> + +From: Luiz Augusto von Dentz + +[ 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 +Stable-dep-of: e83f5e24da74 ("Bluetooth: serialize accept_q access") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..0130543912 --- /dev/null +++ b/queue-5.15/bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch @@ -0,0 +1,210 @@ +From stable+bounces-256726-greg=kroah.com@vger.kernel.org Sat May 30 00:38:46 2026 +From: Sasha Levin +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ş" , "Siwei Zhang" , "Luiz Augusto von Dentz" , "Sasha Levin" +Message-ID: <20260529190813.1682934-1-sashal@kernel.org> + +From: Safa Karakuş + +[ 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 +Reviewed-by: Siwei Zhang +Signed-off-by: Safa Karakuş +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..cd67fc171a --- /dev/null +++ b/queue-5.15/bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch @@ -0,0 +1,155 @@ +From stable+bounces-256793-greg=kroah.com@vger.kernel.org Sat May 30 03:18:53 2026 +From: Sasha Levin +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 , Paul Menzel , Bartosz Golaszewski , Luiz Augusto von Dentz , Sasha Levin +Message-ID: <20260529214845.1804717-1-sashal@kernel.org> + +From: Shuai Zhang + +[ 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 +Acked-by: Bartosz Golaszewski +Signed-off-by: Shuai Zhang +Signed-off-by: Luiz Augusto von Dentz +[ adapted to `vmalloc`-based memdump path and older `qca_serdev_shutdown(struct device *dev)` signature ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..638dc34d1f --- /dev/null +++ b/queue-5.15/bluetooth-hci_sync-make-use-of-hci_cmd_sync_queue-set-2.patch @@ -0,0 +1,130 @@ +From stable+bounces-256805-greg=kroah.com@vger.kernel.org Sat May 30 04:54:04 2026 +From: Sasha Levin +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 , Marcel Holtmann , Sasha Levin +Message-ID: <20260529232204.1873991-1-sashal@kernel.org> + +From: Luiz Augusto von Dentz + +[ 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 +Signed-off-by: Marcel Holtmann +Stable-dep-of: d3f7d17960ed ("Bluetooth: MGMT: validate Add Extended Advertising Data length") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..2bcaa4bea8 --- /dev/null +++ b/queue-5.15/bluetooth-init-sk_peer_-on-bt_sock_alloc.patch @@ -0,0 +1,139 @@ +From stable+bounces-256823-greg=kroah.com@vger.kernel.org Sat May 30 05:13:59 2026 +From: Sasha Levin +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 , Sasha Levin +Message-ID: <20260529233826.1908632-2-sashal@kernel.org> + +From: Luiz Augusto von Dentz + +[ 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 +Stable-dep-of: e83f5e24da74 ("Bluetooth: serialize accept_q access") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..17e6c31ffc --- /dev/null +++ b/queue-5.15/bluetooth-l2cap-use-chan-timer-to-close-channels-in-cleanup_listen.patch @@ -0,0 +1,73 @@ +From stable+bounces-260494-greg=kroah.com@vger.kernel.org Thu Jun 4 19:23:54 2026 +From: Sasha Levin +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 , Luiz Augusto von Dentz , Sasha Levin +Message-ID: <20260604133726.3434716-2-sashal@kernel.org> + +From: Siwei Zhang + +[ 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: # 0b58004: Bluetooth: fix UAF in l2cap_sock_cleanup_listen() vs l2cap_conn_del() +Signed-off-by: Siwei Zhang +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..6e390bf7ec --- /dev/null +++ b/queue-5.15/bluetooth-mgmt-validate-add-extended-advertising-data-length.patch @@ -0,0 +1,58 @@ +From stable+bounces-256806-greg=kroah.com@vger.kernel.org Sat May 30 04:54:05 2026 +From: Sasha Levin +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 , Luiz Augusto von Dentz , Sasha Levin +Message-ID: <20260529232204.1873991-2-sashal@kernel.org> + +From: Michael Bommarito + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..e53c6826db --- /dev/null +++ b/queue-5.15/bluetooth-serialize-accept_q-access.patch @@ -0,0 +1,222 @@ +From stable+bounces-256824-greg=kroah.com@vger.kernel.org Sat May 30 05:08:35 2026 +From: Sasha Levin +Date: Fri, 29 May 2026 19:38:26 -0400 +Subject: Bluetooth: serialize accept_q access +To: stable@vger.kernel.org +Cc: Jiexun Wang , Jann Horn , Yuan Tan , Yifan Wu , Juefei Pu , Xin Liu , Ren Wei , Luiz Augusto von Dentz , Sasha Levin +Message-ID: <20260529233826.1908632-3-sashal@kernel.org> + +From: Jiexun Wang + +[ 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 +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Jiexun Wang +Signed-off-by: Ren Wei +Signed-off-by: Jiexun Wang +Reviewed-by: Jann Horn +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..9e084b7f78 --- /dev/null +++ b/queue-5.15/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch @@ -0,0 +1,59 @@ +From stable+bounces-247798-greg=kroah.com@vger.kernel.org Fri May 15 20:20:56 2026 +From: Sasha Levin +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 , Yochai Eisenrich , David Sterba , Sasha Levin +Message-ID: <20260515144827.3249028-1-sashal@kernel.org> + +From: Yochai Eisenrich + +[ 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 +Reviewed-by: David Sterba +Signed-off-by: David Sterba +[ adapted upstream's `return -EFAULT;` to stable's `ret = -EFAULT;` fall-through to existing `out:` cleanup label ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..78798f7a59 --- /dev/null +++ b/queue-5.15/btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch @@ -0,0 +1,224 @@ +From stable+bounces-249151-greg=kroah.com@vger.kernel.org Mon May 18 04:35:06 2026 +From: Sasha Levin +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 , Slava0135 , David Sterba , Sasha Levin +Message-ID: <20260517230456.408419-1-sashal@kernel.org> + +From: Filipe Manana + +[ 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 + + + +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] + [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] + [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 +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 +Signed-off-by: David Sterba +[ 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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..1098ab62fa --- /dev/null +++ b/queue-5.15/drm-hyperv-remove-support-for-hyper-v-2008-and-2008r2-win7.patch @@ -0,0 +1,93 @@ +From stable+bounces-260841-greg=kroah.com@vger.kernel.org Sat Jun 6 07:49:19 2026 +From: Sasha Levin +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 , Deepak Rawat , "Andrea Parri (Microsoft)" , Wei Liu , Sasha Levin +Message-ID: <20260606021901.2488724-1-sashal@kernel.org> + +From: Michael Kelley + +[ 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 +Reviewed-by: Deepak Rawat +Reviewed-by: Andrea Parri (Microsoft) +Link: https://lore.kernel.org/r/1651509391-2058-5-git-send-email-mikelley@microsoft.com +Signed-off-by: Wei Liu +Stable-dep-of: 13d33b9ef670 ("drm/hyperv: validate resolution_count and fix WIN8 fallback") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..f41a831047 --- /dev/null +++ b/queue-5.15/drm-hyperv-validate-resolution_count-and-fix-win8-fallback.patch @@ -0,0 +1,71 @@ +From stable+bounces-260842-greg=kroah.com@vger.kernel.org Sat Jun 6 07:49:28 2026 +From: Sasha Levin +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 , Michael Kelley , Hamza Mahfooz , Sasha Levin +Message-ID: <20260606021901.2488724-2-sashal@kernel.org> + +From: Berkant Koc + +[ 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 +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 +Tested-by: Michael Kelley +Signed-off-by: Hamza Mahfooz +Link: https://patch.msgid.link/6945b22419c7d404b4954a113de2ac9c900dba93.1779542874.git.me@berkoc.com +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..33ebbdd6a7 --- /dev/null +++ b/queue-5.15/f2fs-fix-false-alarm-of-lockdep-on-cp_global_sem-lock.patch @@ -0,0 +1,102 @@ +From stable+bounces-249897-greg=kroah.com@vger.kernel.org Wed May 20 17:21:50 2026 +From: Sasha Levin +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 , stable@kernel.org, Shin'ichiro Kawasaki , Jaegeuk Kim , Sasha Levin +Message-ID: <20260520114907.3473814-1-sashal@kernel.org> + +From: Chao Yu + +[ 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 +Closes: https://lore.kernel.org/linux-f2fs-devel/20260218125237.3340441-1-shinichiro.kawasaki@wdc.com +Signed-off-by: Shin'ichiro Kawasaki +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +[ 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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..aaf9ea6877 --- /dev/null +++ b/queue-5.15/f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch @@ -0,0 +1,68 @@ +From stable+bounces-249887-greg=kroah.com@vger.kernel.org Wed May 20 17:13:11 2026 +From: Sasha Levin +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 , stable@kernel.org, Chao Yu , Jaegeuk Kim , Sasha Levin +Message-ID: <20260520112913.3439673-1-sashal@kernel.org> + +From: Yongpeng Yang + +[ 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 +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +[ renamed `ifolio` to `ipage` in `inline_data_addr()` and `F2FS_INODE()` calls ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..6dbd631dcc --- /dev/null +++ b/queue-5.15/fbcon-avoid-oob-font-access-if-console-rotation-fails.patch @@ -0,0 +1,56 @@ +From stable+bounces-247682-greg=kroah.com@vger.kernel.org Fri May 15 17:52:20 2026 +From: Sasha Levin +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 , Helge Deller , Sasha Levin +Message-ID: <20260515114520.3021992-1-sashal@kernel.org> + +From: Thomas Zimmermann + +[ 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 +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 +[ renamed `par` to `ops` to match the 6.12 local pointer name ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..7f5163e282 --- /dev/null +++ b/queue-5.15/genetlink-use-internal-flags-for-multicast-groups.patch @@ -0,0 +1,116 @@ +From stable+bounces-256670-greg=kroah.com@vger.kernel.org Fri May 29 22:58:06 2026 +From: Sasha Levin +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 , Mat Martineau , Andy Shevchenko , "David S. Miller" , Sasha Levin +Message-ID: <20260529172153.1318415-1-sashal@kernel.org> + +From: Ido Schimmel + +[ 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 +Reviewed-by: Mat Martineau +Reviewed-by: Andy Shevchenko +Signed-off-by: David S. Miller +Stable-dep-of: d1ebfce2c1d1 ("smb: client: require net admin for CIFS SWN netlink") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..ee94ac881e --- /dev/null +++ b/queue-5.15/hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch @@ -0,0 +1,92 @@ +From stable+bounces-263428-greg=kroah.com@vger.kernel.org Mon Jun 15 23:47:06 2026 +From: Sasha Levin +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 , Paolo Abeni , Sasha Levin +Message-ID: <20260615181657.2320366-1-sashal@kernel.org> + +From: Anton Leontev + +[ 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 +Link: https://patch.msgid.link/20260604165938.32033-1-leontyevantony@gmail.com +Signed-off-by: Paolo Abeni +[ adapted `phys_to_page(paddr)` to `pfn_to_page(PHYS_PFN(paddr))` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 index 0000000000..9721a521d2 --- /dev/null +++ b/queue-5.15/ice-fix-vf-queue-configuration-with-low-mtu-values.patch @@ -0,0 +1,62 @@ +From stable+bounces-256870-greg=kroah.com@vger.kernel.org Sat May 30 17:09:06 2026 +From: Sasha Levin +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 , Jacob Keller , Michal Swiatkowski , Paul Menzel , Rafal Romanowski , Tony Nguyen , Jakub Kicinski , Sasha Levin +Message-ID: <20260530113858.1937093-1-sashal@kernel.org> + +From: Jose Ignacio Tornos Martinez + +[ 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 +Reviewed-by: Jacob Keller +Reviewed-by: Michal Swiatkowski +Reviewed-by: Paul Menzel +Tested-by: Rafal Romanowski +Signed-off-by: Tony Nguyen +Link: https://patch.msgid.link/20260515182419.1597859-3-anthony.l.nguyen@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..c10676a35c --- /dev/null +++ b/queue-5.15/iio-adc-fix-the-return-value-handle-for-platform_get_irq.patch @@ -0,0 +1,81 @@ +From stable+bounces-260514-greg=kroah.com@vger.kernel.org Thu Jun 4 20:15:22 2026 +From: Sasha Levin +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 , Jonathan Cameron , Sasha Levin +Message-ID: <20260604143031.3608772-1-sashal@kernel.org> + +From: Ruan Jinjie + +[ 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 +Link: https://lore.kernel.org/r/20230727131607.2897937-1-ruanjinjie@huawei.com +Signed-off-by: Jonathan Cameron +Stable-dep-of: 0d42e2c0bd6c ("iio: adc: npcm: fix unbalanced clk_disable_unprepare()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..f536ea12da --- /dev/null +++ b/queue-5.15/iio-adc-npcm-convert-to-platform-remove-callback-returning-void.patch @@ -0,0 +1,60 @@ +From stable+bounces-260515-greg=kroah.com@vger.kernel.org Thu Jun 4 20:15:24 2026 +From: Sasha Levin +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" , "Jonathan Cameron" , "Sasha Levin" +Message-ID: <20260604143031.3608772-2-sashal@kernel.org> + +From: Uwe Kleine-König + +[ 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 +Link: https://lore.kernel.org/r/20230919174931.1417681-18-u.kleine-koenig@pengutronix.de +Signed-off-by: Jonathan Cameron +Stable-dep-of: 0d42e2c0bd6c ("iio: adc: npcm: fix unbalanced clk_disable_unprepare()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..08ec350ee1 --- /dev/null +++ b/queue-5.15/iio-adc-npcm-fix-unbalanced-clk_disable_unprepare.patch @@ -0,0 +1,112 @@ +From stable+bounces-260516-greg=kroah.com@vger.kernel.org Thu Jun 4 20:15:25 2026 +From: Sasha Levin +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 , Andy Shevchenko , Stable@vger.kernel.org, Jonathan Cameron , Sasha Levin +Message-ID: <20260604143031.3608772-3-sashal@kernel.org> + +From: David Carlier + +[ 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 +Reviewed-by: Andy Shevchenko +Cc: +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..bbbdef647c --- /dev/null +++ b/queue-5.15/iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch @@ -0,0 +1,38 @@ +From stable+bounces-260571-greg=kroah.com@vger.kernel.org Fri Jun 5 01:13:30 2026 +From: Sasha Levin +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 , Stable@vger.kernel.org, Jonathan Cameron , Sasha Levin +Message-ID: <20260604194017.889785-2-sashal@kernel.org> + +From: Antoniu Miclaus + +[ 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 +Cc: +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..1e37f44419 --- /dev/null +++ b/queue-5.15/iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch @@ -0,0 +1,178 @@ +From stable+bounces-260570-greg=kroah.com@vger.kernel.org Fri Jun 5 01:13:23 2026 +From: Sasha Levin +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 , David Lechner , Tomasz Duszynski , Sasha Levin +Message-ID: <20260604194017.889785-1-sashal@kernel.org> + +From: Jonathan Cameron + +[ 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 +Cc: Tomasz Duszynski +Reviewed-by: David Lechner +Link: https://patch.msgid.link/20250209180624.701140-3-jic23@kernel.org +Signed-off-by: Jonathan Cameron +Stable-dep-of: 5aba4f94b225 ("iio: chemical: scd30: fix division by zero in write_raw") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 + */ + #include ++#include + #include + #include + #include +@@ -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 index 0000000000..820e23e525 --- /dev/null +++ b/queue-5.15/iio-dac-ad5686-acquire-lock-when-doing-powerdown-control.patch @@ -0,0 +1,67 @@ +From stable+bounces-260524-greg=kroah.com@vger.kernel.org Thu Jun 4 20:43:03 2026 +From: Sasha Levin +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 , Stable@vger.kernel.org, Jonathan Cameron , Sasha Levin +Message-ID: <20260604150204.3692750-1-sashal@kernel.org> + +From: Rodrigo Alencar + +[ 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 +Cc: +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..09f82a44e8 --- /dev/null +++ b/queue-5.15/iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch @@ -0,0 +1,65 @@ +From stable+bounces-260603-greg=kroah.com@vger.kernel.org Fri Jun 5 07:15:42 2026 +From: Sasha Levin +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 , Andy Shevchenko , Stable@vger.kernel.org, Jonathan Cameron , Sasha Levin +Message-ID: <20260605013113.2963901-1-sashal@kernel.org> + +From: Rodrigo Alencar + +[ 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 +Signed-off-by: Rodrigo Alencar +Cc: +Signed-off-by: Jonathan Cameron +[ adapted `has_external_vref` to the in-tree equivalent `voltage_uv` variable in the `val =` computation ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..3942db982f --- /dev/null +++ b/queue-5.15/iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch @@ -0,0 +1,39 @@ +From stable+bounces-260564-greg=kroah.com@vger.kernel.org Fri Jun 5 00:48:23 2026 +From: Sasha Levin +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" , "Nuno Sá" , Stable@vger.kernel.org, "Jonathan Cameron" , "Sasha Levin" +Message-ID: <20260604191752.743368-1-sashal@kernel.org> + +From: Antoniu Miclaus + +[ 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 +Reviewed-by: Nuno Sá +Cc: +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..19d507892b --- /dev/null +++ b/queue-5.15/ipv6-addrconf-annotate-data-races-around-devconf-fields-ii.patch @@ -0,0 +1,397 @@ +From stable+bounces-256872-greg=kroah.com@vger.kernel.org Sat May 30 17:09:36 2026 +From: Sasha Levin +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 , Jiri Pirko , "David S. Miller" , Sasha Levin +Message-ID: <20260530113927.1939561-1-sashal@kernel.org> + +From: Eric Dumazet + +[ 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 +Reviewed-by: Jiri Pirko +Signed-off-by: David S. Miller +Stable-dep-of: d4ea0dfd7501 ("ipv6: ioam: add NULL check for idev in ipv6_hop_ioam()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..3c7c33f9a5 --- /dev/null +++ b/queue-5.15/ipv6-ioam-add-null-check-for-idev-in-ipv6_hop_ioam.patch @@ -0,0 +1,59 @@ +From stable+bounces-256873-greg=kroah.com@vger.kernel.org Sat May 30 17:09:38 2026 +From: Sasha Levin +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 , Ido Schimmel , Jakub Kicinski , Sasha Levin +Message-ID: <20260530113927.1939561-2-sashal@kernel.org> + +From: Justin Iurman + +[ 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 +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260517183059.29140-1-justin.iurman@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..18401df0ba --- /dev/null +++ b/queue-5.15/mm-huge_memory-update-file-pmd-counter-before-folio_put.patch @@ -0,0 +1,56 @@ +From stable+bounces-263511-greg=kroah.com@vger.kernel.org Tue Jun 16 07:05:10 2026 +From: Sasha Levin +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 , Lorenzo Stoakes , "David Hildenbrand (arm)" , Lance Yang , Dev Jain , Baolin Wang , Barry Song , Chen Jun , Kefeng Wang , "Liam R. Howlett" , Nico Pache , Ryan Roberts , Vlastimil Babka , Yang Shi , Zi Yan , Andrew Morton , Sasha Levin +Message-ID: <20260616013503.2708473-1-sashal@kernel.org> + +From: Yin Tirui + +[ 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 +Reviewed-by: Lorenzo Stoakes +Acked-by: David Hildenbrand (arm) +Reviewed-by: Lance Yang +Reviewed-by: Dev Jain +Cc: Baolin Wang +Cc: Barry Song +Cc: Chen Jun +Cc: Kefeng Wang +Cc: Liam R. Howlett +Cc: Nico Pache +Cc: Ryan Roberts +Cc: Vlastimil Babka +Cc: Yang Shi +Cc: Zi Yan +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..cacc0383c7 --- /dev/null +++ b/queue-5.15/mm-hugetlb_cma-round-up-per_node-before-logging-it.patch @@ -0,0 +1,79 @@ +From stable+bounces-247238-greg=kroah.com@vger.kernel.org Thu May 14 21:22:58 2026 +From: Sasha Levin +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 , Muchun Song , David Hildenbrand , Oscar Salvador , Andrew Morton , Sasha Levin +Message-ID: <20260514155252.308763-1-sashal@kernel.org> + +From: Sang-Heon Jeon + +[ 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 +Reviewed-by: Muchun Song +Cc: David Hildenbrand +Cc: Oscar Salvador +Cc: +Signed-off-by: Andrew Morton +[ applied the one-line `round_up` to `mm/hugetlb.c` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..f7b05e9866 --- /dev/null +++ b/queue-5.15/mptcp-do-not-drop-partial-packets.patch @@ -0,0 +1,77 @@ +From stable+bounces-259286-greg=kroah.com@vger.kernel.org Sun May 31 01:17:53 2026 +From: Sasha Levin +Date: Sat, 30 May 2026 15:47:45 -0400 +Subject: mptcp: do not drop partial packets +To: stable@vger.kernel.org +Cc: Shardul Bankar , Paolo Abeni , "Matthieu Baerts (NGI0)" , Sasha Levin +Message-ID: <20260530194745.3257532-1-sashal@kernel.org> + +From: Shardul Bankar + +[ 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 +[pabeni@redhat.com: update map] +Signed-off-by: Paolo Abeni +Reviewed-by: Matthieu Baerts (NGI0) +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260515-net-mptcp-misc-fixes-7-1-rc4-v2-1-701e96419f2f@kernel.org +Signed-off-by: Paolo Abeni +[ 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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..fc0dc17744 --- /dev/null +++ b/queue-5.15/mptcp-pm-add_addr-rtx-fix-potential-data-race.patch @@ -0,0 +1,56 @@ +From stable+bounces-249313-greg=kroah.com@vger.kernel.org Mon May 18 20:14:36 2026 +From: Sasha Levin +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)" , Mat Martineau , Jakub Kicinski , Sasha Levin +Message-ID: <20260518144042.1361354-1-sashal@kernel.org> + +From: "Matthieu Baerts (NGI0)" + +[ 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 +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-3-fca8091060a4@kernel.org +Signed-off-by: Jakub Kicinski +[ applied hunk to `net/mptcp/pm_netlink.c` instead of `net/mptcp/pm.c` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..5b7f4c7b57 --- /dev/null +++ b/queue-5.15/mptcp-pm-add_addr-rtx-resched-blocked-add_addr-quicker.patch @@ -0,0 +1,53 @@ +From stable+bounces-249637-greg=kroah.com@vger.kernel.org Tue May 19 22:17:43 2026 +From: Sasha Levin +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)" , Mat Martineau , Jakub Kicinski , Sasha Levin +Message-ID: <20260519161804.2778143-1-sashal@kernel.org> + +From: "Matthieu Baerts (NGI0)" + +[ 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 +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-6-fca8091060a4@kernel.org +Signed-off-by: Jakub Kicinski +[ replaced `TCP_RTO_MAX / 8` with `HZ` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..211ec8ac7b --- /dev/null +++ b/queue-5.15/mptcp-pm-fix-add_addr-timer-infinite-retry-on-option-space-insufficient.patch @@ -0,0 +1,144 @@ +From stable+bounces-256883-greg=kroah.com@vger.kernel.org Sat May 30 17:19:42 2026 +From: Sasha Levin +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 , "Matthieu Baerts (NGI0)" , Paolo Abeni , Sasha Levin +Message-ID: <20260530114813.1965800-1-sashal@kernel.org> + +From: Li Xiasong + +[ 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 +Reviewed-by: Matthieu Baerts (NGI0) +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260515-net-mptcp-misc-fixes-7-1-rc4-v2-2-701e96419f2f@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..87700e051e --- /dev/null +++ b/queue-5.15/mptcp-pm-prio-skip-closed-subflows.patch @@ -0,0 +1,46 @@ +From stable+bounces-249304-greg=kroah.com@vger.kernel.org Mon May 18 20:00:14 2026 +From: Sasha Levin +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)" , Mat Martineau , Jakub Kicinski , Sasha Levin +Message-ID: <20260518142333.1308198-1-sashal@kernel.org> + +From: "Matthieu Baerts (NGI0)" + +[ 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 +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-9-fca8091060a4@kernel.org +Signed-off-by: Jakub Kicinski +[ applied to renamed function `mptcp_pm_nl_mp_prio_send_ack()` in `pm_netlink.c` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index d85e0b05d0..0000000000 --- a/queue-5.15/mtd-docg3-convert-to-platform-remove-callback-returning-void.patch +++ /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 -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" , "Miquel Raynal" , "Tudor Ambarus" , "Sasha Levin" -Message-ID: <20260502021154.4166366-1-sashal@kernel.org> - -From: Uwe Kleine-König - -[ 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 -Signed-off-by: Miquel Raynal -Acked-by: Tudor Ambarus -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 -Signed-off-by: Greg Kroah-Hartman ---- - 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 index 1ecea34524..0000000000 --- a/queue-5.15/mtd-docg3-fix-use-after-free-in-docg3_release.patch +++ /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 -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 , Miquel Raynal , Sasha Levin -Message-ID: <20260502021154.4166366-2-sashal@kernel.org> - -From: James Kim - -[ 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 -Signed-off-by: Miquel Raynal -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - 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 index 0000000000..3757f2a33e --- /dev/null +++ b/queue-5.15/net-hsr-defer-node-table-free-until-after-rcu-readers.patch @@ -0,0 +1,55 @@ +From stable+bounces-256837-greg=kroah.com@vger.kernel.org Sat May 30 05:37:45 2026 +From: Sasha Levin +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 , Jakub Kicinski , Sasha Levin +Message-ID: <20260530000734.2087399-1-sashal@kernel.org> + +From: Michael Bommarito + +[ 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 +Link: https://patch.msgid.link/20260513233838.3064715-2-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +[ replaced `list_del`+`call_rcu(hsr_free_node_rcu)` with `list_del_rcu`+`kfree_rcu(node, rcu_head)` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..98a0637eca --- /dev/null +++ b/queue-5.15/net-ipv4-stop-checking-crypto_ahash_alignmask.patch @@ -0,0 +1,87 @@ +From stable+bounces-246955-greg=kroah.com@vger.kernel.org Wed May 13 22:40:24 2026 +From: Sasha Levin +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 , Herbert Xu , Sasha Levin +Message-ID: <20260513170942.3829179-1-sashal@kernel.org> + +From: Eric Biggers + +[ 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 +Signed-off-by: Herbert Xu +Stable-dep-of: ec54093e6a8f ("xfrm: ah: account for ESN high bits in async callbacks") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..7f0e1f010b --- /dev/null +++ b/queue-5.15/net-ipv6-stop-checking-crypto_ahash_alignmask.patch @@ -0,0 +1,87 @@ +From stable+bounces-246956-greg=kroah.com@vger.kernel.org Wed May 13 22:40:25 2026 +From: Sasha Levin +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 , Herbert Xu , Sasha Levin +Message-ID: <20260513170942.3829179-2-sashal@kernel.org> + +From: Eric Biggers + +[ 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 +Signed-off-by: Herbert Xu +Stable-dep-of: ec54093e6a8f ("xfrm: ah: account for ESN high bits in async callbacks") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..74eed5ebe0 --- /dev/null +++ b/queue-5.15/net-skbuff-fix-missing-zerocopy-reference-in-pskb_carve-helpers.patch @@ -0,0 +1,92 @@ +From stable+bounces-260705-greg=kroah.com@vger.kernel.org Fri Jun 5 19:27:46 2026 +From: Sasha Levin +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 , Willem de Bruijn , Paolo Abeni , Sasha Levin +Message-ID: <20260605135738.973875-1-sashal@kernel.org> + +From: Minh Nguyen + +[ 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 +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260526041240.329462-1-minhnguyen.080505@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..7998a0daeb --- /dev/null +++ b/queue-5.15/netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch @@ -0,0 +1,86 @@ +From stable+bounces-263416-greg=kroah.com@vger.kernel.org Mon Jun 15 23:07:24 2026 +From: Sasha Levin +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 , Florian Westphal , Pablo Neira Ayuso , Sasha Levin +Message-ID: <20260615173718.2302669-1-sashal@kernel.org> + +From: Davide Ornaghi + +[ 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 +Cc: stable@vger.kernel.org +Signed-off-by: Davide Ornaghi +Signed-off-by: Pablo Neira Ayuso +[ 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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..e08b153b30 --- /dev/null +++ b/queue-5.15/octeontx2-af-cgx-add-bounds-check-to-cgx_speed_mbps-index.patch @@ -0,0 +1,52 @@ +From stable+bounces-259296-greg=kroah.com@vger.kernel.org Sun May 31 01:38:11 2026 +From: Sasha Levin +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 , Sunil Goutham , Linu Cherian , Geetha sowjanya , hariprasad , Subbaraya Sundeep , Andrew Lunn , stable , Greg Kroah-Hartman , Jakub Kicinski , Sasha Levin +Message-ID: <20260530200739.3283536-1-sashal@kernel.org> + +From: Sam Daly + +[ 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 +Cc: Linu Cherian +Cc: Geetha sowjanya +Cc: hariprasad +Cc: Subbaraya Sundeep +Cc: Andrew Lunn +Cc: stable +Signed-off-by: Sam Daly +Signed-off-by: Greg Kroah-Hartman +Link: https://patch.msgid.link/2026051352-refined-demise-e88d@gregkh +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..4a86f70fae --- /dev/null +++ b/queue-5.15/octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch @@ -0,0 +1,62 @@ +From stable+bounces-259297-greg=kroah.com@vger.kernel.org Sun May 31 01:43:35 2026 +From: Sasha Levin +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 , Zilin Guan , Simon Horman , Jakub Kicinski , Sasha Levin +Message-ID: <20260530201327.3310899-1-sashal@kernel.org> + +From: Dawei Feng + +[ 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 +Signed-off-by: Dawei Feng +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260515151826.1005397-1-dawei.feng@seu.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..b795867e4d --- /dev/null +++ b/queue-5.15/phy-tegra-xusb-disable-trk-clk-when-not-in-use.patch @@ -0,0 +1,51 @@ +From sashal@kernel.org Mon Jun 1 16:32:21 2026 +From: Sasha Levin +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 , Jon Hunter , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260601110218.439979-1-sashal@kernel.org> + +From: Wayne Chang + +[ 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 +Signed-off-by: Jon Hunter +Link: https://lore.kernel.org/r/20230111110450.24617-5-jonathanh@nvidia.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: da110228b54f ("phy: tegra: xusb: Fix per-pad high-speed termination calibration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..b886ca10cf --- /dev/null +++ b/queue-5.15/phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch @@ -0,0 +1,144 @@ +From stable+bounces-259529-greg=kroah.com@vger.kernel.org Mon Jun 1 16:37:04 2026 +From: Sasha Levin +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 , Wei-Cheng Chen , Jon Hunter , Vinod Koul , Sasha Levin +Message-ID: <20260601110218.439979-2-sashal@kernel.org> + +From: Wayne Chang + +[ 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 +Signed-off-by: Wei-Cheng Chen +Reviewed-by: Jon Hunter +Tested-by: Jon Hunter +Link: https://patch.msgid.link/20260504033305.2283145-1-weichengc@nvidia.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..9cd22e8047 --- /dev/null +++ b/queue-5.15/pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch @@ -0,0 +1,72 @@ +From stable+bounces-247969-greg=kroah.com@vger.kernel.org Fri May 15 21:43:49 2026 +From: Sasha Levin +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 , Geert Uytterhoeven , Geert Uytterhoeven , Sasha Levin +Message-ID: <20260515155536.3359591-1-sashal@kernel.org> + +From: Ulf Hansson + +[ 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 +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 +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..f358d790a0 --- /dev/null +++ b/queue-5.15/qed-fix-double-free-in-qed_cxt_tables_alloc.patch @@ -0,0 +1,58 @@ +From stable+bounces-256817-greg=kroah.com@vger.kernel.org Sat May 30 05:00:39 2026 +From: Sasha Levin +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 , Zilin Guan , Jakub Kicinski , Sasha Levin +Message-ID: <20260529233029.1896294-2-sashal@kernel.org> + +From: Dawei Feng + +[ 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 +Signed-off-by: Dawei Feng +Link: https://patch.msgid.link/20260520070323.2762379-1-dawei.feng@seu.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..b497f91e4c --- /dev/null +++ b/queue-5.15/qed-use-the-bitmap-api-to-simplify-some-functions.patch @@ -0,0 +1,99 @@ +From stable+bounces-256816-greg=kroah.com@vger.kernel.org Sat May 30 05:00:37 2026 +From: Sasha Levin +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 , "David S. Miller" , Sasha Levin +Message-ID: <20260529233029.1896294-1-sashal@kernel.org> + +From: Christophe JAILLET + +[ 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 +Signed-off-by: David S. Miller +Stable-dep-of: 2bccfb8476ca ("qed: fix double free in qed_cxt_tables_alloc()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..e80f98ee5f --- /dev/null +++ b/queue-5.15/rdma-move-dma-block-iterator-logic-into-dedicated-files.patch @@ -0,0 +1,482 @@ +From stable+bounces-263506-greg=kroah.com@vger.kernel.org Tue Jun 16 06:38:08 2026 +From: Sasha Levin +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 , Sasha Levin +Message-ID: <20260616010738.2640782-2-sashal@kernel.org> + +From: Leon Romanovsky + +[ 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 +Stable-dep-of: 15fe76e23615 ("RDMA/umem: Fix truncation for block sizes >= 4G") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 ++#include ++ ++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 + #include + #include +-#include ++#include + + #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 + #include +-#include + #include + #include ++#include + + #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 + + #include +-#include + #include + #include ++#include + #include + + #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 + #include + #include "hns_roce_device.h" +-#include ++#include + + 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 + #include + #include +-#include + #include ++#include + #include + #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 + #include ++#include + + #include "mlx4_ib.h" + +--- a/drivers/infiniband/hw/mlx5/mem.c ++++ b/drivers/infiniband/hw/mlx5/mem.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include "mlx5_ib.h" + #include + +--- a/drivers/infiniband/hw/mlx5/mr.c ++++ b/drivers/infiniband/hw/mlx5/mr.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + #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 +-#include + #include ++#include + #include + + #include +--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c ++++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +@@ -44,9 +44,9 @@ + #include + #include + #include +-#include + #include + #include ++#include + #include + + #include "ocrdma.h" +--- a/drivers/infiniband/hw/qedr/verbs.c ++++ b/drivers/infiniband/hw/qedr/verbs.c +@@ -39,9 +39,9 @@ + #include + #include + #include +-#include + #include + #include ++#include + #include + + #include +--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h ++++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h +@@ -53,8 +53,8 @@ + #include + #include + #include +-#include + #include ++#include + #include + + #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 ++#include ++ ++/** ++ * 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 index 0000000000..5b3cd65959 --- /dev/null +++ b/queue-5.15/rdma-umem-fix-kernel-doc-warnings.patch @@ -0,0 +1,60 @@ +From stable+bounces-263504-greg=kroah.com@vger.kernel.org Tue Jun 16 06:37:44 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 21:07:36 -0400 +Subject: RDMA/umem: fix kernel-doc warnings +To: stable@vger.kernel.org +Cc: Randy Dunlap , Leon Romanovsky , Sasha Levin +Message-ID: <20260616010738.2640782-1-sashal@kernel.org> + +From: Randy Dunlap + +[ 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 +Link: https://patch.msgid.link/20260224003120.3173892-1-rdunlap@infradead.org +Signed-off-by: Leon Romanovsky +Stable-dep-of: 15fe76e23615 ("RDMA/umem: Fix truncation for block sizes >= 4G") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..5743240d8a --- /dev/null +++ b/queue-5.15/rdma-umem-fix-truncation-for-block-sizes-4g.patch @@ -0,0 +1,44 @@ +From stable+bounces-263505-greg=kroah.com@vger.kernel.org Tue Jun 16 06:37:44 2026 +From: Sasha Levin +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 , Sasha Levin +Message-ID: <20260616010738.2640782-3-sashal@kernel.org> + +From: Jason Gunthorpe + +[ 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 +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 70d91f1421..0000000000 --- a/queue-5.15/rxrpc-fix-conn-level-packet-handling-to-unshare-response-packets.patch +++ /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 -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 , Marc Dionne , Jeffrey Altman , Simon Horman , linux-afs@lists.infradead.org, stable@kernel.org, Jakub Kicinski , Sasha Levin -Message-ID: <20260503191416.1286222-1-sashal@kernel.org> - -From: David Howells - -[ 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 -cc: Marc Dionne -cc: Jeffrey Altman -cc: Simon Horman -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 -[ adapted callback signature to include `_abort_code` ] -Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman ---- - 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 index 0000000000..df30b3cc42 --- /dev/null +++ b/queue-5.15/scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch @@ -0,0 +1,203 @@ +From stable+bounces-260823-greg=kroah.com@vger.kernel.org Sat Jun 6 02:05:22 2026 +From: Sasha Levin +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 , John Garry , "Martin K. Petersen" , Sasha Levin +Message-ID: <20260605203405.2224281-1-sashal@kernel.org> + +From: Michael Bommarito + +[ 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 +Tested-by: John Garry +Reviewed-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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, ¶m_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 index 0000000000..5c1b57c05e --- /dev/null +++ b/queue-5.15/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch @@ -0,0 +1,124 @@ +From stable+bounces-260879-greg=kroah.com@vger.kernel.org Sat Jun 6 18:19:36 2026 +From: Sasha Levin +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 , John Garry , "Martin K. Petersen" , Sasha Levin +Message-ID: <20260606124928.2878279-1-sashal@kernel.org> + +From: Michael Bommarito + +[ 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 +Tested-by: John Garry +Reviewed-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..e5462d9965 --- /dev/null +++ b/queue-5.15/selftests-mptcp-drop-nanoseconds-width-specifier.patch @@ -0,0 +1,69 @@ +From stable+bounces-256912-greg=kroah.com@vger.kernel.org Sat May 30 20:11:19 2026 +From: Sasha Levin +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)" , Paolo Abeni , Sasha Levin +Message-ID: <20260530143734.2474733-1-sashal@kernel.org> + +From: "Matthieu Baerts (NGI0)" + +[ 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) +Link: https://patch.msgid.link/20260515-net-mptcp-misc-fixes-7-1-rc4-v2-6-701e96419f2f@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..92e7958de5 --- /dev/null +++ b/queue-5.15/serial-altera_jtaguart-handle-uart_add_one_port-failures.patch @@ -0,0 +1,59 @@ +From sashal@kernel.org Sat Jun 6 17:48:48 2026 +From: Sasha Levin +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 , stable , Ijae Kim , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260606121843.2850594-2-sashal@kernel.org> + +From: Myeonghun Pak + +[ 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 +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Signed-off-by: Myeonghun Pak +Link: https://patch.msgid.link/20260512065837.79528-1-mhun512@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..71cc7ef3ea --- /dev/null +++ b/queue-5.15/serial-altera_jtaguart-use-platform_get_irq_optional-to-get-the-interrupt.patch @@ -0,0 +1,59 @@ +From sashal@kernel.org Sat Jun 6 17:48:47 2026 +From: Sasha Levin +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 , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260606121843.2850594-1-sashal@kernel.org> + +From: Lad Prabhakar + +[ 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 +Link: https://lore.kernel.org/r/20211224142917.6966-7-prabhakar.mahadev-lad.rj@bp.renesas.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: ea66be25f0e9 ("serial: altera_jtaguart: handle uart_add_one_port() failures") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..6c8cebebd6 --- /dev/null +++ b/queue-5.15/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch @@ -0,0 +1,42 @@ +From sashal@kernel.org Sat Jun 6 17:48:58 2026 +From: Sasha Levin +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 , stable , Konrad Dybcio , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260606121854.2850880-3-sashal@kernel.org> + +From: Prasanna S + +[ 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 +Signed-off-by: Prasanna S +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260428-serial-bit-correct-v1-1-9131ad5b97d8@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..999a3bed2b --- /dev/null +++ b/queue-5.15/serial-samsung_tty-use-port-lock-wrappers.patch @@ -0,0 +1,236 @@ +From sashal@kernel.org Sat Jun 6 00:01:18 2026 +From: Sasha Levin +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 , John Ogness , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605183115.2054750-1-sashal@kernel.org> + +From: Thomas Gleixner + +[ 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 +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-54-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: a3bb136bff5e ("tty: serial: samsung: Remove redundant port lock acquisition in rx helpers") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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) diff --git a/queue-5.15/series b/queue-5.15/series index 8bccfa5c68..37f6671c6d 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -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 index 0000000000..f3ac22bd61 --- /dev/null +++ b/queue-5.15/smb-client-require-net-admin-for-cifs-swn-netlink.patch @@ -0,0 +1,62 @@ +From stable+bounces-256669-greg=kroah.com@vger.kernel.org Fri May 29 22:56:50 2026 +From: Sasha Levin +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 , Steve French , Sasha Levin +Message-ID: <20260529172153.1318415-2-sashal@kernel.org> + +From: Michael Bommarito + +[ 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 +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..e4560bf5db --- /dev/null +++ b/queue-5.15/smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch @@ -0,0 +1,158 @@ +From stable+bounces-249152-greg=kroah.com@vger.kernel.org Mon May 18 04:36:16 2026 +From: Sasha Levin +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 , Bharath SM , Piyush Sachdeva , Steve French , Sasha Levin +Message-ID: <20260517230532.410411-1-sashal@kernel.org> + +From: Piyush Sachdeva + +[ 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: +Reviewed-by: Bharath SM +Signed-off-by: Piyush Sachdeva +Signed-off-by: Piyush Sachdeva +Signed-off-by: Steve French +[ 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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..c346d7920e --- /dev/null +++ b/queue-5.15/smb-client-validate-dacloffset-before-building-dacl-pointers.patch @@ -0,0 +1,120 @@ +From stable+bounces-249027-greg=kroah.com@vger.kernel.org Sun May 17 00:39:15 2026 +From: Sasha Levin +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 , Steve French , Sasha Levin +Message-ID: <20260516190910.4016968-1-sashal@kernel.org> + +From: Michael Bommarito + +[ 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 +Signed-off-by: Steve French +[ 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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..332a8e06cf --- /dev/null +++ b/queue-5.15/smb-client-validate-the-whole-dacl-before-rewriting-it-in-cifsacl.patch @@ -0,0 +1,189 @@ +From 0a8cf165566ba55a39fd0f4de172119dd646d39a Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Sun, 19 Apr 2026 20:11:31 -0400 +Subject: smb: client: validate the whole DACL before rewriting it in cifsacl + +From: Michael Bommarito + +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 +Signed-off-by: Steve French +[ 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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..49c20bd92a --- /dev/null +++ b/queue-5.15/spi-lantiq-ssc-fix-controller-deregistration.patch @@ -0,0 +1,59 @@ +From stable+bounces-250012-greg=kroah.com@vger.kernel.org Wed May 20 21:28:28 2026 +From: Sasha Levin +Date: Wed, 20 May 2026 11:18:21 -0400 +Subject: spi: lantiq-ssc: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Hauke Mehrtens , Mark Brown , Sasha Levin +Message-ID: <20260520151821.3913367-1-sashal@kernel.org> + +From: Johan Hovold + +[ 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 +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260409120419.388546-17-johan@kernel.org +Signed-off-by: Mark Brown +[ adapted spi_controller/host naming to spi_master/master and preserved the int-returning remove() with trailing return 0 ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..f27740a291 --- /dev/null +++ b/queue-5.15/spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch @@ -0,0 +1,47 @@ +From stable+bounces-259405-greg=kroah.com@vger.kernel.org Mon Jun 1 07:23:23 2026 +From: Sasha Levin +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 , Mark Brown , Sasha Levin +Message-ID: <20260601015142.161971-2-sashal@kernel.org> + +From: Johan Hovold + +[ 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 +Link: https://patch.msgid.link/20260512074334.914735-1-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..be0b459e67 --- /dev/null +++ b/queue-5.15/spi-qup-switch-to-use-modern-name.patch @@ -0,0 +1,459 @@ +From stable+bounces-259406-greg=kroah.com@vger.kernel.org Mon Jun 1 07:23:36 2026 +From: Sasha Levin +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 , Mark Brown , Sasha Levin +Message-ID: <20260601015142.161971-1-sashal@kernel.org> + +From: Yang Yingliang + +[ Upstream commit 597442ff4f6226206b7cc28b86eb2be0ae9c6418 ] + +Change legacy name master to modern name host or controller. + +No functional changed. + +Signed-off-by: Yang Yingliang +Link: https://lore.kernel.org/r/20230818093154.1183529-10-yangyingliang@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: a7e8f3efd50a ("spi: qup: fix error pointer deref after DMA setup failure") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..2cdcda296d --- /dev/null +++ b/queue-5.15/spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch @@ -0,0 +1,76 @@ +From stable+bounces-247023-greg=kroah.com@vger.kernel.org Thu May 14 01:04:22 2026 +From: Sasha Levin +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" , "Mark Brown" , "Sasha Levin" +Message-ID: <20260513193414.3938310-1-sashal@kernel.org> + +From: Uwe Kleine-König + +[ 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 +Link: https://lore.kernel.org/r/20231105172649.3738556-2-u.kleine-koenig@pengutronix.de +Signed-off-by: Mark Brown +Stable-dep-of: 0c18a1bacbb1 ("spi: ti-qspi: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..72fc56b97a --- /dev/null +++ b/queue-5.15/spi-st-ssc4-fix-controller-deregistration.patch @@ -0,0 +1,56 @@ +From stable+bounces-249944-greg=kroah.com@vger.kernel.org Wed May 20 20:21:36 2026 +From: Sasha Levin +Date: Wed, 20 May 2026 10:27:57 -0400 +Subject: spi: st-ssc4: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Lee Jones , Mark Brown , Sasha Levin +Message-ID: <20260520142757.3647294-1-sashal@kernel.org> + +From: Johan Hovold + +[ 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 +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-18-johan@kernel.org +Signed-off-by: Mark Brown +[ changed spi_controller/host API calls to spi_master/master equivalents ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..4cb3a34e4b --- /dev/null +++ b/queue-5.15/spi-sun4i-fix-controller-deregistration.patch @@ -0,0 +1,56 @@ +From stable+bounces-247010-greg=kroah.com@vger.kernel.org Wed May 13 23:59:30 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 14:20:50 -0400 +Subject: spi: sun4i: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Maxime Ripard , Mark Brown , Sasha Levin +Message-ID: <20260513182050.3919910-1-sashal@kernel.org> + +From: Johan Hovold + +[ 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 +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-19-johan@kernel.org +Signed-off-by: Mark Brown +[ renamed `host`/`spi_controller` to `master`/`spi_master` and kept `int` return type with `return 0` in remove ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..74d15686bb --- /dev/null +++ b/queue-5.15/spi-sun6i-fix-controller-deregistration.patch @@ -0,0 +1,59 @@ +From stable+bounces-247096-greg=kroah.com@vger.kernel.org Thu May 14 09:44:22 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 00:14:12 -0400 +Subject: spi: sun6i: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Maxime Ripard , Mark Brown , Sasha Levin +Message-ID: <20260514041412.4189652-1-sashal@kernel.org> + +From: Johan Hovold + +[ 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 +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-20-johan@kernel.org +Signed-off-by: Mark Brown +[ renamed spi_controller APIs to spi_master equivalents and kept int return type for sun6i_spi_remove ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..888b6aafa0 --- /dev/null +++ b/queue-5.15/spi-syncuacer-fix-controller-deregistration.patch @@ -0,0 +1,56 @@ +From stable+bounces-247009-greg=kroah.com@vger.kernel.org Wed May 13 23:58:58 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 14:20:37 -0400 +Subject: spi: syncuacer: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Masahisa Kojima , Mark Brown , Sasha Levin +Message-ID: <20260513182037.3918900-1-sashal@kernel.org> + +From: Johan Hovold + +[ 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 +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-21-johan@kernel.org +Signed-off-by: Mark Brown +[ renamed spi_controller/host to spi_master/master and kept int return type with `return 0;` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..df1aa69c00 --- /dev/null +++ b/queue-5.15/spi-tegra114-fix-controller-deregistration.patch @@ -0,0 +1,59 @@ +From stable+bounces-247179-greg=kroah.com@vger.kernel.org Thu May 14 17:28:26 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 07:58:05 -0400 +Subject: spi: tegra114: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Jingoo Han , Mark Brown , Sasha Levin +Message-ID: <20260514115805.188807-1-sashal@kernel.org> + +From: Johan Hovold + +[ 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 +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-22-johan@kernel.org +Signed-off-by: Mark Brown +[ 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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..6620c97fe4 --- /dev/null +++ b/queue-5.15/spi-tegra20-sflash-fix-controller-deregistration.patch @@ -0,0 +1,58 @@ +From stable+bounces-247180-greg=kroah.com@vger.kernel.org Thu May 14 17:28:58 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 07:58:49 -0400 +Subject: spi: tegra20-sflash: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Jingoo Han , Mark Brown , Sasha Levin +Message-ID: <20260514115849.189593-1-sashal@kernel.org> + +From: Johan Hovold + +[ 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 +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-23-johan@kernel.org +Signed-off-by: Mark Brown +[ 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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..9b8aceedae --- /dev/null +++ b/queue-5.15/spi-ti-qspi-fix-controller-deregistration.patch @@ -0,0 +1,70 @@ +From stable+bounces-247029-greg=kroah.com@vger.kernel.org Thu May 14 01:05:04 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 15:34:14 -0400 +Subject: spi: ti-qspi: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Sebastian Andrzej Siewior , Mark Brown , Sasha Levin +Message-ID: <20260513193414.3938310-2-sashal@kernel.org> + +From: Johan Hovold + +[ 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 +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-24-johan@kernel.org +Signed-off-by: Mark Brown +[ renamed spi_controller_* API calls to legacy spi_master_* equivalents and qspi->host to qspi->master ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..2531a1b52b --- /dev/null +++ b/queue-5.15/spi-topcliff-pch-convert-to-platform-remove-callback-returning-void.patch @@ -0,0 +1,62 @@ +From stable+bounces-247738-greg=kroah.com@vger.kernel.org Fri May 15 18:06:53 2026 +From: Sasha Levin +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" , "Mark Brown" , "Sasha Levin" +Message-ID: <20260515121525.3130058-1-sashal@kernel.org> + +From: Uwe Kleine-König + +[ 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 +Link: https://lore.kernel.org/r/20230303172041.2103336-83-u.kleine-koenig@pengutronix.de +Signed-off-by: Mark Brown +Stable-dep-of: 5d6f477d6fc0 ("spi: topcliff-pch: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..736a0a8b53 --- /dev/null +++ b/queue-5.15/spi-topcliff-pch-fix-controller-deregistration.patch @@ -0,0 +1,48 @@ +From stable+bounces-247741-greg=kroah.com@vger.kernel.org Fri May 15 18:08:30 2026 +From: Sasha Levin +Date: Fri, 15 May 2026 08:15:25 -0400 +Subject: spi: topcliff-pch: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Masayuki Ohtake , Mark Brown , Sasha Levin +Message-ID: <20260515121525.3130058-2-sashal@kernel.org> + +From: Johan Hovold + +[ 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 +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260414134319.978196-8-johan@kernel.org +Signed-off-by: Mark Brown +[ renamed spi_controller_*(data->host) calls to spi_master_*(data->master) ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..806cb1f91a --- /dev/null +++ b/queue-5.15/spi-uniphier-fix-controller-deregistration.patch @@ -0,0 +1,63 @@ +From stable+bounces-247195-greg=kroah.com@vger.kernel.org Thu May 14 18:11:34 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 08:41:24 -0400 +Subject: spi: uniphier: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Keiji Hayashibara , Mark Brown , Sasha Levin +Message-ID: <20260514124124.212147-1-sashal@kernel.org> + +From: Johan Hovold + +[ 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 +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-25-johan@kernel.org +Signed-off-by: Mark Brown +[ 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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..6f2b8d62b6 --- /dev/null +++ b/queue-5.15/spi-zynq-qspi-fix-controller-deregistration.patch @@ -0,0 +1,78 @@ +From stable+bounces-247092-greg=kroah.com@vger.kernel.org Thu May 14 08:40:05 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 23:09:55 -0400 +Subject: spi: zynq-qspi: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Naga Sureshkumar Relli , Mark Brown , Sasha Levin +Message-ID: <20260514030955.4116823-1-sashal@kernel.org> + +From: Johan Hovold + +[ 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 +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-27-johan@kernel.org +Signed-off-by: Mark Brown +[ 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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..8362e3f9ca --- /dev/null +++ b/queue-5.15/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch @@ -0,0 +1,112 @@ +From stable+bounces-260822-greg=kroah.com@vger.kernel.org Sat Jun 6 02:04:15 2026 +From: Sasha Levin +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 , Mika Westerberg , Sasha Levin +Message-ID: <20260605203400.2224060-1-sashal@kernel.org> + +From: Michael Bommarito + +[ 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 +Signed-off-by: Mika Westerberg +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..cf37e7258a --- /dev/null +++ b/queue-5.15/tracing-probes-limit-size-of-event-probe-to-3k.patch @@ -0,0 +1,70 @@ +From stable+bounces-247823-greg=kroah.com@vger.kernel.org Fri May 15 20:52:22 2026 +From: Sasha Levin +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 , Mathieu Desnoyers , "Masami Hiramatsu (Google)" , Sasha Levin +Message-ID: <20260515152051.3277784-1-sashal@kernel.org> + +From: Steven Rostedt + +[ 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 +Acked-by: Masami Hiramatsu (Google) +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 +[ adjusted context for missing later-kernel infrastructure and used `goto out` instead of `goto fail` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..0a20779173 --- /dev/null +++ b/queue-5.15/tty-serial-qcom-geni-serial-align-define-values.patch @@ -0,0 +1,115 @@ +From stable+bounces-260865-greg=kroah.com@vger.kernel.org Sat Jun 6 17:49:55 2026 +From: Sasha Levin +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 , Konrad Dybcio , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260606121854.2850880-2-sashal@kernel.org> + +From: Bartosz Golaszewski + +[ Upstream commit 6cde11dbf4b65170eeefba48df730c93d75e01a3 ] + +Keep the #define symbols aligned for better readability. + +Signed-off-by: Bartosz Golaszewski +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20221229155030.418800-5-brgl@bgdev.pl +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: ca2584d841b6 ("serial: qcom-geni: fix UART_RX_PAR_EN bit position") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..c52d1b6488 --- /dev/null +++ b/queue-5.15/tty-serial-qcom-geni-serial-remove-unused-symbols.patch @@ -0,0 +1,73 @@ +From sashal@kernel.org Sat Jun 6 17:48:57 2026 +From: Sasha Levin +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 , Konrad Dybcio , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260606121854.2850880-1-sashal@kernel.org> + +From: Bartosz Golaszewski + +[ Upstream commit 68c6bd92c86cbc4937834c79963b27c77ee3bf51 ] + +Drop all unused symbols from the driver. + +Signed-off-by: Bartosz Golaszewski +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20221229155030.418800-4-brgl@bgdev.pl +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: ca2584d841b6 ("serial: qcom-geni: fix UART_RX_PAR_EN bit position") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..6b0c3e2c78 --- /dev/null +++ b/queue-5.15/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch @@ -0,0 +1,85 @@ +From sashal@kernel.org Sat Jun 6 00:01:20 2026 +From: Sasha Levin +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 , stable , John Ogness , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605183115.2054750-3-sashal@kernel.org> + +From: Tudor Ambarus + +[ 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 +Fixes: b497549a035c ("[ARM] S3C24XX: Split serial driver into core and per-cpu drivers") +Reported-by: John Ogness +Closes: https://sashiko.dev/#/patchset/20260506121606.5805-1-john.ogness%40linutronix.de [1] +Signed-off-by: Tudor Ambarus +Link: https://patch.msgid.link/20260515-samsung-tty-flow-control-deadlock-v1-1-93255edbc9bc@linaro.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..06433f8982 --- /dev/null +++ b/queue-5.15/tty-serial-samsung-use-u32-for-register-interactions.patch @@ -0,0 +1,216 @@ +From sashal@kernel.org Sat Jun 6 00:01:19 2026 +From: Sasha Levin +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 , Sam Protsenko , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605183115.2054750-2-sashal@kernel.org> + +From: Tudor Ambarus + +[ 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 +Signed-off-by: Tudor Ambarus +Link: https://lore.kernel.org/r/20240119104526.1221243-9-tudor.ambarus@linaro.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: a3bb136bff5e ("tty: serial: samsung: Remove redundant port lock acquisition in rx helpers") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..069cc42e97 --- /dev/null +++ b/queue-5.15/usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch @@ -0,0 +1,48 @@ +From stable+bounces-260693-greg=kroah.com@vger.kernel.org Fri Jun 5 18:35:53 2026 +From: Sasha Levin +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 , stable , sashiko-bot , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605130538.413416-1-sashal@kernel.org> + +From: Peter Chen + +[ 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 +Reported-by: sashiko-bot +Closes: https://lore.kernel.org/linux-devicetree/agKaEePSFknhDBg2@nchen-desktop/T/#m21e1d9c1574eb127ce03c0c2a1a49002ce435b52 +Signed-off-by: Peter Chen +Link: https://patch.msgid.link/20260513085310.2217547-2-peter.chen@cixtech.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..7afa8a64fb --- /dev/null +++ b/queue-5.15/usb-dwc3-move-guid-programming-after-phy-initialization.patch @@ -0,0 +1,63 @@ +From sashal@kernel.org Wed May 13 19:23:37 2026 +From: Sasha Levin +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 , stable , Pritam Manohar Sutar , Thinh Nguyen , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260513135334.3740565-1-sashal@kernel.org> + +From: Selvarasu Ganesan + +[ 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 +Reported-by: Pritam Manohar Sutar +Signed-off-by: Selvarasu Ganesan +Acked-by: Thinh Nguyen +Link: https://patch.msgid.link/20260417063314.2359-1-selvarasu.g@samsung.com +Signed-off-by: Greg Kroah-Hartman +[ adapted dwc3_writel(dwc, ...) to dwc3_writel(dwc->regs, ...) ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..797663a80b --- /dev/null +++ b/queue-5.15/usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch @@ -0,0 +1,84 @@ +From sashal@kernel.org Sat Jun 6 00:47:04 2026 +From: Sasha Levin +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 , Thinh Nguyen , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605191701.2128791-1-sashal@kernel.org> + +From: Radhey Shyam Pandey + +[ 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 +Signed-off-by: Radhey Shyam Pandey +Link: https://patch.msgid.link/20260519115529.2980421-1-radhey.shyam.pandey@amd.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..9f7a1aad27 --- /dev/null +++ b/queue-5.15/usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch @@ -0,0 +1,58 @@ +From sashal@kernel.org Sat Jun 6 01:08:30 2026 +From: Sasha Levin +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 , stable , Johan Hovold , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605193826.2169399-2-sashal@kernel.org> + +From: Guangshuo Li + +[ 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 +Reviewed-by: Johan Hovold +Signed-off-by: Guangshuo Li +Reviewed-by: Johan Hovold johan@kernel.org +Link: https://patch.msgid.link/20260413142119.2977716-1-lgs201920130244@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..9a5d706614 --- /dev/null +++ b/queue-5.15/usb-gadget-f_hid-tidy-error-handling-in-hidg_alloc.patch @@ -0,0 +1,87 @@ +From sashal@kernel.org Sat Jun 6 01:08:30 2026 +From: Sasha Levin +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 , Lee Jones , Andrzej Pietrasiewicz , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605193826.2169399-1-sashal@kernel.org> + +From: John Keeping + +[ 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 +Reviewed-by: Andrzej Pietrasiewicz +Reviewed-by: Lee Jones +Signed-off-by: John Keeping +Link: https://lore.kernel.org/r/20221122123523.3068034-4-john@metanate.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 4f88d65def6f ("usb: gadget: f_hid: fix device reference leak in hidg_alloc()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..5db92c1ea7 --- /dev/null +++ b/queue-5.15/usb-typec-tcpm-reset-internal-port-states-on-soft-reset-ams.patch @@ -0,0 +1,90 @@ +From sashal@kernel.org Wed May 13 18:18:29 2026 +From: Sasha Levin +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 , stable , Badhri Jagan Sridharan , Heikki Krogerus , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260513124826.3711905-1-sashal@kernel.org> + +From: Amit Sunil Dhamne + +[ 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 +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 +Reviewed-by: Badhri Jagan Sridharan +Acked-by: Heikki Krogerus +Link: https://patch.msgid.link/20260414-fix-soft-reset-v1-1-01d7cb9764e2@google.com +Signed-off-by: Greg Kroah-Hartman +[ kept `tcpm_pd_send_control(port, PD_CTRL_ACCEPT)` call unchanged ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..96b6dad3a1 --- /dev/null +++ b/queue-5.15/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch @@ -0,0 +1,69 @@ +From stable+bounces-260824-greg=kroah.com@vger.kernel.org Sat Jun 6 02:04:37 2026 +From: Sasha Levin +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 , stable , Sergey Senozhatsky , Heikki Krogerus , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605203410.2224712-1-sashal@kernel.org> + +From: Myrrh Periwinkle + +[ 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 +Fixes: 7616f006db07 ("usb: typec: ucsi: Update power_supply on power role change") +Signed-off-by: Myrrh Periwinkle +Reported-and-tested-by: Sergey Senozhatsky +Reviewed-by: Heikki Krogerus +Link: https://patch.msgid.link/20260519-ucsi-fix-2-v1-1-6f1239535187@qtmlabs.xyz +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..c19156759b --- /dev/null +++ b/queue-5.15/use-less-confusing-names-for-iov_iter-direction-initializers.patch @@ -0,0 +1,1624 @@ +From stable+bounces-256875-greg=kroah.com@vger.kernel.org Sat May 30 17:12:20 2026 +From: Sasha Levin +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 , Sasha Levin +Message-ID: <20260530114046.1945359-1-sashal@kernel.org> + +From: Al Viro + +[ 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 +Stable-dep-of: a4f0b001782b ("vsock/virtio: reset connection on receiving queue overflow") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..965d3bd324 --- /dev/null +++ b/queue-5.15/wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch @@ -0,0 +1,55 @@ +From stable+bounces-246852-greg=kroah.com@vger.kernel.org Wed May 13 18:53:15 2026 +From: Sasha Levin +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 , Arend van Spriel , Johannes Berg , Sasha Levin +Message-ID: <20260513131114.3723069-1-sashal@kernel.org> + +From: Marek Szyprowski + +[ 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 +Acked-by: Arend van Spriel +Link: https://patch.msgid.link/20260416093339.2066829-1-m.szyprowski@samsung.com +Signed-off-by: Johannes Berg +[ replaced kthread_stop_put() with open-coded kthread_stop() + put_task_struct() ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..713384b735 --- /dev/null +++ b/queue-5.15/xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch @@ -0,0 +1,132 @@ +From stable+bounces-246957-greg=kroah.com@vger.kernel.org Wed May 13 22:40:29 2026 +From: Sasha Levin +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 , Steffen Klassert , Sasha Levin +Message-ID: <20260513170942.3829179-3-sashal@kernel.org> + +From: Michael Bommarito + +[ 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 +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..3e9385235c --- /dev/null +++ b/queue-5.15/xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch @@ -0,0 +1,119 @@ +From stable+bounces-246976-greg=kroah.com@vger.kernel.org Wed May 13 23:25:23 2026 +From: Sasha Levin +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 , Steffen Klassert , Sasha Levin +Message-ID: <20260513174448.3896129-1-sashal@kernel.org> + +From: Michal Kosiorek + +[ 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 +Tested-by: Michal Kosiorek +Cc: stable@vger.kernel.org +Signed-off-by: Michal Kosiorek +Signed-off-by: Steffen Klassert +[ dropped state_cache/state_cache_input unhash hunks and xfrm_nat_keepalive_state_updated() call ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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); +