]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for all trees
authorSasha Levin <sashal@kernel.org>
Thu, 6 Aug 2026 11:35:00 +0000 (07:35 -0400)
committerSasha Levin <sashal@kernel.org>
Thu, 6 Aug 2026 11:35:00 +0000 (07:35 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
31 files changed:
queue-5.10/bluetooth-sco-fix-uaf-on-sco_sock_timeout.patch [new file with mode: 0644]
queue-5.10/bluetooth-sco-fix-use-after-free-in-sco_recv_frame-d.patch [new file with mode: 0644]
queue-5.10/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch [new file with mode: 0644]
queue-5.10/net-openvswitch-fix-skb-leak-on-flow-key-update-fail.patch [new file with mode: 0644]
queue-5.10/series
queue-5.15/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch [new file with mode: 0644]
queue-5.15/net-openvswitch-fix-skb-leak-on-flow-key-update-fail.patch [new file with mode: 0644]
queue-5.15/series
queue-6.1/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch [new file with mode: 0644]
queue-6.1/mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch [new file with mode: 0644]
queue-6.1/net-openvswitch-fix-skb-leak-on-flow-key-update-fail.patch [new file with mode: 0644]
queue-6.1/series
queue-6.12/fs-proc-task_mmu-fix-pagemap_scan-written-state-for-.patch [new file with mode: 0644]
queue-6.12/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch [new file with mode: 0644]
queue-6.12/mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch [new file with mode: 0644]
queue-6.12/series
queue-6.18/file-add-fd_-add-prepare.patch [new file with mode: 0644]
queue-6.18/file-ensure-cleanup.patch [new file with mode: 0644]
queue-6.18/fs-proc-task_mmu-fix-pagemap_scan-written-state-for-.patch [new file with mode: 0644]
queue-6.18/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch [new file with mode: 0644]
queue-6.18/mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch [new file with mode: 0644]
queue-6.18/net-handshake-close-the-submit-side-sock_hold-race.patch [new file with mode: 0644]
queue-6.18/net-handshake-convert-handshake_nl_accept_doit-to-fd.patch [new file with mode: 0644]
queue-6.18/net-handshake-drain-pending-requests-at-net-namespac.patch [new file with mode: 0644]
queue-6.18/net-handshake-fix-null-ptr-deref-in-handshake_comple.patch [new file with mode: 0644]
queue-6.18/net-handshake-hand-off-the-pinned-file-reference-to-.patch [new file with mode: 0644]
queue-6.18/net-handshake-take-a-long-lived-file-reference-at-su.patch [new file with mode: 0644]
queue-6.18/series
queue-6.6/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch [new file with mode: 0644]
queue-6.6/mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch [new file with mode: 0644]
queue-6.6/series

diff --git a/queue-5.10/bluetooth-sco-fix-uaf-on-sco_sock_timeout.patch b/queue-5.10/bluetooth-sco-fix-uaf-on-sco_sock_timeout.patch
new file mode 100644 (file)
index 0000000..db1d6ea
--- /dev/null
@@ -0,0 +1,124 @@
+From 8ae367233833ab99544779e7e33fd11b7d54dcff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 21:24:34 +0000
+Subject: Bluetooth: SCO: Fix UAF on sco_sock_timeout
+
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+
+commit 1bf4470a3939c678fb822073e9ea77a0560bc6bb upstream.
+
+conn->sk maybe have been unlinked/freed while waiting for sco_conn_lock
+so this checks if the conn->sk is still valid by checking if it part of
+sco_sk_list.
+
+Reported-by: syzbot+4c0d0c4cde787116d465@syzkaller.appspotmail.com
+Tested-by: syzbot+4c0d0c4cde787116d465@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=4c0d0c4cde787116d465
+Fixes: ba316be1b6a0 ("Bluetooth: schedule SCO timeouts with delayed_work")
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Xiangyu Chen <xiangyu.chen@windriver.com>
+Signed-off-by: He Zhe <zhe.he@windriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[ Resolved trivial conflicts in net/bluetooth/sco.c, removed
+extra reference on sk ]
+Signed-off-by: Todd Kjos <tkjos@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/bluetooth/bluetooth.h |  1 +
+ net/bluetooth/af_bluetooth.c      | 22 ++++++++++++++++++++++
+ net/bluetooth/sco.c               | 17 ++++++++++++-----
+ 3 files changed, 35 insertions(+), 5 deletions(-)
+
+diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
+index 43b4386018e26..85bab90a6921c 100644
+--- a/include/net/bluetooth/bluetooth.h
++++ b/include/net/bluetooth/bluetooth.h
+@@ -317,6 +317,7 @@ void bt_sock_link(struct bt_sock_list *l, struct sock *s);
+ void bt_sock_unlink(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);
++bool bt_sock_linked(struct bt_sock_list *l, struct sock *s);
+ 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,
+diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
+index b983ec52a99a1..16bea865e6d64 100644
+--- a/net/bluetooth/af_bluetooth.c
++++ b/net/bluetooth/af_bluetooth.c
+@@ -184,6 +184,28 @@ void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk)
+ }
+ EXPORT_SYMBOL(bt_sock_unlink);
++bool bt_sock_linked(struct bt_sock_list *l, struct sock *s)
++{
++      struct sock *sk;
++
++      if (!l || !s)
++              return false;
++
++      read_lock(&l->lock);
++
++      sk_for_each(sk, &l->head) {
++              if (s == sk) {
++                      read_unlock(&l->lock);
++                      return true;
++              }
++      }
++
++      read_unlock(&l->lock);
++
++      return false;
++}
++EXPORT_SYMBOL(bt_sock_linked);
++
+ void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh)
+ {
+       const struct cred *old_cred;
+diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
+index 01a01d6f01c30..2fbd9c93440ce 100644
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -76,6 +76,16 @@ struct sco_pinfo {
+ #define SCO_CONN_TIMEOUT      (HZ * 40)
+ #define SCO_DISCONN_TIMEOUT   (HZ * 2)
++static struct sock *sco_sock_hold(struct sco_conn *conn)
++{
++      if (!conn || !bt_sock_linked(&sco_sk_list, conn->sk))
++              return NULL;
++
++      sock_hold(conn->sk);
++
++      return conn->sk;
++}
++
+ static void sco_sock_timeout(struct work_struct *work)
+ {
+       struct sco_conn *conn = container_of(work, struct sco_conn,
+@@ -87,9 +97,7 @@ static void sco_sock_timeout(struct work_struct *work)
+               sco_conn_unlock(conn);
+               return;
+       }
+-      sk = conn->sk;
+-      if (sk)
+-              sock_hold(sk);
++      sk = sco_sock_hold(conn);
+       sco_conn_unlock(conn);
+       if (!sk)
+@@ -192,11 +200,10 @@ static void sco_conn_del(struct hci_conn *hcon, int err)
+       /* Kill socket */
+       sco_conn_lock(conn);
+-      sk = conn->sk;
++      sk = sco_sock_hold(conn);
+       sco_conn_unlock(conn);
+       if (sk) {
+-              sock_hold(sk);
+               bh_lock_sock(sk);
+               sco_sock_clear_timer(sk);
+               sco_chan_del(sk, err);
+-- 
+2.53.0
+
diff --git a/queue-5.10/bluetooth-sco-fix-use-after-free-in-sco_recv_frame-d.patch b/queue-5.10/bluetooth-sco-fix-use-after-free-in-sco_recv_frame-d.patch
new file mode 100644 (file)
index 0000000..a2c214e
--- /dev/null
@@ -0,0 +1,65 @@
+From ce001ea24bf3c889949f3b75fd27cc0525c901e6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 21:24:35 +0000
+Subject: Bluetooth: SCO: Fix use-after-free in sco_recv_frame() due to missing
+ sock_hold
+
+From: Hyunwoo Kim <imv4bel@gmail.com>
+
+[ Upstream commit 598dbba9919c5e36c54fe1709b557d64120cb94b ]
+
+sco_recv_frame() reads conn->sk under sco_conn_lock() but immediately
+releases the lock without holding a reference to the socket. A concurrent
+close() can free the socket between the lock release and the subsequent
+sk->sk_state access, resulting in a use-after-free.
+
+Other functions in the same file (sco_sock_timeout(), sco_conn_del())
+correctly use sco_sock_hold() to safely hold a reference under the lock.
+
+Fix by using sco_sock_hold() to take a reference before releasing the
+lock, and adding sock_put() on all exit paths.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Todd Kjos <tkjos@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/sco.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
+index 2fbd9c93440ce..b49b2d6bb778e 100644
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -312,7 +312,7 @@ static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
+       struct sock *sk;
+       sco_conn_lock(conn);
+-      sk = conn->sk;
++      sk = sco_sock_hold(conn);
+       sco_conn_unlock(conn);
+       if (!sk)
+@@ -321,11 +321,15 @@ static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
+       BT_DBG("sk %p len %d", sk, skb->len);
+       if (sk->sk_state != BT_CONNECTED)
+-              goto drop;
++              goto drop_put;
+-      if (!sock_queue_rcv_skb(sk, skb))
++      if (!sock_queue_rcv_skb(sk, skb)) {
++              sock_put(sk);
+               return;
++      }
++drop_put:
++      sock_put(sk);
+ drop:
+       kfree_skb(skb);
+ }
+-- 
+2.53.0
+
diff --git a/queue-5.10/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch b/queue-5.10/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
new file mode 100644 (file)
index 0000000..e939e26
--- /dev/null
@@ -0,0 +1,125 @@
+From 2e907dc7f60cb68b88bc912c6a0dea8c0a31ce9f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:45:07 +0100
+Subject: mm/huge_memory: unlock i_mmap_rwsem before releasing after-split
+ folios
+
+From: Kiryl Shutsemau (Meta) <kas@kernel.org>
+
+[ Upstream commit e923bd21058ea02fd0dcd3549d151d143fd036e5 ]
+
+__folio_split() keeps dereferencing the mapping after the split:
+shmem_uncharge(mapping->host) and remap_page() while the folios are still
+frozen/locked, and i_mmap_unlock_read(mapping) at the very end, after the
+after-split folios have been unlocked and freed.
+
+Nothing holds an inode reference across that.  The split relies on @folio
+-- which the beyond-EOF drop loop never removes, as it starts at
+folio_next(folio) -- staying locked and in the page cache to hold off
+eviction.  But the unlock loop unlocks @folio before i_mmap_unlock_read()
+runs.  If the caller's @lock_at is a tail beyond EOF, as memory_failure()
+passes when splitting a poisoned tail of a shmem THP that reaches past
+i_size during truncation, it too is gone from the page cache; so once
+@folio is unlocked no locked, in-cache folio pins the inode, and a
+concurrent final iput() can evict and RCU-free it before
+i_mmap_unlock_read() touches i_mmap_rwsem:
+
+  BUG: KASAN: slab-use-after-free in __up_read+0x634/0x790
+   i_mmap_unlock_read include/linux/fs.h:537 [inline]
+   __folio_split+0x732/0x1640 mm/huge_memory.c:4100
+   try_to_split_thp_page+0xab/0x390 mm/memory-failure.c:1675
+   memory_failure+0x1394/0x26e0 mm/memory-failure.c:2470
+
+  Freed by task 4601:
+   shmem_free_in_core_inode+0x54/0xb0 mm/shmem.c:5177
+   evict+0x57f/0xac0 fs/inode.c:870
+
+Do every mapping dereference while @folio still pins the inode: drop
+i_mmap_rwsem right after remap_page(), before the loop that unlocks and
+frees the after-split folios, and clear @mapping so the exit path does not
+unlock it again.  shmem_uncharge() and remap_page() already run before
+that point, so after this nothing past the unlock loop touches the inode
+or the mapping.
+
+This is now a rule the split depends on, alongside keeping @folio frozen
+until the page cache is updated: no inode or mapping dereference once the
+after-split folios start being unlocked.
+
+Link: https://lore.kernel.org/20260716095424.471052-1-kirill@shutemov.name
+Fixes: baa355fd3314 ("thp: file pages support for split_huge_page()")
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Reported-by: Hao Zhang <zhanghao1@kylinos.cn>
+Closes: https://lore.kernel.org/linux-mm/20260710071344.GA106129@zh-pc
+Co-developed-by: Hao Zhang <zhanghao1@kylinos.cn>
+Signed-off-by: Hao Zhang <zhanghao1@kylinos.cn>
+Acked-by: David Hildenbrand (Arm) <david@kernel.org>
+Reviewed-by: Zi Yan <ziy@nvidia.com>
+Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
+Reviewed-by: Miaohe Lin <linmiaohe@huawei.com>
+Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
+Cc: Barry Song <baohua@kernel.org>
+Cc: Dev Jain <dev.jain@arm.com>
+Cc: Lance Yang <lance.yang@linux.dev>
+Cc: Liam R. Howlett <liam@infradead.org>
+Cc: Lorenzo Stoakes <ljs@kernel.org>
+Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
+Cc: Nico Pache <npache@redhat.com>
+Cc: Ryan Roberts <ryan.roberts@arm.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+
+(cherry picked from commit e923bd21058ea02fd0dcd3549d151d143fd036e5)
+[ kas: adapt to the __split_huge_page()/split_huge_page_to_list()
+  two-function split: pass @mapping into __split_huge_page() and drop it
+  there, before the loop that frees the after-split subpages while the
+  head is still locked; the caller then skips its own i_mmap unlock ]
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/huge_memory.c | 16 ++++++++++++++--
+ 1 file changed, 14 insertions(+), 2 deletions(-)
+
+diff --git a/mm/huge_memory.c b/mm/huge_memory.c
+index fdcf89e3b1d27..f620861d00995 100644
+--- a/mm/huge_memory.c
++++ b/mm/huge_memory.c
+@@ -2445,7 +2445,7 @@ static void __split_huge_page_tail(struct page *head, int tail,
+ }
+ static void __split_huge_page(struct page *page, struct list_head *list,
+-              pgoff_t end, unsigned long flags)
++              pgoff_t end, unsigned long flags, struct address_space *mapping)
+ {
+       struct page *head = compound_head(page);
+       pg_data_t *pgdat = page_pgdat(head);
+@@ -2515,6 +2515,16 @@ static void __split_huge_page(struct page *page, struct list_head *list,
+               split_swap_cluster(entry);
+       }
++      /*
++       * Drop the mapping while the head page is still locked and thus pins
++       * the inode. The loop below may free the after-split subpages --
++       * including the head, when @page is a tail beyond EOF that the split
++       * dropped from the page cache -- which could otherwise let the inode,
++       * and @mapping, be freed before this unlock.
++       */
++      if (mapping)
++              i_mmap_unlock_read(mapping);
++
+       for (i = 0; i < nr; i++) {
+               struct page *subpage = head + i;
+               if (subpage == page)
+@@ -2746,7 +2756,9 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
+                               __dec_node_page_state(head, NR_FILE_THPS);
+               }
+-              __split_huge_page(page, list, end, flags);
++              __split_huge_page(page, list, end, flags, mapping);
++              /* __split_huge_page() dropped the i_mmap lock */
++              mapping = NULL;
+               ret = 0;
+       } else {
+               spin_unlock(&ds_queue->split_queue_lock);
+-- 
+2.53.0
+
diff --git a/queue-5.10/net-openvswitch-fix-skb-leak-on-flow-key-update-fail.patch b/queue-5.10/net-openvswitch-fix-skb-leak-on-flow-key-update-fail.patch
new file mode 100644 (file)
index 0000000..557b9fd
--- /dev/null
@@ -0,0 +1,65 @@
+From 04627e32c1d6329676730aaf81d8e9ce7f793b1b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 00:21:01 +0200
+Subject: net: openvswitch: fix skb leak on flow key update failure during
+ recirculation
+
+From: Ilya Maximets <i.maximets@ovn.org>
+
+[ Upstream commit e1cf066244dad576221b7123a0e5005967f25a20 ]
+
+do_execute_actions() returns right away when execute_recirc() fails on
+the last action as it assumes this function always takes ownership of
+the skb when 'last' is true.  But when the flow key update fails, the
+function doesn't free the skb and it ends up leaked.
+
+This is a very unlikely scenario as it requires the packet to become
+unparseable by applying a set of actions on a previously parseable skb,
+but should be fixed nevertheless.
+
+Reported by Sashiko.
+
+Fixes: 971427f353f3 ("openvswitch: Add recirc and hash action.")
+Cc: stable@vger.kernel.org
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+Reviewed-by: Aaron Conole <aconole@redhat.com>
+Link: https://patch.msgid.link/20260727181851.306076-2-i.maximets@ovn.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[OVS drop reasons are not available in 5.10, hence plain kfree_skb()]
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/actions.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
+index ffd56da14c745..99fff9d6596c8 100644
+--- a/net/openvswitch/actions.c
++++ b/net/openvswitch/actions.c
+@@ -1100,6 +1100,10 @@ static int execute_masked_set_action(struct sk_buff *skb,
+       return err;
+ }
++/* When 'last' is true, recirc() should always consume the 'skb'.
++ * Otherwise, recirc() should keep 'skb' intact regardless what
++ * actions are executed on recirculation.
++ */
+ static int execute_recirc(struct datapath *dp, struct sk_buff *skb,
+                         struct sw_flow_key *key,
+                         const struct nlattr *a, bool last)
+@@ -1110,8 +1114,11 @@ static int execute_recirc(struct datapath *dp, struct sk_buff *skb,
+               int err;
+               err = ovs_flow_key_update(skb, key);
+-              if (err)
++              if (err) {
++                      if (last)
++                              kfree_skb(skb);
+                       return err;
++              }
+       }
+       BUG_ON(!is_flow_key_valid(key));
+-- 
+2.53.0
+
index c75747cfae9942bcf26fe1fa837f59c6ff30ae6f..c2315769f4732598591e8cb1cbe0dddd52381bb6 100644 (file)
@@ -300,3 +300,7 @@ drm-amdgpu-cap-gtt-size-to-physical-ram-on-apus.patch
 drm-vmwgfx-validate-draw_primitives-header-size-before-division.patch
 drm-vmwgfx-bound-dma-command-body-size-against-suffix-pointer.patch
 hid-logitech-dj-fix-maxfield-check-in-dj-short-report-validation.patch
+mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
+bluetooth-sco-fix-uaf-on-sco_sock_timeout.patch
+bluetooth-sco-fix-use-after-free-in-sco_recv_frame-d.patch
+net-openvswitch-fix-skb-leak-on-flow-key-update-fail.patch
diff --git a/queue-5.15/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch b/queue-5.15/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
new file mode 100644 (file)
index 0000000..25466bc
--- /dev/null
@@ -0,0 +1,125 @@
+From a95a0d61d69266ff55ffb79e44797c7d0d65cfc4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:45:12 +0100
+Subject: mm/huge_memory: unlock i_mmap_rwsem before releasing after-split
+ folios
+
+From: Kiryl Shutsemau (Meta) <kas@kernel.org>
+
+[ Upstream commit e923bd21058ea02fd0dcd3549d151d143fd036e5 ]
+
+__folio_split() keeps dereferencing the mapping after the split:
+shmem_uncharge(mapping->host) and remap_page() while the folios are still
+frozen/locked, and i_mmap_unlock_read(mapping) at the very end, after the
+after-split folios have been unlocked and freed.
+
+Nothing holds an inode reference across that.  The split relies on @folio
+-- which the beyond-EOF drop loop never removes, as it starts at
+folio_next(folio) -- staying locked and in the page cache to hold off
+eviction.  But the unlock loop unlocks @folio before i_mmap_unlock_read()
+runs.  If the caller's @lock_at is a tail beyond EOF, as memory_failure()
+passes when splitting a poisoned tail of a shmem THP that reaches past
+i_size during truncation, it too is gone from the page cache; so once
+@folio is unlocked no locked, in-cache folio pins the inode, and a
+concurrent final iput() can evict and RCU-free it before
+i_mmap_unlock_read() touches i_mmap_rwsem:
+
+  BUG: KASAN: slab-use-after-free in __up_read+0x634/0x790
+   i_mmap_unlock_read include/linux/fs.h:537 [inline]
+   __folio_split+0x732/0x1640 mm/huge_memory.c:4100
+   try_to_split_thp_page+0xab/0x390 mm/memory-failure.c:1675
+   memory_failure+0x1394/0x26e0 mm/memory-failure.c:2470
+
+  Freed by task 4601:
+   shmem_free_in_core_inode+0x54/0xb0 mm/shmem.c:5177
+   evict+0x57f/0xac0 fs/inode.c:870
+
+Do every mapping dereference while @folio still pins the inode: drop
+i_mmap_rwsem right after remap_page(), before the loop that unlocks and
+frees the after-split folios, and clear @mapping so the exit path does not
+unlock it again.  shmem_uncharge() and remap_page() already run before
+that point, so after this nothing past the unlock loop touches the inode
+or the mapping.
+
+This is now a rule the split depends on, alongside keeping @folio frozen
+until the page cache is updated: no inode or mapping dereference once the
+after-split folios start being unlocked.
+
+Link: https://lore.kernel.org/20260716095424.471052-1-kirill@shutemov.name
+Fixes: baa355fd3314 ("thp: file pages support for split_huge_page()")
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Reported-by: Hao Zhang <zhanghao1@kylinos.cn>
+Closes: https://lore.kernel.org/linux-mm/20260710071344.GA106129@zh-pc
+Co-developed-by: Hao Zhang <zhanghao1@kylinos.cn>
+Signed-off-by: Hao Zhang <zhanghao1@kylinos.cn>
+Acked-by: David Hildenbrand (Arm) <david@kernel.org>
+Reviewed-by: Zi Yan <ziy@nvidia.com>
+Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
+Reviewed-by: Miaohe Lin <linmiaohe@huawei.com>
+Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
+Cc: Barry Song <baohua@kernel.org>
+Cc: Dev Jain <dev.jain@arm.com>
+Cc: Lance Yang <lance.yang@linux.dev>
+Cc: Liam R. Howlett <liam@infradead.org>
+Cc: Lorenzo Stoakes <ljs@kernel.org>
+Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
+Cc: Nico Pache <npache@redhat.com>
+Cc: Ryan Roberts <ryan.roberts@arm.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+
+(cherry picked from commit e923bd21058ea02fd0dcd3549d151d143fd036e5)
+[ kas: adapt to the __split_huge_page()/split_huge_page_to_list()
+  two-function split: pass @mapping into __split_huge_page() and drop it
+  there, before the loop that frees the after-split subpages while the
+  head is still locked; the caller then skips its own i_mmap unlock ]
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/huge_memory.c | 16 ++++++++++++++--
+ 1 file changed, 14 insertions(+), 2 deletions(-)
+
+diff --git a/mm/huge_memory.c b/mm/huge_memory.c
+index 934c08de74f42..94398e024d3a3 100644
+--- a/mm/huge_memory.c
++++ b/mm/huge_memory.c
+@@ -2403,7 +2403,7 @@ static void __split_huge_page_tail(struct page *head, int tail,
+ }
+ static void __split_huge_page(struct page *page, struct list_head *list,
+-              pgoff_t end)
++              pgoff_t end, struct address_space *mapping)
+ {
+       struct page *head = compound_head(page);
+       struct lruvec *lruvec;
+@@ -2476,6 +2476,16 @@ static void __split_huge_page(struct page *page, struct list_head *list,
+               split_swap_cluster(entry);
+       }
++      /*
++       * Drop the mapping while the head page is still locked and thus pins
++       * the inode. The loop below may free the after-split subpages --
++       * including the head, when @page is a tail beyond EOF that the split
++       * dropped from the page cache -- which could otherwise let the inode,
++       * and @mapping, be freed before this unlock.
++       */
++      if (mapping)
++              i_mmap_unlock_read(mapping);
++
+       for (i = 0; i < nr; i++) {
+               struct page *subpage = head + i;
+               if (subpage == page)
+@@ -2717,7 +2727,9 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
+                       }
+               }
+-              __split_huge_page(page, list, end);
++              __split_huge_page(page, list, end, mapping);
++              /* __split_huge_page() dropped the i_mmap lock */
++              mapping = NULL;
+               ret = 0;
+       } else {
+               spin_unlock(&ds_queue->split_queue_lock);
+-- 
+2.53.0
+
diff --git a/queue-5.15/net-openvswitch-fix-skb-leak-on-flow-key-update-fail.patch b/queue-5.15/net-openvswitch-fix-skb-leak-on-flow-key-update-fail.patch
new file mode 100644 (file)
index 0000000..94db0ba
--- /dev/null
@@ -0,0 +1,65 @@
+From 062bb2e0b8209517023291e58d6bd09078a5fa1d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 00:20:07 +0200
+Subject: net: openvswitch: fix skb leak on flow key update failure during
+ recirculation
+
+From: Ilya Maximets <i.maximets@ovn.org>
+
+[ Upstream commit e1cf066244dad576221b7123a0e5005967f25a20 ]
+
+do_execute_actions() returns right away when execute_recirc() fails on
+the last action as it assumes this function always takes ownership of
+the skb when 'last' is true.  But when the flow key update fails, the
+function doesn't free the skb and it ends up leaked.
+
+This is a very unlikely scenario as it requires the packet to become
+unparseable by applying a set of actions on a previously parseable skb,
+but should be fixed nevertheless.
+
+Reported by Sashiko.
+
+Fixes: 971427f353f3 ("openvswitch: Add recirc and hash action.")
+Cc: stable@vger.kernel.org
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+Reviewed-by: Aaron Conole <aconole@redhat.com>
+Link: https://patch.msgid.link/20260727181851.306076-2-i.maximets@ovn.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[OVS drop reasons are not available in 5.15, hence plain kfree_skb()]
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/actions.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
+index 3a69ed9d21926..6fd22d3632ba3 100644
+--- a/net/openvswitch/actions.c
++++ b/net/openvswitch/actions.c
+@@ -1107,6 +1107,10 @@ static int execute_masked_set_action(struct sk_buff *skb,
+       return err;
+ }
++/* When 'last' is true, recirc() should always consume the 'skb'.
++ * Otherwise, recirc() should keep 'skb' intact regardless what
++ * actions are executed on recirculation.
++ */
+ static int execute_recirc(struct datapath *dp, struct sk_buff *skb,
+                         struct sw_flow_key *key,
+                         const struct nlattr *a, bool last)
+@@ -1117,8 +1121,11 @@ static int execute_recirc(struct datapath *dp, struct sk_buff *skb,
+               int err;
+               err = ovs_flow_key_update(skb, key);
+-              if (err)
++              if (err) {
++                      if (last)
++                              kfree_skb(skb);
+                       return err;
++              }
+       }
+       BUG_ON(!is_flow_key_valid(key));
+-- 
+2.53.0
+
index a7a10458dc5d920ccdd3d1d281f24db9590f93ef..139cb65a17c38311d2a7dac5cd745b548b92bf60 100644 (file)
@@ -359,3 +359,5 @@ drm-amdgpu-cap-gtt-size-to-physical-ram-on-apus.patch
 drm-vmwgfx-validate-draw_primitives-header-size-before-division.patch
 drm-vmwgfx-bound-dma-command-body-size-against-suffix-pointer.patch
 hid-logitech-dj-fix-maxfield-check-in-dj-short-report-validation.patch
+mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
+net-openvswitch-fix-skb-leak-on-flow-key-update-fail.patch
diff --git a/queue-6.1/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch b/queue-6.1/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
new file mode 100644 (file)
index 0000000..1d36a3d
--- /dev/null
@@ -0,0 +1,125 @@
+From 0ce3e869cfb8e4c1f8133f2a6e0f3138b2af6c63 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:45:16 +0100
+Subject: mm/huge_memory: unlock i_mmap_rwsem before releasing after-split
+ folios
+
+From: Kiryl Shutsemau (Meta) <kas@kernel.org>
+
+[ Upstream commit e923bd21058ea02fd0dcd3549d151d143fd036e5 ]
+
+__folio_split() keeps dereferencing the mapping after the split:
+shmem_uncharge(mapping->host) and remap_page() while the folios are still
+frozen/locked, and i_mmap_unlock_read(mapping) at the very end, after the
+after-split folios have been unlocked and freed.
+
+Nothing holds an inode reference across that.  The split relies on @folio
+-- which the beyond-EOF drop loop never removes, as it starts at
+folio_next(folio) -- staying locked and in the page cache to hold off
+eviction.  But the unlock loop unlocks @folio before i_mmap_unlock_read()
+runs.  If the caller's @lock_at is a tail beyond EOF, as memory_failure()
+passes when splitting a poisoned tail of a shmem THP that reaches past
+i_size during truncation, it too is gone from the page cache; so once
+@folio is unlocked no locked, in-cache folio pins the inode, and a
+concurrent final iput() can evict and RCU-free it before
+i_mmap_unlock_read() touches i_mmap_rwsem:
+
+  BUG: KASAN: slab-use-after-free in __up_read+0x634/0x790
+   i_mmap_unlock_read include/linux/fs.h:537 [inline]
+   __folio_split+0x732/0x1640 mm/huge_memory.c:4100
+   try_to_split_thp_page+0xab/0x390 mm/memory-failure.c:1675
+   memory_failure+0x1394/0x26e0 mm/memory-failure.c:2470
+
+  Freed by task 4601:
+   shmem_free_in_core_inode+0x54/0xb0 mm/shmem.c:5177
+   evict+0x57f/0xac0 fs/inode.c:870
+
+Do every mapping dereference while @folio still pins the inode: drop
+i_mmap_rwsem right after remap_page(), before the loop that unlocks and
+frees the after-split folios, and clear @mapping so the exit path does not
+unlock it again.  shmem_uncharge() and remap_page() already run before
+that point, so after this nothing past the unlock loop touches the inode
+or the mapping.
+
+This is now a rule the split depends on, alongside keeping @folio frozen
+until the page cache is updated: no inode or mapping dereference once the
+after-split folios start being unlocked.
+
+Link: https://lore.kernel.org/20260716095424.471052-1-kirill@shutemov.name
+Fixes: baa355fd3314 ("thp: file pages support for split_huge_page()")
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Reported-by: Hao Zhang <zhanghao1@kylinos.cn>
+Closes: https://lore.kernel.org/linux-mm/20260710071344.GA106129@zh-pc
+Co-developed-by: Hao Zhang <zhanghao1@kylinos.cn>
+Signed-off-by: Hao Zhang <zhanghao1@kylinos.cn>
+Acked-by: David Hildenbrand (Arm) <david@kernel.org>
+Reviewed-by: Zi Yan <ziy@nvidia.com>
+Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
+Reviewed-by: Miaohe Lin <linmiaohe@huawei.com>
+Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
+Cc: Barry Song <baohua@kernel.org>
+Cc: Dev Jain <dev.jain@arm.com>
+Cc: Lance Yang <lance.yang@linux.dev>
+Cc: Liam R. Howlett <liam@infradead.org>
+Cc: Lorenzo Stoakes <ljs@kernel.org>
+Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
+Cc: Nico Pache <npache@redhat.com>
+Cc: Ryan Roberts <ryan.roberts@arm.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+
+(cherry picked from commit e923bd21058ea02fd0dcd3549d151d143fd036e5)
+[ kas: adapt to the __split_huge_page()/split_huge_page_to_list()
+  two-function split: pass @mapping into __split_huge_page() and drop it
+  there, before the loop that frees the after-split subpages while the
+  head is still locked; the caller then skips its own i_mmap unlock ]
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/huge_memory.c | 16 ++++++++++++++--
+ 1 file changed, 14 insertions(+), 2 deletions(-)
+
+diff --git a/mm/huge_memory.c b/mm/huge_memory.c
+index 7023bdf489605..153f06e42866c 100644
+--- a/mm/huge_memory.c
++++ b/mm/huge_memory.c
+@@ -2516,7 +2516,7 @@ static void __split_huge_page_tail(struct page *head, int tail,
+ }
+ static void __split_huge_page(struct page *page, struct list_head *list,
+-              pgoff_t end)
++              pgoff_t end, struct address_space *mapping)
+ {
+       struct folio *folio = page_folio(page);
+       struct page *head = &folio->page;
+@@ -2594,6 +2594,16 @@ static void __split_huge_page(struct page *page, struct list_head *list,
+               split_swap_cluster(entry);
+       }
++      /*
++       * Drop the mapping while the head page is still locked and thus pins
++       * the inode. The loop below may free the after-split subpages --
++       * including the head, when @page is a tail beyond EOF that the split
++       * dropped from the page cache -- which could otherwise let the inode,
++       * and @mapping, be freed before this unlock.
++       */
++      if (mapping)
++              i_mmap_unlock_read(mapping);
++
+       for (i = 0; i < nr; i++) {
+               struct page *subpage = head + i;
+               if (subpage == page)
+@@ -2774,7 +2784,9 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
+                       }
+               }
+-              __split_huge_page(page, list, end);
++              __split_huge_page(page, list, end, mapping);
++              /* __split_huge_page() dropped the i_mmap lock */
++              mapping = NULL;
+               ret = 0;
+       } else {
+               spin_unlock(&ds_queue->split_queue_lock);
+-- 
+2.53.0
+
diff --git a/queue-6.1/mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch b/queue-6.1/mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch
new file mode 100644 (file)
index 0000000..d296df0
--- /dev/null
@@ -0,0 +1,114 @@
+From 2e486744764f7d972f5f9db98fb69f207706ea73 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:43:30 +0100
+Subject: mm/hugetlb: fix swap entry corruption when clearing uffd-wp at fork()
+
+From: Kiryl Shutsemau (Meta) <kas@kernel.org>
+
+[ Upstream commit 83abe2fd5b3aeb3123b5408a5a91709c5538fb23 ]
+
+copy_hugetlb_page_range() clears the uffd-wp bit of migration and hwpoison
+entries with huge_pte_clear_uffd_wp(), which operates on the present-PTE
+bit position.  Swap entries keep the uffd-wp state elsewhere -- the
+migration branch reads and sets it with pte_swp_uffd_wp() and
+pte_swp_mkuffd_wp() -- and the present-PTE position falls into the swap
+payload.  On x86-64 it lands in the inverted swap offset, where a
+naturally-aligned hugetlb PFN always has the affected bit set, so the
+clear advances the encoded PFN by two pages.
+
+No userfaultfd needs to be involved: the clear is guarded only by the
+child VMA not being uffd-wp registered, so a plain fork() with an
+in-flight hugetlb migration entry (or a poisoned hugetlb page) corrupts
+the entry copied into the child.  Instrumenting the clear and forking
+after MADV_HWPOISON on a 2MB anon hugetlb page shows:
+
+  offset before=120e00
+  offset after =120e02
+
+The fallout is mostly latent: rmap walks match migration entries by folio
+range and remove_migration_pte() rebuilds the PTE from the folio, so a
+within-folio PFN skew heals once migration completes.  But any path that
+re-encodes the corrupted offset -- e.g.  hugetlb_change_protection()
+rewriting a writable migration entry via
+make_readable_migration_entry(swp_offset(entry)) -- propagates it.
+
+Migration entries legitimately carry uffd-wp, so clear it with
+pte_swp_clear_uffd_wp(), matching copy_nonpresent_pte() and
+move_huge_pte().
+
+A hwpoison entry, on the other hand, never carries the uffd-wp bit: it is
+installed fresh by make_hwpoison_entry() (try_to_unmap_one() does not
+preserve uffd-wp on the hwpoison path) and hugetlb_change_protection()
+leaves hwpoison entries untouched.  There was nothing to clear there, only
+the corruption, so drop the clear entirely.
+
+Link: https://lore.kernel.org/20260708090110.136162-1-kirill@shutemov.name
+Fixes: bc70fbf269fd ("mm/hugetlb: handle uffd-wp during fork()")
+Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
+Reported-by: Sashiko AI review <sashiko-bot@kernel.org>
+Closes: https://lore.kernel.org/all/20260703140011.99E601F000E9@smtp.kernel.org/
+Suggested-by: David Hildenbrand <david@kernel.org>
+Acked-by: David Hildenbrand (Arm) <david@kernel.org>
+Assisted-by: Claude:claude-fable-5
+Cc: Muchun Song <muchun.song@linux.dev>
+Cc: Oscar Salvador <osalvador@suse.de>
+Cc: Peter Xu <peterx@redhat.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+(cherry picked from commit 83abe2fd5b3aeb3123b5408a5a91709c5538fb23)
+[ kas: 6.1 predates the huge_pte_*uffd_wp() -> pte_swp_*uffd_wp()
+  conversion in copy_hugetlb_page_range() (commit 5a2f8d22ace4), so apply
+  the fix inline: convert the migration branch's uffd-wp read and set to
+  the swap-position helpers too, otherwise the src re-encode
+  (huge_pte_mkuffd_wp) corrupts the offset the same way; and drop the
+  hwpoison clear ]
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/hugetlb.c | 18 ++++++++++--------
+ 1 file changed, 10 insertions(+), 8 deletions(-)
+
+diff --git a/mm/hugetlb.c b/mm/hugetlb.c
+index c7683d00584fd..ffe5196b4afa6 100644
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -5106,14 +5106,16 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
+                        */
+                       ;
+               } else if (unlikely(is_hugetlb_entry_hwpoisoned(entry))) {
+-                      bool uffd_wp = huge_pte_uffd_wp(entry);
+-
+-                      if (!userfaultfd_wp(dst_vma) && uffd_wp)
+-                              entry = huge_pte_clear_uffd_wp(entry);
++                      /*
++                       * A hwpoison entry never carries the uffd-wp bit: it is
++                       * installed fresh by make_hwpoison_entry() and
++                       * hugetlb_change_protection() leaves it untouched, so
++                       * there is nothing to clear for the child.
++                       */
+                       set_huge_pte_at(dst, addr, dst_pte, entry);
+               } else if (unlikely(is_hugetlb_entry_migration(entry))) {
+                       swp_entry_t swp_entry = pte_to_swp_entry(entry);
+-                      bool uffd_wp = huge_pte_uffd_wp(entry);
++                      bool uffd_wp = pte_swp_uffd_wp(entry);
+                       if (!is_readable_migration_entry(swp_entry) && cow) {
+                               /*
+@@ -5124,11 +5126,11 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
+                                                       swp_offset(swp_entry));
+                               entry = swp_entry_to_pte(swp_entry);
+                               if (userfaultfd_wp(src_vma) && uffd_wp)
+-                                      entry = huge_pte_mkuffd_wp(entry);
++                                      entry = pte_swp_mkuffd_wp(entry);
+                               set_huge_pte_at(src, addr, src_pte, entry);
+                       }
+-                      if (!userfaultfd_wp(dst_vma) && uffd_wp)
+-                              entry = huge_pte_clear_uffd_wp(entry);
++                      if (!userfaultfd_wp(dst_vma))
++                              entry = pte_swp_clear_uffd_wp(entry);
+                       set_huge_pte_at(dst, addr, dst_pte, entry);
+               } else if (unlikely(is_pte_marker(entry))) {
+                       /*
+-- 
+2.53.0
+
diff --git a/queue-6.1/net-openvswitch-fix-skb-leak-on-flow-key-update-fail.patch b/queue-6.1/net-openvswitch-fix-skb-leak-on-flow-key-update-fail.patch
new file mode 100644 (file)
index 0000000..55b8ec7
--- /dev/null
@@ -0,0 +1,65 @@
+From bad565cef9e3e755e0b5724fc62aee47764a878f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 00:19:18 +0200
+Subject: net: openvswitch: fix skb leak on flow key update failure during
+ recirculation
+
+From: Ilya Maximets <i.maximets@ovn.org>
+
+[ Upstream commit e1cf066244dad576221b7123a0e5005967f25a20 ]
+
+do_execute_actions() returns right away when execute_recirc() fails on
+the last action as it assumes this function always takes ownership of
+the skb when 'last' is true.  But when the flow key update fails, the
+function doesn't free the skb and it ends up leaked.
+
+This is a very unlikely scenario as it requires the packet to become
+unparseable by applying a set of actions on a previously parseable skb,
+but should be fixed nevertheless.
+
+Reported by Sashiko.
+
+Fixes: 971427f353f3 ("openvswitch: Add recirc and hash action.")
+Cc: stable@vger.kernel.org
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+Reviewed-by: Aaron Conole <aconole@redhat.com>
+Link: https://patch.msgid.link/20260727181851.306076-2-i.maximets@ovn.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[OVS drop reasons are not available in 6.1, hence plain kfree_skb()]
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/openvswitch/actions.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
+index db4b6929d5bc5..679409953ac50 100644
+--- a/net/openvswitch/actions.c
++++ b/net/openvswitch/actions.c
+@@ -1107,6 +1107,10 @@ static int execute_masked_set_action(struct sk_buff *skb,
+       return err;
+ }
++/* When 'last' is true, recirc() should always consume the 'skb'.
++ * Otherwise, recirc() should keep 'skb' intact regardless what
++ * actions are executed on recirculation.
++ */
+ static int execute_recirc(struct datapath *dp, struct sk_buff *skb,
+                         struct sw_flow_key *key,
+                         const struct nlattr *a, bool last)
+@@ -1117,8 +1121,11 @@ static int execute_recirc(struct datapath *dp, struct sk_buff *skb,
+               int err;
+               err = ovs_flow_key_update(skb, key);
+-              if (err)
++              if (err) {
++                      if (last)
++                              kfree_skb(skb);
+                       return err;
++              }
+       }
+       BUG_ON(!is_flow_key_valid(key));
+-- 
+2.53.0
+
index e8150aa85bd505c5ba85ba9685de0680a515f805..2775ac515fb4625143440e434b0086fd2cd9fc1a 100644 (file)
@@ -475,3 +475,6 @@ drm-vmwgfx-bound-dma-command-body-size-against-suffix-pointer.patch
 hid-logitech-dj-fix-maxfield-check-in-dj-short-report-validation.patch
 ata-libahci_platform-do-not-set-mask_port_map-when-not-needed.patch
 ata-ahci-make-ahci_ignore_port-handle-empty-mask_port_map.patch
+mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch
+mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
+net-openvswitch-fix-skb-leak-on-flow-key-update-fail.patch
diff --git a/queue-6.12/fs-proc-task_mmu-fix-pagemap_scan-written-state-for-.patch b/queue-6.12/fs-proc-task_mmu-fix-pagemap_scan-written-state-for-.patch
new file mode 100644 (file)
index 0000000..8c0f59a
--- /dev/null
@@ -0,0 +1,89 @@
+From 486c83bce0b2e7e4b4be509134aa2fd91ad47952 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:43:49 +0100
+Subject: fs/proc/task_mmu: fix PAGEMAP_SCAN written state for unpopulated ptes
+
+From: Kiryl Shutsemau (Meta) <kas@kernel.org>
+
+[ Upstream commit 07b4377bdbe74a3ec0c8da5849d014f70e003384 ]
+
+PAGEMAP_SCAN reports an unpopulated pte differently depending on which
+path serves the request.  The PAGE_IS_WRITTEN fast path in
+pagemap_scan_pmd_entry() reports a pte_none as written (and, under
+PM_SCAN_WP_MATCHING, arms a marker); pagemap_page_category() returns 0 for
+the same pte_none.  A request that cannot take the fast path (an extra
+category bit, category_anyof_mask or category_inverted) therefore reports
+the pte as clean and skips arming it.
+
+A range that was populated and then MADV_DONTNEED'd reads as written via
+one mask and clean via another, and in the latter case is not re-armed for
+the next round -- an incremental-dump consumer (e.g.  CRIU) using a richer
+mask drops the zapped range and stops tracking writes to it.
+
+Report pte_none as written in pagemap_page_category() too.  A pte_none
+carries no uffd-wp marker, i.e.  it is not write-protected -- the same
+condition under which the present and swap cases already report
+PAGE_IS_WRITTEN.  The fast path applies no VMA test, so neither does this.
+
+The hugetlb and fully-unpopulated-PMD (no page table) scans have no
+PAGE_IS_WRITTEN fast path, so they do not exhibit the per-entry divergence
+and are left unchanged.
+
+Add a pagemap_ioctl selftest that populates a range, drops it with
+MADV_DONTNEED, and checks that the fast path and the generic
+(category_anyof_mask) path both report every page written.
+
+Link: https://lore.kernel.org/20260707151349.92143-1-kirill@shutemov.name
+Fixes: 12f6b01a0bcb ("fs/proc/task_mmu: add fast paths to get/clear PAGE_IS_WRITTEN flag")
+Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
+Cc: Muhammad Usama Anjum <usama.anjum@collabora.com>
+Cc: David Hildenbrand <david@kernel.org>
+Cc: Jann Horn <jannh@google.com>
+Cc: Liam R. Howlett <liam@infradead.org>
+Cc: Lorenzo Stoakes <ljs@kernel.org>
+Cc: Michal Hocko <mhocko@suse.com>
+Cc: Mike Rapoport <rppt@kernel.org>
+Cc: Pedro Falcato <pfalcato@suse.de>
+Cc: Peter Xu <peterx@redhat.com>
+Cc: Shuah Khan <shuah@kernel.org>
+Cc: Suren Baghdasaryan <surenb@google.com>
+Cc: Vlastimil Babka <vbabka@kernel.org>
+Assisted-by: Claude:claude-fable-5
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+(cherry picked from commit 07b4377bdbe74a3ec0c8da5849d014f70e003384)
+[ kas: fix only; selftest hunk dropped (pagemap_ioctl.c differs on this tree) ]
+
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/proc/task_mmu.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
+index a521f0faa0a49..44dc442b4f0e7 100644
+--- a/fs/proc/task_mmu.c
++++ b/fs/proc/task_mmu.c
+@@ -2097,6 +2097,19 @@ static unsigned long pagemap_page_category(struct pagemap_scan_private *p,
+ {
+       unsigned long categories = 0;
++      if (pte_none(pte)) {
++              /*
++               * An unpopulated pte carries no uffd-wp marker, i.e. it is not
++               * write-protected, the same condition under which the present
++               * and swap cases below report PAGE_IS_WRITTEN. Report it here
++               * too so this generic path agrees with the PAGE_IS_WRITTEN fast
++               * path in pagemap_scan_pmd_entry(), which reports pte_none as
++               * written and, under PM_SCAN_WP_MATCHING, arms a marker. The
++               * fast path applies no VMA test, so neither does this.
++               */
++              return PAGE_IS_WRITTEN;
++      }
++
+       if (pte_present(pte)) {
+               struct page *page;
+-- 
+2.53.0
+
diff --git a/queue-6.12/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch b/queue-6.12/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
new file mode 100644 (file)
index 0000000..67f26d9
--- /dev/null
@@ -0,0 +1,125 @@
+From 8d90b9228590d70236b730657e5d97713aea9ddc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:45:22 +0100
+Subject: mm/huge_memory: unlock i_mmap_rwsem before releasing after-split
+ folios
+
+From: Kiryl Shutsemau (Meta) <kas@kernel.org>
+
+[ Upstream commit e923bd21058ea02fd0dcd3549d151d143fd036e5 ]
+
+__folio_split() keeps dereferencing the mapping after the split:
+shmem_uncharge(mapping->host) and remap_page() while the folios are still
+frozen/locked, and i_mmap_unlock_read(mapping) at the very end, after the
+after-split folios have been unlocked and freed.
+
+Nothing holds an inode reference across that.  The split relies on @folio
+-- which the beyond-EOF drop loop never removes, as it starts at
+folio_next(folio) -- staying locked and in the page cache to hold off
+eviction.  But the unlock loop unlocks @folio before i_mmap_unlock_read()
+runs.  If the caller's @lock_at is a tail beyond EOF, as memory_failure()
+passes when splitting a poisoned tail of a shmem THP that reaches past
+i_size during truncation, it too is gone from the page cache; so once
+@folio is unlocked no locked, in-cache folio pins the inode, and a
+concurrent final iput() can evict and RCU-free it before
+i_mmap_unlock_read() touches i_mmap_rwsem:
+
+  BUG: KASAN: slab-use-after-free in __up_read+0x634/0x790
+   i_mmap_unlock_read include/linux/fs.h:537 [inline]
+   __folio_split+0x732/0x1640 mm/huge_memory.c:4100
+   try_to_split_thp_page+0xab/0x390 mm/memory-failure.c:1675
+   memory_failure+0x1394/0x26e0 mm/memory-failure.c:2470
+
+  Freed by task 4601:
+   shmem_free_in_core_inode+0x54/0xb0 mm/shmem.c:5177
+   evict+0x57f/0xac0 fs/inode.c:870
+
+Do every mapping dereference while @folio still pins the inode: drop
+i_mmap_rwsem right after remap_page(), before the loop that unlocks and
+frees the after-split folios, and clear @mapping so the exit path does not
+unlock it again.  shmem_uncharge() and remap_page() already run before
+that point, so after this nothing past the unlock loop touches the inode
+or the mapping.
+
+This is now a rule the split depends on, alongside keeping @folio frozen
+until the page cache is updated: no inode or mapping dereference once the
+after-split folios start being unlocked.
+
+Link: https://lore.kernel.org/20260716095424.471052-1-kirill@shutemov.name
+Fixes: baa355fd3314 ("thp: file pages support for split_huge_page()")
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Reported-by: Hao Zhang <zhanghao1@kylinos.cn>
+Closes: https://lore.kernel.org/linux-mm/20260710071344.GA106129@zh-pc
+Co-developed-by: Hao Zhang <zhanghao1@kylinos.cn>
+Signed-off-by: Hao Zhang <zhanghao1@kylinos.cn>
+Acked-by: David Hildenbrand (Arm) <david@kernel.org>
+Reviewed-by: Zi Yan <ziy@nvidia.com>
+Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
+Reviewed-by: Miaohe Lin <linmiaohe@huawei.com>
+Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
+Cc: Barry Song <baohua@kernel.org>
+Cc: Dev Jain <dev.jain@arm.com>
+Cc: Lance Yang <lance.yang@linux.dev>
+Cc: Liam R. Howlett <liam@infradead.org>
+Cc: Lorenzo Stoakes <ljs@kernel.org>
+Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
+Cc: Nico Pache <npache@redhat.com>
+Cc: Ryan Roberts <ryan.roberts@arm.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+
+(cherry picked from commit e923bd21058ea02fd0dcd3549d151d143fd036e5)
+[ kas: adapt to the __split_huge_page()/split_huge_page_to_list_to_order()
+  two-function split: pass @mapping into __split_huge_page() and drop it
+  there, before the loop that frees the after-split subpages while the
+  head is still locked; the caller then skips its own i_mmap unlock ]
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/huge_memory.c | 16 ++++++++++++++--
+ 1 file changed, 14 insertions(+), 2 deletions(-)
+
+diff --git a/mm/huge_memory.c b/mm/huge_memory.c
+index e60c21b924644..b2daa1767d900 100644
+--- a/mm/huge_memory.c
++++ b/mm/huge_memory.c
+@@ -3206,7 +3206,7 @@ static void __split_huge_page_tail(struct folio *folio, int tail,
+ }
+ static void __split_huge_page(struct page *page, struct list_head *list,
+-              pgoff_t end, unsigned int new_order)
++              pgoff_t end, unsigned int new_order, struct address_space *mapping)
+ {
+       struct folio *folio = page_folio(page);
+       /* Scan poisoned pages when split a poisoned folio to large folios */
+@@ -3303,6 +3303,16 @@ static void __split_huge_page(struct page *page, struct list_head *list,
+       if (new_order)
+               page = compound_head(page);
++      /*
++       * Drop the mapping while the head page is still locked and thus pins
++       * the inode. The loop below may free the after-split subpages --
++       * including the head, when @page is a tail beyond EOF that the split
++       * dropped from the page cache -- which could otherwise let the inode,
++       * and @mapping, be freed before this unlock.
++       */
++      if (mapping)
++              i_mmap_unlock_read(mapping);
++
+       for (i = 0; i < nr; i += new_nr) {
+               struct page *subpage = head + i;
+               struct folio *new_folio = page_folio(subpage);
+@@ -3580,7 +3590,9 @@ int split_huge_page_to_list_to_order(struct page *page, struct list_head *list,
+                       mod_mthp_stat(order, MTHP_STAT_NR_ANON, -1);
+                       mod_mthp_stat(new_order, MTHP_STAT_NR_ANON, 1 << (order - new_order));
+               }
+-              __split_huge_page(page, list, end, new_order);
++              __split_huge_page(page, list, end, new_order, mapping);
++              /* __split_huge_page() dropped the i_mmap lock */
++              mapping = NULL;
+               ret = 0;
+       } else {
+               spin_unlock(&ds_queue->split_queue_lock);
+-- 
+2.53.0
+
diff --git a/queue-6.12/mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch b/queue-6.12/mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch
new file mode 100644 (file)
index 0000000..0ab77d2
--- /dev/null
@@ -0,0 +1,96 @@
+From 9add7c1fec764f2d02a469ece9fc4b76408c6edd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:43:43 +0100
+Subject: mm/hugetlb: fix swap entry corruption when clearing uffd-wp at fork()
+
+From: Kiryl Shutsemau (Meta) <kas@kernel.org>
+
+[ Upstream commit 83abe2fd5b3aeb3123b5408a5a91709c5538fb23 ]
+
+copy_hugetlb_page_range() clears the uffd-wp bit of migration and hwpoison
+entries with huge_pte_clear_uffd_wp(), which operates on the present-PTE
+bit position.  Swap entries keep the uffd-wp state elsewhere -- the
+migration branch reads and sets it with pte_swp_uffd_wp() and
+pte_swp_mkuffd_wp() -- and the present-PTE position falls into the swap
+payload.  On x86-64 it lands in the inverted swap offset, where a
+naturally-aligned hugetlb PFN always has the affected bit set, so the
+clear advances the encoded PFN by two pages.
+
+No userfaultfd needs to be involved: the clear is guarded only by the
+child VMA not being uffd-wp registered, so a plain fork() with an
+in-flight hugetlb migration entry (or a poisoned hugetlb page) corrupts
+the entry copied into the child.  Instrumenting the clear and forking
+after MADV_HWPOISON on a 2MB anon hugetlb page shows:
+
+  offset before=120e00
+  offset after =120e02
+
+The fallout is mostly latent: rmap walks match migration entries by folio
+range and remove_migration_pte() rebuilds the PTE from the folio, so a
+within-folio PFN skew heals once migration completes.  But any path that
+re-encodes the corrupted offset -- e.g.  hugetlb_change_protection()
+rewriting a writable migration entry via
+make_readable_migration_entry(swp_offset(entry)) -- propagates it.
+
+Migration entries legitimately carry uffd-wp, so clear it with
+pte_swp_clear_uffd_wp(), matching copy_nonpresent_pte() and
+move_huge_pte().
+
+A hwpoison entry, on the other hand, never carries the uffd-wp bit: it is
+installed fresh by make_hwpoison_entry() (try_to_unmap_one() does not
+preserve uffd-wp on the hwpoison path) and hugetlb_change_protection()
+leaves hwpoison entries untouched.  There was nothing to clear there, only
+the corruption, so drop the clear entirely.
+
+Link: https://lore.kernel.org/20260708090110.136162-1-kirill@shutemov.name
+Fixes: bc70fbf269fd ("mm/hugetlb: handle uffd-wp during fork()")
+Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
+Reported-by: Sashiko AI review <sashiko-bot@kernel.org>
+Closes: https://lore.kernel.org/all/20260703140011.99E601F000E9@smtp.kernel.org/
+Suggested-by: David Hildenbrand <david@kernel.org>
+Acked-by: David Hildenbrand (Arm) <david@kernel.org>
+Assisted-by: Claude:claude-fable-5
+Cc: Muchun Song <muchun.song@linux.dev>
+Cc: Oscar Salvador <osalvador@suse.de>
+Cc: Peter Xu <peterx@redhat.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+(cherry picked from commit 83abe2fd5b3aeb3123b5408a5a91709c5538fb23)
+[ kas: adapt to the pre-softleaf idiom ]
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/hugetlb.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/mm/hugetlb.c b/mm/hugetlb.c
+index 2fb6e45a1ea0d..e910ed0c43d0b 100644
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -5281,8 +5281,12 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
+                        */
+                       ;
+               } else if (unlikely(is_hugetlb_entry_hwpoisoned(entry))) {
+-                      if (!userfaultfd_wp(dst_vma))
+-                              entry = huge_pte_clear_uffd_wp(entry);
++                      /*
++                       * A hwpoison entry never carries the uffd-wp bit: it is
++                       * installed fresh by make_hwpoison_entry() and
++                       * hugetlb_change_protection() leaves it untouched, so
++                       * there is nothing to clear for the child.
++                       */
+                       set_huge_pte_at(dst, addr, dst_pte, entry, sz);
+               } else if (unlikely(is_hugetlb_entry_migration(entry))) {
+                       swp_entry_t swp_entry = pte_to_swp_entry(entry);
+@@ -5301,7 +5305,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
+                               set_huge_pte_at(src, addr, src_pte, entry, sz);
+                       }
+                       if (!userfaultfd_wp(dst_vma))
+-                              entry = huge_pte_clear_uffd_wp(entry);
++                              entry = pte_swp_clear_uffd_wp(entry);
+                       set_huge_pte_at(dst, addr, dst_pte, entry, sz);
+               } else if (unlikely(is_pte_marker(entry))) {
+                       pte_marker marker = copy_pte_marker(
+-- 
+2.53.0
+
index 84862f6fdbff8a5382bf00ad2cbc473ce3f27c3f..33c246585439dfb76b356710cdd5d6ea5586630a 100644 (file)
@@ -283,3 +283,6 @@ drm-xe-rtp-toggle-deny-bit-to-de-whitelist-oa-regs.patch
 drm-xe-rtp-de-whitelist-oa-registers-for-all-hwe-s-f.patch
 drm-xe-oa-de-whitelist-oa-registers-on-oa-stream-ope.patch
 drm-xe-rtp-ensure-locking-ref-counting-for-oa-whitel.patch
+mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch
+fs-proc-task_mmu-fix-pagemap_scan-written-state-for-.patch
+mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
diff --git a/queue-6.18/file-add-fd_-add-prepare.patch b/queue-6.18/file-add-fd_-add-prepare.patch
new file mode 100644 (file)
index 0000000..bac12ee
--- /dev/null
@@ -0,0 +1,234 @@
+From e5f42b8df94634180b4fd5dc4ae634c984f03cca Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 01:39:52 +0800
+Subject: file: add FD_{ADD,PREPARE}()
+
+From: Christian Brauner <brauner@kernel.org>
+
+[ Upstream commit 011703a9acd76edc7c85d80dbccb6e50dba53aad ]
+
+I've been playing with this to allow for moderately flexible usage of
+the get_unused_fd_flags() + create file + fd_install() pattern that's
+used quite extensively.
+
+How callers allocate files is really heterogenous so it's not really
+convenient to fold them into a single class. It's possibe to split them
+into subclasses like for anon inodes. I think that's not necessarily
+nice as well.
+
+My take is to add two primites:
+(1) FD_ADD() the simple cases a file is installed:
+
+    fd = FD_ADD(O_CLOEXEC, open_file(some, args)));
+    if (fd >= 0)
+            kvm_get_kvm(vcpu->kvm);
+    return fd;
+
+(2) FD_PREPARE() that captures all the cases where access to fd or file
+    or additional work before publishing the fd is needed:
+
+    FD_PREPARE(fdf, open_flag, file_open_handle(&path, open_flag));
+    if (fdf.err)
+            return fdf.err;
+
+    if (copy_to_user(/* something something */))
+            return -EFAULT;
+
+    return fd_publish(fdf);
+
+I've converted all of the easy cases over to it and it gets rid of an
+aweful lot of convoluted cleanup logic.
+
+It's centered around struct fd_prepare. FD_PREPARE() encapsulates all of
+allocation and cleanup logic and must be followed by a call to
+fd_publish() which associates the fd with the file and installs it into
+the callers fdtable. If fd_publish() isn't called both are deallocated.
+
+It mandates a specific order namely that first we allocate the fd and
+then instantiate the file. But that shouldn't be a problem nearly
+everyone I've converted uses this exact pattern anyway.
+
+There's a bunch of additional cases where it would be easy to convert
+them to this pattern. For example, the whole sync file stuff in dma
+currently retains the containing structure of the file instead of the
+file itself even though it's only used to allocate files. Changing that
+would make it fall into the FD_PREPARE() pattern easily. I've not done
+that work yet.
+
+There's room for extending this in a way that wed'd have subclasses for
+some particularly often use patterns but as I said I'm not even sure
+that's worth it.
+
+Link: https://patch.msgid.link/20251123-work-fd-prepare-v4-1-b6efa1706cfd@kernel.org
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+(cherry picked from commit 011703a9acd76edc7c85d80dbccb6e50dba53aad)
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/cleanup.h |   7 +++
+ include/linux/file.h    | 126 ++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 133 insertions(+)
+
+diff --git a/include/linux/cleanup.h b/include/linux/cleanup.h
+index a1194e44b5276..bacefa0f1512f 100644
+--- a/include/linux/cleanup.h
++++ b/include/linux/cleanup.h
+@@ -261,6 +261,10 @@ const volatile void * __must_check_fn(const volatile void *val)
+  * CLASS(name, var)(args...):
+  *    declare the variable @var as an instance of the named class
+  *
++ * CLASS_INIT(name, var, init_expr):
++ *    declare the variable @var as an instance of the named class with
++ *    custom initialization expression.
++ *
+  * Ex.
+  *
+  * DEFINE_CLASS(fdget, struct fd, fdput(_T), fdget(fd), int fd)
+@@ -290,6 +294,9 @@ static inline class_##_name##_t class_##_name##ext##_constructor(_init_args) \
+       class_##_name##_t var __cleanup(class_##_name##_destructor) =   \
+               class_##_name##_constructor
++#define CLASS_INIT(_name, _var, _init_expr)                             \
++        class_##_name##_t _var __cleanup(class_##_name##_destructor) = (_init_expr)
++
+ #define __scoped_class(_name, var, _label, args...)        \
+       for (CLASS(_name, var)(args); ; ({ goto _label; })) \
+               if (0) {                                   \
+diff --git a/include/linux/file.h b/include/linux/file.h
+index af1768d934a01..cf389fde9bc28 100644
+--- a/include/linux/file.h
++++ b/include/linux/file.h
+@@ -127,4 +127,130 @@ extern void __fput_sync(struct file *);
+ extern unsigned int sysctl_nr_open_min, sysctl_nr_open_max;
++/*
++ * fd_prepare: Combined fd + file allocation cleanup class.
++ * @err: Error code to indicate if allocation succeeded.
++ * @__fd: Allocated fd (may not be accessed directly)
++ * @__file: Allocated struct file pointer (may not be accessed directly)
++ *
++ * Allocates an fd and a file together. On error paths, automatically cleans
++ * up whichever resource was successfully allocated. Allows flexible file
++ * allocation with different functions per usage.
++ *
++ * Do not use directly.
++ */
++struct fd_prepare {
++      s32 err;
++      s32 __fd; /* do not access directly */
++      struct file *__file; /* do not access directly */
++};
++
++/* Typedef for fd_prepare cleanup guards. */
++typedef struct fd_prepare class_fd_prepare_t;
++
++/*
++ * Accessors for fd_prepare class members.
++ * _Generic() is used for zero-cost type safety.
++ */
++#define fd_prepare_fd(_fdf) \
++      (_Generic((_fdf), struct fd_prepare: (_fdf).__fd))
++
++#define fd_prepare_file(_fdf) \
++      (_Generic((_fdf), struct fd_prepare: (_fdf).__file))
++
++/* Do not use directly. */
++static inline void class_fd_prepare_destructor(const struct fd_prepare *fdf)
++{
++      if (unlikely(fdf->err)) {
++              if (likely(fdf->__fd >= 0))
++                      put_unused_fd(fdf->__fd);
++              if (unlikely(!IS_ERR_OR_NULL(fdf->__file)))
++                      fput(fdf->__file);
++      }
++}
++
++/* Do not use directly. */
++static inline int class_fd_prepare_lock_err(const struct fd_prepare *fdf)
++{
++      if (unlikely(fdf->err))
++              return fdf->err;
++      if (unlikely(fdf->__fd < 0))
++              return fdf->__fd;
++      if (unlikely(IS_ERR(fdf->__file)))
++              return PTR_ERR(fdf->__file);
++      if (unlikely(!fdf->__file))
++              return -ENOMEM;
++      return 0;
++}
++
++/*
++ * __FD_PREPARE_INIT - Helper to initialize fd_prepare class.
++ * @_fd_flags: flags for get_unused_fd_flags()
++ * @_file_owned: expression that returns struct file *
++ *
++ * Returns a struct fd_prepare with fd, file, and err set.
++ * If fd allocation fails, fd will be negative and err will be set. If
++ * fd succeeds but file_init_expr fails, file will be ERR_PTR and err
++ * will be set. The err field is the single source of truth for error
++ * checking.
++ */
++#define __FD_PREPARE_INIT(_fd_flags, _file_owned)                 \
++      ({                                                        \
++              struct fd_prepare fdf = {                         \
++                      .__fd = get_unused_fd_flags((_fd_flags)), \
++              };                                                \
++              if (likely(fdf.__fd >= 0))                        \
++                      fdf.__file = (_file_owned);               \
++              fdf.err = ACQUIRE_ERR(fd_prepare, &fdf);          \
++              fdf;                                              \
++      })
++
++/*
++ * FD_PREPARE - Macro to declare and initialize an fd_prepare variable.
++ *
++ * Declares and initializes an fd_prepare variable with automatic
++ * cleanup. No separate scope required - cleanup happens when variable
++ * goes out of scope.
++ *
++ * @_fdf: name of struct fd_prepare variable to define
++ * @_fd_flags: flags for get_unused_fd_flags()
++ * @_file_owned: struct file to take ownership of (can be expression)
++ */
++#define FD_PREPARE(_fdf, _fd_flags, _file_owned) \
++      CLASS_INIT(fd_prepare, _fdf, __FD_PREPARE_INIT(_fd_flags, _file_owned))
++
++/*
++ * fd_publish - Publish prepared fd and file to the fd table.
++ * @_fdf: struct fd_prepare variable
++ */
++#define fd_publish(_fdf)                                       \
++      ({                                                     \
++              struct fd_prepare *fdp = &(_fdf);              \
++              VFS_WARN_ON_ONCE(fdp->err);                    \
++              VFS_WARN_ON_ONCE(fdp->__fd < 0);               \
++              VFS_WARN_ON_ONCE(IS_ERR_OR_NULL(fdp->__file)); \
++              fd_install(fdp->__fd, fdp->__file);            \
++              fdp->__fd;                                     \
++      })
++
++/* Do not use directly. */
++#define __FD_ADD(_fdf, _fd_flags, _file_owned)            \
++      ({                                                \
++              FD_PREPARE(_fdf, _fd_flags, _file_owned); \
++              s32 ret = _fdf.err;                       \
++              if (likely(!ret))                         \
++                      ret = fd_publish(_fdf);           \
++              ret;                                      \
++      })
++
++/*
++ * FD_ADD - Allocate and install an fd and file in one step.
++ * @_fd_flags: flags for get_unused_fd_flags()
++ * @_file_owned: struct file to take ownership of
++ *
++ * Returns the allocated fd number, or negative error code on failure.
++ */
++#define FD_ADD(_fd_flags, _file_owned) \
++      __FD_ADD(__UNIQUE_ID(fd_prepare), _fd_flags, _file_owned)
++
+ #endif /* __LINUX_FILE_H */
+-- 
+2.53.0
+
diff --git a/queue-6.18/file-ensure-cleanup.patch b/queue-6.18/file-ensure-cleanup.patch
new file mode 100644 (file)
index 0000000..1e981a6
--- /dev/null
@@ -0,0 +1,61 @@
+From 32def2a8a0e486faf15c5ef99561fbfd944d631f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 01:39:54 +0800
+Subject: file: ensure cleanup
+
+From: Christian Brauner <brauner@kernel.org>
+
+[ Upstream commit d2ea4d254d04a89e17504af0230c7268e3cac6bf ]
+
+Brown paper bag time. This is a silly oversight where I missed to drop
+the error condition checking to ensure we clean up on early error
+returns. I have an internal unit testset coming up for this which will
+catch all such issues going forward.
+
+Reported-by: Chris Mason <clm@fb.com>
+Reported-by: Jeff Layton <jlayton@kernel.org>
+Fixes: 011703a9acd7 ("file: add FD_{ADD,PREPARE}()")
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+(cherry picked from commit d2ea4d254d04a89e17504af0230c7268e3cac6bf)
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/file.h | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+diff --git a/include/linux/file.h b/include/linux/file.h
+index cf389fde9bc28..27484b444d315 100644
+--- a/include/linux/file.h
++++ b/include/linux/file.h
+@@ -161,12 +161,10 @@ typedef struct fd_prepare class_fd_prepare_t;
+ /* Do not use directly. */
+ static inline void class_fd_prepare_destructor(const struct fd_prepare *fdf)
+ {
+-      if (unlikely(fdf->err)) {
+-              if (likely(fdf->__fd >= 0))
+-                      put_unused_fd(fdf->__fd);
+-              if (unlikely(!IS_ERR_OR_NULL(fdf->__file)))
+-                      fput(fdf->__file);
+-      }
++      if (unlikely(fdf->__fd >= 0))
++              put_unused_fd(fdf->__fd);
++      if (unlikely(!IS_ERR_OR_NULL(fdf->__file)))
++              fput(fdf->__file);
+ }
+ /* Do not use directly. */
+@@ -230,7 +228,8 @@ static inline int class_fd_prepare_lock_err(const struct fd_prepare *fdf)
+               VFS_WARN_ON_ONCE(fdp->__fd < 0);               \
+               VFS_WARN_ON_ONCE(IS_ERR_OR_NULL(fdp->__file)); \
+               fd_install(fdp->__fd, fdp->__file);            \
+-              fdp->__fd;                                     \
++              retain_and_null_ptr(fdp->__file);              \
++              take_fd(fdp->__fd);                            \
+       })
+ /* Do not use directly. */
+-- 
+2.53.0
+
diff --git a/queue-6.18/fs-proc-task_mmu-fix-pagemap_scan-written-state-for-.patch b/queue-6.18/fs-proc-task_mmu-fix-pagemap_scan-written-state-for-.patch
new file mode 100644 (file)
index 0000000..7c3dd38
--- /dev/null
@@ -0,0 +1,89 @@
+From b00f0ed2dd3731ff3df4a0dc787009696f55346a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:43:52 +0100
+Subject: fs/proc/task_mmu: fix PAGEMAP_SCAN written state for unpopulated ptes
+
+From: Kiryl Shutsemau (Meta) <kas@kernel.org>
+
+[ Upstream commit 07b4377bdbe74a3ec0c8da5849d014f70e003384 ]
+
+PAGEMAP_SCAN reports an unpopulated pte differently depending on which
+path serves the request.  The PAGE_IS_WRITTEN fast path in
+pagemap_scan_pmd_entry() reports a pte_none as written (and, under
+PM_SCAN_WP_MATCHING, arms a marker); pagemap_page_category() returns 0 for
+the same pte_none.  A request that cannot take the fast path (an extra
+category bit, category_anyof_mask or category_inverted) therefore reports
+the pte as clean and skips arming it.
+
+A range that was populated and then MADV_DONTNEED'd reads as written via
+one mask and clean via another, and in the latter case is not re-armed for
+the next round -- an incremental-dump consumer (e.g.  CRIU) using a richer
+mask drops the zapped range and stops tracking writes to it.
+
+Report pte_none as written in pagemap_page_category() too.  A pte_none
+carries no uffd-wp marker, i.e.  it is not write-protected -- the same
+condition under which the present and swap cases already report
+PAGE_IS_WRITTEN.  The fast path applies no VMA test, so neither does this.
+
+The hugetlb and fully-unpopulated-PMD (no page table) scans have no
+PAGE_IS_WRITTEN fast path, so they do not exhibit the per-entry divergence
+and are left unchanged.
+
+Add a pagemap_ioctl selftest that populates a range, drops it with
+MADV_DONTNEED, and checks that the fast path and the generic
+(category_anyof_mask) path both report every page written.
+
+Link: https://lore.kernel.org/20260707151349.92143-1-kirill@shutemov.name
+Fixes: 12f6b01a0bcb ("fs/proc/task_mmu: add fast paths to get/clear PAGE_IS_WRITTEN flag")
+Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
+Cc: Muhammad Usama Anjum <usama.anjum@collabora.com>
+Cc: David Hildenbrand <david@kernel.org>
+Cc: Jann Horn <jannh@google.com>
+Cc: Liam R. Howlett <liam@infradead.org>
+Cc: Lorenzo Stoakes <ljs@kernel.org>
+Cc: Michal Hocko <mhocko@suse.com>
+Cc: Mike Rapoport <rppt@kernel.org>
+Cc: Pedro Falcato <pfalcato@suse.de>
+Cc: Peter Xu <peterx@redhat.com>
+Cc: Shuah Khan <shuah@kernel.org>
+Cc: Suren Baghdasaryan <surenb@google.com>
+Cc: Vlastimil Babka <vbabka@kernel.org>
+Assisted-by: Claude:claude-fable-5
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+(cherry picked from commit 07b4377bdbe74a3ec0c8da5849d014f70e003384)
+[ kas: fix only; selftest hunk dropped (pagemap_ioctl.c differs on this tree). Add the pte_none early-return before the pte_present branch ]
+
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/proc/task_mmu.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
+index 0cec16f9e9afd..48455e2a66a1e 100644
+--- a/fs/proc/task_mmu.c
++++ b/fs/proc/task_mmu.c
+@@ -2326,6 +2326,19 @@ static unsigned long pagemap_page_category(struct pagemap_scan_private *p,
+ {
+       unsigned long categories = 0;
++      if (pte_none(pte)) {
++              /*
++               * An unpopulated pte carries no uffd-wp marker, i.e. it is not
++               * write-protected, the same condition under which the present
++               * and swap cases below report PAGE_IS_WRITTEN. Report it here
++               * too so this generic path agrees with the PAGE_IS_WRITTEN fast
++               * path in pagemap_scan_pmd_entry(), which reports pte_none as
++               * written and, under PM_SCAN_WP_MATCHING, arms a marker. The
++               * fast path applies no VMA test, so neither does this.
++               */
++              return PAGE_IS_WRITTEN;
++      }
++
+       if (pte_present(pte)) {
+               struct page *page;
+-- 
+2.53.0
+
diff --git a/queue-6.18/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch b/queue-6.18/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
new file mode 100644 (file)
index 0000000..85f8529
--- /dev/null
@@ -0,0 +1,103 @@
+From 76cf830b745a7ee00b18b549fc5bb4b75f3692e3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:45:25 +0100
+Subject: mm/huge_memory: unlock i_mmap_rwsem before releasing after-split
+ folios
+
+From: Kiryl Shutsemau (Meta) <kas@kernel.org>
+
+[ Upstream commit e923bd21058ea02fd0dcd3549d151d143fd036e5 ]
+
+__folio_split() keeps dereferencing the mapping after the split:
+shmem_uncharge(mapping->host) and remap_page() while the folios are still
+frozen/locked, and i_mmap_unlock_read(mapping) at the very end, after the
+after-split folios have been unlocked and freed.
+
+Nothing holds an inode reference across that.  The split relies on @folio
+-- which the beyond-EOF drop loop never removes, as it starts at
+folio_next(folio) -- staying locked and in the page cache to hold off
+eviction.  But the unlock loop unlocks @folio before i_mmap_unlock_read()
+runs.  If the caller's @lock_at is a tail beyond EOF, as memory_failure()
+passes when splitting a poisoned tail of a shmem THP that reaches past
+i_size during truncation, it too is gone from the page cache; so once
+@folio is unlocked no locked, in-cache folio pins the inode, and a
+concurrent final iput() can evict and RCU-free it before
+i_mmap_unlock_read() touches i_mmap_rwsem:
+
+  BUG: KASAN: slab-use-after-free in __up_read+0x634/0x790
+   i_mmap_unlock_read include/linux/fs.h:537 [inline]
+   __folio_split+0x732/0x1640 mm/huge_memory.c:4100
+   try_to_split_thp_page+0xab/0x390 mm/memory-failure.c:1675
+   memory_failure+0x1394/0x26e0 mm/memory-failure.c:2470
+
+  Freed by task 4601:
+   shmem_free_in_core_inode+0x54/0xb0 mm/shmem.c:5177
+   evict+0x57f/0xac0 fs/inode.c:870
+
+Do every mapping dereference while @folio still pins the inode: drop
+i_mmap_rwsem right after remap_page(), before the loop that unlocks and
+frees the after-split folios, and clear @mapping so the exit path does not
+unlock it again.  shmem_uncharge() and remap_page() already run before
+that point, so after this nothing past the unlock loop touches the inode
+or the mapping.
+
+This is now a rule the split depends on, alongside keeping @folio frozen
+until the page cache is updated: no inode or mapping dereference once the
+after-split folios start being unlocked.
+
+Link: https://lore.kernel.org/20260716095424.471052-1-kirill@shutemov.name
+Fixes: baa355fd3314 ("thp: file pages support for split_huge_page()")
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Reported-by: Hao Zhang <zhanghao1@kylinos.cn>
+Closes: https://lore.kernel.org/linux-mm/20260710071344.GA106129@zh-pc
+Co-developed-by: Hao Zhang <zhanghao1@kylinos.cn>
+Signed-off-by: Hao Zhang <zhanghao1@kylinos.cn>
+Acked-by: David Hildenbrand (Arm) <david@kernel.org>
+Reviewed-by: Zi Yan <ziy@nvidia.com>
+Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
+Reviewed-by: Miaohe Lin <linmiaohe@huawei.com>
+Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
+Cc: Barry Song <baohua@kernel.org>
+Cc: Dev Jain <dev.jain@arm.com>
+Cc: Lance Yang <lance.yang@linux.dev>
+Cc: Liam R. Howlett <liam@infradead.org>
+Cc: Lorenzo Stoakes <ljs@kernel.org>
+Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
+Cc: Nico Pache <npache@redhat.com>
+Cc: Ryan Roberts <ryan.roberts@arm.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+(cherry picked from commit e923bd21058ea02fd0dcd3549d151d143fd036e5)
+
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/huge_memory.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/mm/huge_memory.c b/mm/huge_memory.c
+index c08aa3db96431..bd3093a6cc628 100644
+--- a/mm/huge_memory.c
++++ b/mm/huge_memory.c
+@@ -3871,6 +3871,18 @@ static int __folio_split(struct folio *folio, unsigned int new_order,
+               remap_flags = RMP_USE_SHARED_ZEROPAGE;
+       remap_page(folio, 1 << order, remap_flags);
++      /*
++       * Drop the mapping while the inode is still pinned. @folio stays
++       * locked and present in the page cache until the loop below, so
++       * eviction cannot free the inode yet; @lock_at is not enough, it may
++       * be a tail beyond EOF that the split already dropped from the page
++       * cache. Nothing past this point may touch the inode or the mapping.
++       */
++      if (mapping) {
++              i_mmap_unlock_read(mapping);
++              mapping = NULL;
++      }
++
+       /*
+        * Unlock all after-split folios except the one containing
+        * @lock_at page. If @folio is not split, it will be kept locked.
+-- 
+2.53.0
+
diff --git a/queue-6.18/mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch b/queue-6.18/mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch
new file mode 100644 (file)
index 0000000..d7bd4c5
--- /dev/null
@@ -0,0 +1,96 @@
+From a66eaa861ea42be82959100491e3c75cb3ba849c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:43:46 +0100
+Subject: mm/hugetlb: fix swap entry corruption when clearing uffd-wp at fork()
+
+From: Kiryl Shutsemau (Meta) <kas@kernel.org>
+
+[ Upstream commit 83abe2fd5b3aeb3123b5408a5a91709c5538fb23 ]
+
+copy_hugetlb_page_range() clears the uffd-wp bit of migration and hwpoison
+entries with huge_pte_clear_uffd_wp(), which operates on the present-PTE
+bit position.  Swap entries keep the uffd-wp state elsewhere -- the
+migration branch reads and sets it with pte_swp_uffd_wp() and
+pte_swp_mkuffd_wp() -- and the present-PTE position falls into the swap
+payload.  On x86-64 it lands in the inverted swap offset, where a
+naturally-aligned hugetlb PFN always has the affected bit set, so the
+clear advances the encoded PFN by two pages.
+
+No userfaultfd needs to be involved: the clear is guarded only by the
+child VMA not being uffd-wp registered, so a plain fork() with an
+in-flight hugetlb migration entry (or a poisoned hugetlb page) corrupts
+the entry copied into the child.  Instrumenting the clear and forking
+after MADV_HWPOISON on a 2MB anon hugetlb page shows:
+
+  offset before=120e00
+  offset after =120e02
+
+The fallout is mostly latent: rmap walks match migration entries by folio
+range and remove_migration_pte() rebuilds the PTE from the folio, so a
+within-folio PFN skew heals once migration completes.  But any path that
+re-encodes the corrupted offset -- e.g.  hugetlb_change_protection()
+rewriting a writable migration entry via
+make_readable_migration_entry(swp_offset(entry)) -- propagates it.
+
+Migration entries legitimately carry uffd-wp, so clear it with
+pte_swp_clear_uffd_wp(), matching copy_nonpresent_pte() and
+move_huge_pte().
+
+A hwpoison entry, on the other hand, never carries the uffd-wp bit: it is
+installed fresh by make_hwpoison_entry() (try_to_unmap_one() does not
+preserve uffd-wp on the hwpoison path) and hugetlb_change_protection()
+leaves hwpoison entries untouched.  There was nothing to clear there, only
+the corruption, so drop the clear entirely.
+
+Link: https://lore.kernel.org/20260708090110.136162-1-kirill@shutemov.name
+Fixes: bc70fbf269fd ("mm/hugetlb: handle uffd-wp during fork()")
+Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
+Reported-by: Sashiko AI review <sashiko-bot@kernel.org>
+Closes: https://lore.kernel.org/all/20260703140011.99E601F000E9@smtp.kernel.org/
+Suggested-by: David Hildenbrand <david@kernel.org>
+Acked-by: David Hildenbrand (Arm) <david@kernel.org>
+Assisted-by: Claude:claude-fable-5
+Cc: Muchun Song <muchun.song@linux.dev>
+Cc: Oscar Salvador <osalvador@suse.de>
+Cc: Peter Xu <peterx@redhat.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+(cherry picked from commit 83abe2fd5b3aeb3123b5408a5a91709c5538fb23)
+[ kas: adapt to the pre-softleaf idiom ]
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/hugetlb.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/mm/hugetlb.c b/mm/hugetlb.c
+index 0b3fd6943836e..5515870b5b155 100644
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -5634,8 +5634,12 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
+                        */
+                       ;
+               } else if (unlikely(is_hugetlb_entry_hwpoisoned(entry))) {
+-                      if (!userfaultfd_wp(dst_vma))
+-                              entry = huge_pte_clear_uffd_wp(entry);
++                      /*
++                       * A hwpoison entry never carries the uffd-wp bit: it is
++                       * installed fresh by make_hwpoison_entry() and
++                       * hugetlb_change_protection() leaves it untouched, so
++                       * there is nothing to clear for the child.
++                       */
+                       set_huge_pte_at(dst, addr, dst_pte, entry, sz);
+               } else if (unlikely(is_hugetlb_entry_migration(entry))) {
+                       swp_entry_t swp_entry = pte_to_swp_entry(entry);
+@@ -5654,7 +5658,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
+                               set_huge_pte_at(src, addr, src_pte, entry, sz);
+                       }
+                       if (!userfaultfd_wp(dst_vma))
+-                              entry = huge_pte_clear_uffd_wp(entry);
++                              entry = pte_swp_clear_uffd_wp(entry);
+                       set_huge_pte_at(dst, addr, dst_pte, entry, sz);
+               } else if (unlikely(is_pte_marker(entry))) {
+                       pte_marker marker = copy_pte_marker(
+-- 
+2.53.0
+
diff --git a/queue-6.18/net-handshake-close-the-submit-side-sock_hold-race.patch b/queue-6.18/net-handshake-close-the-submit-side-sock_hold-race.patch
new file mode 100644 (file)
index 0000000..3e3870f
--- /dev/null
@@ -0,0 +1,83 @@
+From 0fa09a2c127b52c59e46b760a0871b8b23296ec5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 01:40:04 +0800
+Subject: net/handshake: Close the submit-side sock_hold race
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 5da98f55b13173c08f003011b76531b25c821c07 ]
+
+handshake_req_submit() publishes the request via
+handshake_req_hash_add() and __add_pending_locked(), drops
+hn_lock, and calls handshake_genl_notify() (which can sleep)
+before taking sock_hold() on req->hr_sk. A fast tlshd ACCEPT
+followed by DONE can drive handshake_complete()'s sock_put()
+into the window between the spin_unlock and the late
+sock_hold(); on a system where the consumer's fd held the
+only sk reference, the late sock_hold() then operates on an
+sk whose refcount has reached zero.
+
+The preceding two patches install an explicit file reference
+on struct handshake_req. That file pins sock->file, which
+pins the embedded struct socket, which defers inet_release()'s
+sock_put(). As long as hr_file is held, sk cannot reach refcount
+zero from the consumer side, and the submit-side sock_hold()
+with its matching sock_put() calls in handshake_complete() and
+handshake_req_cancel() is now redundant.
+
+Drop all three. The file reference already keeps each request's
+socket alive, and the lifetime story is contained in a single
+get_file()/fput() pair.
+
+Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests")
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: Hannes Reinecke <hare@kernel.org>
+Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-6-66c616906ead@oracle.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+(cherry picked from commit 5da98f55b13173c08f003011b76531b25c821c07)
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/handshake/request.c | 12 ------------
+ 1 file changed, 12 deletions(-)
+
+diff --git a/net/handshake/request.c b/net/handshake/request.c
+index 4bf98793491aa..035bb2d7471c9 100644
+--- a/net/handshake/request.c
++++ b/net/handshake/request.c
+@@ -301,13 +301,6 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req,
+                       goto out_err;
+       }
+-      /*
+-       * Pin struct sock so sk_destruct does not run until the
+-       * handshake completion path releases it; struct socket is
+-       * held separately via hr_file above.
+-       */
+-      sock_hold(req->hr_sk);
+-
+       trace_handshake_submit(net, req, req->hr_sk);
+       return 0;
+@@ -337,9 +330,6 @@ void handshake_complete(struct handshake_req *req, int status,
+               trace_handshake_complete(net, req, sk, status);
+               req->hr_proto->hp_done(req, status, info);
+-              /* Handshake request is no longer pending */
+-              sock_put(sk);
+-
+               fput(file);
+       }
+ }
+@@ -387,8 +377,6 @@ bool handshake_req_cancel(struct sock *sk)
+ out_true:
+       trace_handshake_cancel(net, req, sk);
+-      /* Handshake request is no longer pending */
+-      sock_put(sk);
+       fput(req->hr_file);
+       return true;
+ }
+-- 
+2.53.0
+
diff --git a/queue-6.18/net-handshake-convert-handshake_nl_accept_doit-to-fd.patch b/queue-6.18/net-handshake-convert-handshake_nl_accept_doit-to-fd.patch
new file mode 100644 (file)
index 0000000..a4c2794
--- /dev/null
@@ -0,0 +1,79 @@
+From 9cb400cb6a52c1935e2fcf5f86d2114fdc5678fa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 01:39:56 +0800
+Subject: net/handshake: convert handshake_nl_accept_doit() to FD_PREPARE()
+
+From: Christian Brauner <brauner@kernel.org>
+
+[ Upstream commit fe67b063f687d8f32c466778aad57508bc1c618a ]
+
+Link: https://patch.msgid.link/20251123-work-fd-prepare-v4-27-b6efa1706cfd@kernel.org
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+(cherry picked from commit fe67b063f687d8f32c466778aad57508bc1c618a)
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/handshake/netlink.c | 38 ++++++++++++++++++--------------------
+ 1 file changed, 18 insertions(+), 20 deletions(-)
+
+diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c
+index d8211e0ba75c6..7b1d42607ae68 100644
+--- a/net/handshake/netlink.c
++++ b/net/handshake/netlink.c
+@@ -93,7 +93,7 @@ int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info)
+       struct handshake_net *hn = handshake_pernet(net);
+       struct handshake_req *req = NULL;
+       struct socket *sock;
+-      int class, fd, err;
++      int class, err;
+       err = -EOPNOTSUPP;
+       if (!hn)
+@@ -106,27 +106,25 @@ int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info)
+       err = -EAGAIN;
+       req = handshake_req_next(hn, class);
+-      if (!req)
+-              goto out_status;
+-
+-      sock = req->hr_sk->sk_socket;
+-      fd = get_unused_fd_flags(O_CLOEXEC);
+-      if (fd < 0) {
+-              err = fd;
+-              goto out_complete;
+-      }
+-
+-      err = req->hr_proto->hp_accept(req, info, fd);
+-      if (err) {
+-              put_unused_fd(fd);
+-              goto out_complete;
++      if (req) {
++              sock = req->hr_sk->sk_socket;
++
++              FD_PREPARE(fdf, O_CLOEXEC, sock->file);
++              if (fdf.err) {
++                      err = fdf.err;
++                      goto out_complete;
++              }
++
++              get_file(sock->file); /* FD_PREPARE() consumes a reference. */
++              err = req->hr_proto->hp_accept(req, info, fd_prepare_fd(fdf));
++              if (err)
++                      goto out_complete; /* Automatic cleanup handles fput */
++
++              trace_handshake_cmd_accept(net, req, req->hr_sk, fd_prepare_fd(fdf));
++              fd_publish(fdf);
++              return 0;
+       }
+-      fd_install(fd, get_file(sock->file));
+-
+-      trace_handshake_cmd_accept(net, req, req->hr_sk, fd);
+-      return 0;
+-
+ out_complete:
+       handshake_complete(req, -EIO, NULL);
+ out_status:
+-- 
+2.53.0
+
diff --git a/queue-6.18/net-handshake-drain-pending-requests-at-net-namespac.patch b/queue-6.18/net-handshake-drain-pending-requests-at-net-namespac.patch
new file mode 100644 (file)
index 0000000..c29d84d
--- /dev/null
@@ -0,0 +1,114 @@
+From 1be2f0670e21e2e3612655a8aac4366305a98a1e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 01:40:06 +0800
+Subject: net/handshake: Drain pending requests at net namespace exit
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit ea5fe6a73ca57e5150b8a38b341aef2636eb72f0 ]
+
+The arguments to list_splice_init() in handshake_net_exit() are
+reversed. The call moves the local empty "requests" list onto
+hn->hn_requests, leaving the local list empty, so the subsequent
+drain loop runs zero iterations. Pending handshake requests that
+had not yet been accepted are not torn down when the net namespace
+is destroyed; each one keeps a reference on a socket file and on
+the handshake_req allocation.
+
+Pass the source and destination in the documented order
+(list_splice_init(list, head) moves list onto head) so the pending
+list is transferred to the local scratch list and drained through
+handshake_complete().
+
+Fixing the splice direction exposes a list-corruption race. After
+the splice each req->hr_list still has non-empty link pointers,
+threading the stack-local scratch list rather than hn_requests.
+A concurrent handshake_req_cancel() -- for example, from sunrpc's
+TLS timeout on a kernel socket whose netns reference was not
+taken -- finds the request through the rhashtable, calls
+remove_pending(), and sees !list_empty(&req->hr_list).
+__remove_pending_locked() then list_del_init()s an entry off the
+scratch list while the drain iterates, corrupting it. The same
+call arriving after the drain loop has run list_del() on an
+entry hits LIST_POISON instead.
+
+Have remove_pending() check HANDSHAKE_F_NET_DRAINING under
+hn_lock and report not-found when drain is in progress. The
+drain has already taken ownership; handshake_complete()'s existing
+test_and_set on HANDSHAKE_F_REQ_COMPLETED still arbitrates
+between drain and cancel for who calls the consumer's hp_done. Use
+list_del_init() rather than list_del() in the drain so req->hr_list
+does not carry LIST_POISON after drain releases the entry.
+
+The DRAINING guard in remove_pending() makes cancel return false,
+but cancel still falls through to test_and_set_bit on
+HANDSHAKE_F_REQ_COMPLETED and drops the request's hr_file reference.
+Without another pin, if that is the last reference, sk_destruct frees
+the request while it is still linked on the drain loop's local list.
+Pin each request's hr_file under hn_lock before releasing the list,
+and drop that drain pin after the loop finishes with the request.
+
+Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests")
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: Hannes Reinecke <hare@kernel.org>
+Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-8-66c616906ead@oracle.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+(cherry picked from commit ea5fe6a73ca57e5150b8a38b341aef2636eb72f0)
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/handshake/netlink.c | 10 ++++++++--
+ net/handshake/request.c |  5 ++++-
+ 2 files changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c
+index 21d6cbd52fcdb..3fd4fef9bab1a 100644
+--- a/net/handshake/netlink.c
++++ b/net/handshake/netlink.c
+@@ -201,13 +201,19 @@ static void __net_exit handshake_net_exit(struct net *net)
+        */
+       spin_lock_bh(&hn->hn_lock);
+       set_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags);
+-      list_splice_init(&requests, &hn->hn_requests);
++      list_splice_init(&hn->hn_requests, &requests);
++      list_for_each_entry(req, &requests, hr_list)
++              get_file(req->hr_file);
+       spin_unlock_bh(&hn->hn_lock);
+       while (!list_empty(&requests)) {
++              struct file *file;
++
+               req = list_first_entry(&requests, struct handshake_req, hr_list);
+-              list_del(&req->hr_list);
++              file = req->hr_file;
++              list_del_init(&req->hr_list);
+               handshake_complete(req, -ETIMEDOUT, NULL);
++              fput(file);
+       }
+ }
+diff --git a/net/handshake/request.c b/net/handshake/request.c
+index 035bb2d7471c9..d4a3a50f8a3b5 100644
+--- a/net/handshake/request.c
++++ b/net/handshake/request.c
+@@ -163,13 +163,16 @@ static void __remove_pending_locked(struct handshake_net *hn,
+  * otherwise %false.
+  *
+  * If @req was on a pending list, it has not yet been accepted.
++ * Returns %false when the net namespace is draining; the drain
++ * loop has taken ownership of the pending list.
+  */
+ static bool remove_pending(struct handshake_net *hn, struct handshake_req *req)
+ {
+       bool ret = false;
+       spin_lock_bh(&hn->hn_lock);
+-      if (!list_empty(&req->hr_list)) {
++      if (!test_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags) &&
++          !list_empty(&req->hr_list)) {
+               __remove_pending_locked(hn, req);
+               ret = true;
+       }
+-- 
+2.53.0
+
diff --git a/queue-6.18/net-handshake-fix-null-ptr-deref-in-handshake_comple.patch b/queue-6.18/net-handshake-fix-null-ptr-deref-in-handshake_comple.patch
new file mode 100644 (file)
index 0000000..6827967
--- /dev/null
@@ -0,0 +1,72 @@
+From fb2046a110c035c0978a943ecc883d241feaae96 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 01:39:58 +0800
+Subject: net/handshake: Fix null-ptr-deref in handshake_complete()
+
+From: Wang Liang <wangliang74@huawei.com>
+
+[ Upstream commit dabac51b8102e1643d8e297a8e6948dab190aa4c ]
+
+A null pointer dereference in handshake_complete() was observed [1].
+
+When handshake_req_next() return NULL in handshake_nl_accept_doit(),
+function handshake_complete() will be called unexpectedly which triggers
+this crash. Fix it by goto out_status when req is NULL.
+
+[1]
+Oops: general protection fault, probably for non-canonical address 0xdffffc0000000005: 0000 [#1] SMP KASAN PTI
+RIP: 0010:handshake_complete+0x36/0x2b0 net/handshake/request.c:288
+Call Trace:
+ <TASK>
+ handshake_nl_accept_doit+0x32d/0x7e0 net/handshake/netlink.c:129
+ genl_family_rcv_msg_doit+0x204/0x300 net/netlink/genetlink.c:1115
+ genl_family_rcv_msg+0x436/0x670 net/netlink/genetlink.c:1195
+ genl_rcv_msg+0xcc/0x170 net/netlink/genetlink.c:1210
+ netlink_rcv_skb+0x14c/0x430 net/netlink/af_netlink.c:2550
+ genl_rcv+0x2d/0x40 net/netlink/genetlink.c:1219
+ netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline]
+ netlink_unicast+0x878/0xb20 net/netlink/af_netlink.c:1344
+ netlink_sendmsg+0x897/0xd70 net/netlink/af_netlink.c:1894
+ sock_sendmsg_nosec net/socket.c:727 [inline]
+ __sock_sendmsg net/socket.c:742 [inline]
+ ____sys_sendmsg+0xa39/0xbf0 net/socket.c:2592
+ ___sys_sendmsg+0x121/0x1c0 net/socket.c:2646
+ __sys_sendmsg+0x155/0x200 net/socket.c:2678
+ do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+ do_syscall_64+0x5f/0x350 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+ </TASK>
+
+Fixes: fe67b063f687 ("net/handshake: convert handshake_nl_accept_doit() to FD_PREPARE()")
+Reviewed-by: Chuck Lever <chuck.lever@oracle.com>
+Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
+Closes: https://lore.kernel.org/kernel-tls-handshake/aScekpuOYHRM9uOd@morisot.1015granger.net/T/#m7cfa5c11efc626d77622b2981591197a2acdd65e
+Signed-off-by: Wang Liang <wangliang74@huawei.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20251212012723.4111831-1-wangliang74@huawei.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+
+(cherry picked from commit dabac51b8102e1643d8e297a8e6948dab190aa4c)
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/handshake/netlink.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c
+index 7b1d42607ae68..039344979de93 100644
+--- a/net/handshake/netlink.c
++++ b/net/handshake/netlink.c
+@@ -126,7 +126,8 @@ int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info)
+       }
+ out_complete:
+-      handshake_complete(req, -EIO, NULL);
++      if (req)
++              handshake_complete(req, -EIO, NULL);
+ out_status:
+       trace_handshake_cmd_accept_err(net, req, NULL, err);
+       return err;
+-- 
+2.53.0
+
diff --git a/queue-6.18/net-handshake-hand-off-the-pinned-file-reference-to-.patch b/queue-6.18/net-handshake-hand-off-the-pinned-file-reference-to-.patch
new file mode 100644 (file)
index 0000000..60d0b4d
--- /dev/null
@@ -0,0 +1,153 @@
+From 6f64110126105e5e5f8ed16c0cdc45c12e735498 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 01:40:02 +0800
+Subject: net/handshake: hand off the pinned file reference to accept_doit
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit f4251190e58b209999c1ba9e6d2976136a1be055 ]
+
+handshake_req_next() removes the request from the per-net
+pending list and drops hn_lock before handshake_nl_accept_doit()
+reads req->hr_sk->sk_socket and dereferences sock->file (once in
+FD_PREPARE() and again in get_file()).  In that window a
+consumer running tls_handshake_cancel() followed by sockfd_put()
+(svc_sock_free) or __fput_sync() (xs_reset_transport) releases
+sock->file.  sock_release() then runs sock_orphan(), zeroing
+sk_socket, and frees the struct socket.  The accept-side code
+either reads NULL through sk_socket or chases freed memory.
+
+The submit-side sock_hold() does not prevent this.  sk_refcnt
+protects struct sock, but struct socket and sock->file are
+independently refcounted via the file descriptor the consumer
+owns.  Pinning sk leaves sock and sock->file unprotected.
+
+Retarget the accept-side dereferences at req->hr_file, which was
+pinned at submit time, instead of req->hr_sk->sk_socket->file.
+Pinning on its own is not sufficient: a consumer that cancels
+between handshake_req_next() returning and accept_doit reaching
+FD_PREPARE() takes the !remove_pending() branch in
+handshake_req_cancel() and drops hr_file before the accept side
+takes its own reference.  Hand off an additional file reference
+inside handshake_req_next(), under hn_lock, so the accept side
+operates on a reference that no concurrent handshake_req_cancel()
+can revoke.  FD_PREPARE() consumes that handed-off reference,
+either by transferring it to the new fd in fd_publish() or by
+dropping it in the cleanup destructor on error; the explicit
+get_file() that previously balanced FD_PREPARE() is therefore
+redundant and goes away.
+
+Update handshake_req_cancel_test2 and _test3 to simulate the
+FD_PREPARE() consumption with an fput() so the kunit file-count
+assertions stay balanced.
+
+Reported-by: Chris Mason <clm@meta.com>
+Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests")
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: Hannes Reinecke <hare@kernel.org>
+Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-5-66c616906ead@oracle.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+(cherry picked from commit f4251190e58b209999c1ba9e6d2976136a1be055)
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/handshake/handshake-test.c |  8 ++++++++
+ net/handshake/netlink.c        |  7 ++-----
+ net/handshake/request.c        | 18 ++++++++++++++++++
+ 3 files changed, 28 insertions(+), 5 deletions(-)
+
+diff --git a/net/handshake/handshake-test.c b/net/handshake/handshake-test.c
+index df3948e807a0f..9cc7a95f41207 100644
+--- a/net/handshake/handshake-test.c
++++ b/net/handshake/handshake-test.c
+@@ -375,6 +375,10 @@ static void handshake_req_cancel_test2(struct kunit *test)
+       /* Pretend to accept this request */
+       next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD);
+       KUNIT_ASSERT_PTR_EQ(test, req, next);
++      /* Simulate FD_PREPARE() consuming the file reference handed
++       * off by handshake_req_next(); see handshake_nl_accept_doit().
++       */
++      fput(filp);
+       /* Act */
+       result = handshake_req_cancel(sock->sk);
+@@ -417,6 +421,10 @@ static void handshake_req_cancel_test3(struct kunit *test)
+       /* Pretend to accept this request */
+       next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD);
+       KUNIT_ASSERT_PTR_EQ(test, req, next);
++      /* Simulate FD_PREPARE() consuming the file reference handed
++       * off by handshake_req_next(); see handshake_nl_accept_doit().
++       */
++      fput(filp);
+       /* Pretend to complete this request */
+       handshake_complete(next, -ETIMEDOUT, NULL);
+diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c
+index 1a5821eb71847..21d6cbd52fcdb 100644
+--- a/net/handshake/netlink.c
++++ b/net/handshake/netlink.c
+@@ -92,7 +92,6 @@ int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info)
+       struct net *net = sock_net(skb->sk);
+       struct handshake_net *hn = handshake_pernet(net);
+       struct handshake_req *req = NULL;
+-      struct socket *sock;
+       int class, err;
+       err = -EOPNOTSUPP;
+@@ -107,15 +106,13 @@ int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info)
+       err = -EAGAIN;
+       req = handshake_req_next(hn, class);
+       if (req) {
+-              sock = req->hr_sk->sk_socket;
+-
+-              FD_PREPARE(fdf, O_CLOEXEC, sock->file);
++              FD_PREPARE(fdf, O_CLOEXEC, req->hr_file);
+               if (fdf.err) {
++                      fput(req->hr_file); /* drop ref from handshake_req_next() */
+                       err = fdf.err;
+                       goto out_complete;
+               }
+-              get_file(sock->file); /* FD_PREPARE() consumes a reference. */
+               err = req->hr_proto->hp_accept(req, info, fd_prepare_fd(fdf));
+               if (err)
+                       goto out_complete; /* Automatic cleanup handles fput */
+diff --git a/net/handshake/request.c b/net/handshake/request.c
+index 35bc6290e1203..4bf98793491aa 100644
+--- a/net/handshake/request.c
++++ b/net/handshake/request.c
+@@ -178,6 +178,17 @@ static bool remove_pending(struct handshake_net *hn, struct handshake_req *req)
+       return ret;
+ }
++/**
++ * handshake_req_next - Return the next queued handshake request
++ * @hn: per-net handshake state
++ * @class: handler class to match
++ *
++ * On a non-NULL return, the caller owns an extra reference
++ * on @req->hr_file.  FD_PREPARE() consumes it on success; on
++ * the FD_PREPARE() failure path the caller must fput() it.
++ *
++ * Return: pointer to a removed handshake_req, or NULL.
++ */
+ struct handshake_req *handshake_req_next(struct handshake_net *hn, int class)
+ {
+       struct handshake_req *req, *pos;
+@@ -188,6 +199,13 @@ struct handshake_req *handshake_req_next(struct handshake_net *hn, int class)
+               if (pos->hr_proto->hp_handler_class != class)
+                       continue;
+               __remove_pending_locked(hn, pos);
++              /* Hand off a file reference to the accept side under
++               * hn_lock.  A concurrent handshake_req_cancel() can drop
++               * hr_file before accept reaches FD_PREPARE(); this extra
++               * reference keeps the file alive until FD_PREPARE() takes
++               * ownership.
++               */
++              get_file(pos->hr_file);
+               req = pos;
+               break;
+       }
+-- 
+2.53.0
+
diff --git a/queue-6.18/net-handshake-take-a-long-lived-file-reference-at-su.patch b/queue-6.18/net-handshake-take-a-long-lived-file-reference-at-su.patch
new file mode 100644 (file)
index 0000000..7abeee0
--- /dev/null
@@ -0,0 +1,188 @@
+From 0a8bac33dc7ecc2c0f44829dec6e9d231fc8b61b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 01:40:00 +0800
+Subject: net/handshake: Take a long-lived file reference at submit
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 09dba37eee70d0596e26645015f1aa95a9848e9d ]
+
+handshake_nl_accept_doit() needs the file pointer backing
+req->hr_sk->sk_socket to survive the window between
+handshake_req_next() and the subsequent FD_PREPARE() and get_file().
+The submit-side sock_hold() does not provide that.  sk_refcnt keeps
+struct sock alive, but struct socket is owned by sock->file: when
+the consumer fputs the last file reference, sock_release() tears
+the socket down regardless of any sock_hold.
+
+Add an hr_file pointer to struct handshake_req and acquire an
+explicit reference on sock->file during handshake_req_submit().
+handshake_complete() and handshake_req_cancel() release the
+reference on the completion-bit-winning path.
+
+The submit error path must also release the file reference, but
+after rhashtable insertion a concurrent handshake_req_cancel() can
+discover the request and race the error path.  Gate the error-path
+cleanup -- sk_destruct restoration, fput, and request destruction
+-- with test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED), the same
+serialization handshake_complete() and handshake_req_cancel()
+already use.  When cancel has already claimed ownership, the submit
+error path returns without touching the request; socket teardown
+handles final destruction.
+
+The accept-side dereferences are not yet retargeted; that change
+comes in the next patch.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-4-66c616906ead@oracle.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+(cherry picked from commit 09dba37eee70d0596e26645015f1aa95a9848e9d)
+Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/handshake/handshake.h |  2 ++
+ net/handshake/netlink.c   |  6 ------
+ net/handshake/request.c   | 42 ++++++++++++++++++++++++++++++++-------
+ 3 files changed, 37 insertions(+), 13 deletions(-)
+
+diff --git a/net/handshake/handshake.h b/net/handshake/handshake.h
+index 2289b0e274f40..da61cadd1ad3e 100644
+--- a/net/handshake/handshake.h
++++ b/net/handshake/handshake.h
+@@ -24,6 +24,7 @@ enum hn_flags_bits {
+       HANDSHAKE_F_NET_DRAINING,
+ };
++struct file;
+ struct handshake_proto;
+ /* One handshake request */
+@@ -32,6 +33,7 @@ struct handshake_req {
+       struct rhash_head               hr_rhash;
+       unsigned long                   hr_flags;
+       const struct handshake_proto    *hr_proto;
++      struct file                     *hr_file;
+       struct sock                     *hr_sk;
+       void                            (*hr_odestruct)(struct sock *sk);
+diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c
+index 039344979de93..1a5821eb71847 100644
+--- a/net/handshake/netlink.c
++++ b/net/handshake/netlink.c
+@@ -210,12 +210,6 @@ static void __net_exit handshake_net_exit(struct net *net)
+       while (!list_empty(&requests)) {
+               req = list_first_entry(&requests, struct handshake_req, hr_list);
+               list_del(&req->hr_list);
+-
+-              /*
+-               * Requests on this list have not yet been
+-               * accepted, so they do not have an fd to put.
+-               */
+-
+               handshake_complete(req, -ETIMEDOUT, NULL);
+       }
+ }
+diff --git a/net/handshake/request.c b/net/handshake/request.c
+index 62efb7e32730e..35bc6290e1203 100644
+--- a/net/handshake/request.c
++++ b/net/handshake/request.c
+@@ -13,6 +13,7 @@
+ #include <linux/module.h>
+ #include <linux/skbuff.h>
+ #include <linux/inet.h>
++#include <linux/file.h>
+ #include <linux/rhashtable.h>
+ #include <net/sock.h>
+@@ -215,9 +216,16 @@ EXPORT_SYMBOL_IF_KUNIT(handshake_req_next);
+  * A zero return value from handshake_req_submit() means that
+  * exactly one subsequent completion callback is guaranteed.
+  *
+- * A negative return value from handshake_req_submit() means that
+- * no completion callback will be done and that @req has been
+- * destroyed.
++ * A negative return value from handshake_req_submit() guarantees that
++ * no completion callback will occur and that @req is no longer owned by
++ * the caller. If cancellation wins the completion race after the request
++ * has been published, final destruction is deferred until socket teardown.
++ *
++ * The caller must hold a reference on @sock->file for the duration
++ * of this call. Once the request is published to the accept side, a
++ * concurrent completion or cancellation may release the request's pin on
++ * @sock->file; the caller's reference is what keeps @sock->sk valid until
++ * handshake_req_submit() returns.
+  */
+ int handshake_req_submit(struct socket *sock, struct handshake_req *req,
+                        gfp_t flags)
+@@ -236,6 +244,14 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req,
+               kfree(req);
+               return -EINVAL;
+       }
++
++      /*
++       * Pin sock->file for the lifetime of the request so the
++       * accept side does not race a consumer that releases the
++       * socket while a handshake is pending.
++       */
++      req->hr_file = get_file(sock->file);
++
+       req->hr_odestruct = req->hr_sk->sk_destruct;
+       req->hr_sk->sk_destruct = handshake_sk_destruct;
+@@ -267,7 +283,11 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req,
+                       goto out_err;
+       }
+-      /* Prevent socket release while a handshake request is pending */
++      /*
++       * Pin struct sock so sk_destruct does not run until the
++       * handshake completion path releases it; struct socket is
++       * held separately via hr_file above.
++       */
+       sock_hold(req->hr_sk);
+       trace_handshake_submit(net, req, req->hr_sk);
+@@ -276,10 +296,13 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req,
+ out_unlock:
+       spin_unlock_bh(&hn->hn_lock);
+ out_err:
+-      /* Restore original destructor so socket teardown still runs on failure */
+-      req->hr_sk->sk_destruct = req->hr_odestruct;
+       trace_handshake_submit_err(net, req, req->hr_sk, ret);
+-      handshake_req_destroy(req);
++      if (!test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) {
++              /* Restore original destructor so socket teardown still runs. */
++              req->hr_sk->sk_destruct = req->hr_odestruct;
++              fput(req->hr_file);
++              handshake_req_destroy(req);
++      }
+       return ret;
+ }
+ EXPORT_SYMBOL(handshake_req_submit);
+@@ -291,11 +314,15 @@ void handshake_complete(struct handshake_req *req, int status,
+       struct net *net = sock_net(sk);
+       if (!test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) {
++              struct file *file = req->hr_file;
++
+               trace_handshake_complete(net, req, sk, status);
+               req->hr_proto->hp_done(req, status, info);
+               /* Handshake request is no longer pending */
+               sock_put(sk);
++
++              fput(file);
+       }
+ }
+ EXPORT_SYMBOL_IF_KUNIT(handshake_complete);
+@@ -344,6 +371,7 @@ bool handshake_req_cancel(struct sock *sk)
+       /* Handshake request is no longer pending */
+       sock_put(sk);
++      fput(req->hr_file);
+       return true;
+ }
+ EXPORT_SYMBOL(handshake_req_cancel);
+-- 
+2.53.0
+
index c07a0f977bc4064fb932ba2f6e2f660288818bf3..57cb4f230241f7ec6fcb2a73c2c3f54e83eff08d 100644 (file)
@@ -351,3 +351,14 @@ drm-xe-rtp-toggle-deny-bit-to-de-whitelist-oa-regs.patch
 drm-xe-rtp-de-whitelist-oa-registers-for-all-hwe-s-f.patch
 drm-xe-oa-de-whitelist-oa-registers-on-oa-stream-ope.patch
 drm-xe-rtp-ensure-locking-ref-counting-for-oa-whitel.patch
+mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch
+fs-proc-task_mmu-fix-pagemap_scan-written-state-for-.patch
+mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
+file-add-fd_-add-prepare.patch
+file-ensure-cleanup.patch
+net-handshake-convert-handshake_nl_accept_doit-to-fd.patch
+net-handshake-fix-null-ptr-deref-in-handshake_comple.patch
+net-handshake-take-a-long-lived-file-reference-at-su.patch
+net-handshake-hand-off-the-pinned-file-reference-to-.patch
+net-handshake-close-the-submit-side-sock_hold-race.patch
+net-handshake-drain-pending-requests-at-net-namespac.patch
diff --git a/queue-6.6/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch b/queue-6.6/mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
new file mode 100644 (file)
index 0000000..8a7e776
--- /dev/null
@@ -0,0 +1,125 @@
+From f072d6a25d426a9f4efc380fea6b5167d612e499 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:45:19 +0100
+Subject: mm/huge_memory: unlock i_mmap_rwsem before releasing after-split
+ folios
+
+From: Kiryl Shutsemau (Meta) <kas@kernel.org>
+
+[ Upstream commit e923bd21058ea02fd0dcd3549d151d143fd036e5 ]
+
+__folio_split() keeps dereferencing the mapping after the split:
+shmem_uncharge(mapping->host) and remap_page() while the folios are still
+frozen/locked, and i_mmap_unlock_read(mapping) at the very end, after the
+after-split folios have been unlocked and freed.
+
+Nothing holds an inode reference across that.  The split relies on @folio
+-- which the beyond-EOF drop loop never removes, as it starts at
+folio_next(folio) -- staying locked and in the page cache to hold off
+eviction.  But the unlock loop unlocks @folio before i_mmap_unlock_read()
+runs.  If the caller's @lock_at is a tail beyond EOF, as memory_failure()
+passes when splitting a poisoned tail of a shmem THP that reaches past
+i_size during truncation, it too is gone from the page cache; so once
+@folio is unlocked no locked, in-cache folio pins the inode, and a
+concurrent final iput() can evict and RCU-free it before
+i_mmap_unlock_read() touches i_mmap_rwsem:
+
+  BUG: KASAN: slab-use-after-free in __up_read+0x634/0x790
+   i_mmap_unlock_read include/linux/fs.h:537 [inline]
+   __folio_split+0x732/0x1640 mm/huge_memory.c:4100
+   try_to_split_thp_page+0xab/0x390 mm/memory-failure.c:1675
+   memory_failure+0x1394/0x26e0 mm/memory-failure.c:2470
+
+  Freed by task 4601:
+   shmem_free_in_core_inode+0x54/0xb0 mm/shmem.c:5177
+   evict+0x57f/0xac0 fs/inode.c:870
+
+Do every mapping dereference while @folio still pins the inode: drop
+i_mmap_rwsem right after remap_page(), before the loop that unlocks and
+frees the after-split folios, and clear @mapping so the exit path does not
+unlock it again.  shmem_uncharge() and remap_page() already run before
+that point, so after this nothing past the unlock loop touches the inode
+or the mapping.
+
+This is now a rule the split depends on, alongside keeping @folio frozen
+until the page cache is updated: no inode or mapping dereference once the
+after-split folios start being unlocked.
+
+Link: https://lore.kernel.org/20260716095424.471052-1-kirill@shutemov.name
+Fixes: baa355fd3314 ("thp: file pages support for split_huge_page()")
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Reported-by: Hao Zhang <zhanghao1@kylinos.cn>
+Closes: https://lore.kernel.org/linux-mm/20260710071344.GA106129@zh-pc
+Co-developed-by: Hao Zhang <zhanghao1@kylinos.cn>
+Signed-off-by: Hao Zhang <zhanghao1@kylinos.cn>
+Acked-by: David Hildenbrand (Arm) <david@kernel.org>
+Reviewed-by: Zi Yan <ziy@nvidia.com>
+Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
+Reviewed-by: Miaohe Lin <linmiaohe@huawei.com>
+Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
+Cc: Barry Song <baohua@kernel.org>
+Cc: Dev Jain <dev.jain@arm.com>
+Cc: Lance Yang <lance.yang@linux.dev>
+Cc: Liam R. Howlett <liam@infradead.org>
+Cc: Lorenzo Stoakes <ljs@kernel.org>
+Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
+Cc: Nico Pache <npache@redhat.com>
+Cc: Ryan Roberts <ryan.roberts@arm.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+
+(cherry picked from commit e923bd21058ea02fd0dcd3549d151d143fd036e5)
+[ kas: adapt to the __split_huge_page()/split_huge_page_to_list()
+  two-function split: pass @mapping into __split_huge_page() and drop it
+  there, before the loop that frees the after-split subpages while the
+  head is still locked; the caller then skips its own i_mmap unlock ]
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/huge_memory.c | 16 ++++++++++++++--
+ 1 file changed, 14 insertions(+), 2 deletions(-)
+
+diff --git a/mm/huge_memory.c b/mm/huge_memory.c
+index 4443cc44cbf9f..ff95a802d1582 100644
+--- a/mm/huge_memory.c
++++ b/mm/huge_memory.c
+@@ -2489,7 +2489,7 @@ static void __split_huge_page_tail(struct folio *folio, int tail,
+ }
+ static void __split_huge_page(struct page *page, struct list_head *list,
+-              pgoff_t end)
++              pgoff_t end, struct address_space *mapping)
+ {
+       struct folio *folio = page_folio(page);
+       struct page *head = &folio->page;
+@@ -2564,6 +2564,16 @@ static void __split_huge_page(struct page *page, struct list_head *list,
+       if (folio_test_swapcache(folio))
+               split_swap_cluster(folio->swap);
++      /*
++       * Drop the mapping while the head page is still locked and thus pins
++       * the inode. The loop below may free the after-split subpages --
++       * including the head, when @page is a tail beyond EOF that the split
++       * dropped from the page cache -- which could otherwise let the inode,
++       * and @mapping, be freed before this unlock.
++       */
++      if (mapping)
++              i_mmap_unlock_read(mapping);
++
+       for (i = 0; i < nr; i++) {
+               struct page *subpage = head + i;
+               if (subpage == page)
+@@ -2745,7 +2755,9 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
+                       }
+               }
+-              __split_huge_page(page, list, end);
++              __split_huge_page(page, list, end, mapping);
++              /* __split_huge_page() dropped the i_mmap lock */
++              mapping = NULL;
+               ret = 0;
+       } else {
+               spin_unlock(&ds_queue->split_queue_lock);
+-- 
+2.53.0
+
diff --git a/queue-6.6/mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch b/queue-6.6/mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch
new file mode 100644 (file)
index 0000000..986db51
--- /dev/null
@@ -0,0 +1,96 @@
+From 9a1f6eb0b724013b9b77d262bdcb811830ac20b0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2026 14:43:38 +0100
+Subject: mm/hugetlb: fix swap entry corruption when clearing uffd-wp at fork()
+
+From: Kiryl Shutsemau (Meta) <kas@kernel.org>
+
+[ Upstream commit 83abe2fd5b3aeb3123b5408a5a91709c5538fb23 ]
+
+copy_hugetlb_page_range() clears the uffd-wp bit of migration and hwpoison
+entries with huge_pte_clear_uffd_wp(), which operates on the present-PTE
+bit position.  Swap entries keep the uffd-wp state elsewhere -- the
+migration branch reads and sets it with pte_swp_uffd_wp() and
+pte_swp_mkuffd_wp() -- and the present-PTE position falls into the swap
+payload.  On x86-64 it lands in the inverted swap offset, where a
+naturally-aligned hugetlb PFN always has the affected bit set, so the
+clear advances the encoded PFN by two pages.
+
+No userfaultfd needs to be involved: the clear is guarded only by the
+child VMA not being uffd-wp registered, so a plain fork() with an
+in-flight hugetlb migration entry (or a poisoned hugetlb page) corrupts
+the entry copied into the child.  Instrumenting the clear and forking
+after MADV_HWPOISON on a 2MB anon hugetlb page shows:
+
+  offset before=120e00
+  offset after =120e02
+
+The fallout is mostly latent: rmap walks match migration entries by folio
+range and remove_migration_pte() rebuilds the PTE from the folio, so a
+within-folio PFN skew heals once migration completes.  But any path that
+re-encodes the corrupted offset -- e.g.  hugetlb_change_protection()
+rewriting a writable migration entry via
+make_readable_migration_entry(swp_offset(entry)) -- propagates it.
+
+Migration entries legitimately carry uffd-wp, so clear it with
+pte_swp_clear_uffd_wp(), matching copy_nonpresent_pte() and
+move_huge_pte().
+
+A hwpoison entry, on the other hand, never carries the uffd-wp bit: it is
+installed fresh by make_hwpoison_entry() (try_to_unmap_one() does not
+preserve uffd-wp on the hwpoison path) and hugetlb_change_protection()
+leaves hwpoison entries untouched.  There was nothing to clear there, only
+the corruption, so drop the clear entirely.
+
+Link: https://lore.kernel.org/20260708090110.136162-1-kirill@shutemov.name
+Fixes: bc70fbf269fd ("mm/hugetlb: handle uffd-wp during fork()")
+Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
+Reported-by: Sashiko AI review <sashiko-bot@kernel.org>
+Closes: https://lore.kernel.org/all/20260703140011.99E601F000E9@smtp.kernel.org/
+Suggested-by: David Hildenbrand <david@kernel.org>
+Acked-by: David Hildenbrand (Arm) <david@kernel.org>
+Assisted-by: Claude:claude-fable-5
+Cc: Muchun Song <muchun.song@linux.dev>
+Cc: Oscar Salvador <osalvador@suse.de>
+Cc: Peter Xu <peterx@redhat.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+(cherry picked from commit 83abe2fd5b3aeb3123b5408a5a91709c5538fb23)
+[ kas: adapt to the pre-softleaf idiom ]
+Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/hugetlb.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/mm/hugetlb.c b/mm/hugetlb.c
+index af4533028f62e..edae641407b96 100644
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -5112,8 +5112,12 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
+                        */
+                       ;
+               } else if (unlikely(is_hugetlb_entry_hwpoisoned(entry))) {
+-                      if (!userfaultfd_wp(dst_vma))
+-                              entry = huge_pte_clear_uffd_wp(entry);
++                      /*
++                       * A hwpoison entry never carries the uffd-wp bit: it is
++                       * installed fresh by make_hwpoison_entry() and
++                       * hugetlb_change_protection() leaves it untouched, so
++                       * there is nothing to clear for the child.
++                       */
+                       set_huge_pte_at(dst, addr, dst_pte, entry, sz);
+               } else if (unlikely(is_hugetlb_entry_migration(entry))) {
+                       swp_entry_t swp_entry = pte_to_swp_entry(entry);
+@@ -5132,7 +5136,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
+                               set_huge_pte_at(src, addr, src_pte, entry, sz);
+                       }
+                       if (!userfaultfd_wp(dst_vma))
+-                              entry = huge_pte_clear_uffd_wp(entry);
++                              entry = pte_swp_clear_uffd_wp(entry);
+                       set_huge_pte_at(dst, addr, dst_pte, entry, sz);
+               } else if (unlikely(is_pte_marker(entry))) {
+                       pte_marker marker = copy_pte_marker(
+-- 
+2.53.0
+
index 7d45e9410bba288b71c5ac99b2bcbe1ad669cafa..b286c4f48ecef21a1bdf89d51a65e0df6555c9a6 100644 (file)
@@ -206,3 +206,5 @@ hid-logitech-dj-fix-maxfield-check-in-dj-short-report-validation.patch
 ata-libahci_platform-do-not-set-mask_port_map-when-not-needed.patch
 ata-ahci-make-ahci_ignore_port-handle-empty-mask_port_map.patch
 iommu-sva-move-x86-disable-check-before-allocation.patch
+mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch
+mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch