]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for all trees
authorSasha Levin <sashal@kernel.org>
Sun, 21 Jun 2026 13:47:26 +0000 (09:47 -0400)
committerSasha Levin <sashal@kernel.org>
Sun, 21 Jun 2026 13:47:26 +0000 (09:47 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
28 files changed:
queue-5.10/batman-adv-tt-prevent-tvlv-entry-number-overflow.patch [new file with mode: 0644]
queue-5.10/batman-adv-tt-reject-oversized-local-tvlv-buffers.patch [new file with mode: 0644]
queue-5.10/series
queue-5.10/vfio-iommu_type1-replace-kfree-with-kvfree.patch [new file with mode: 0644]
queue-5.15/batman-adv-tt-prevent-tvlv-entry-number-overflow.patch [new file with mode: 0644]
queue-5.15/batman-adv-tt-reject-oversized-local-tvlv-buffers.patch [new file with mode: 0644]
queue-5.15/iio-light-bh1780-fix-pm-runtime-leak-on-error-path.patch [new file with mode: 0644]
queue-5.15/series
queue-5.15/vfio-iommu_type1-replace-kfree-with-kvfree.patch [new file with mode: 0644]
queue-6.1/batman-adv-tt-prevent-tvlv-entry-number-overflow.patch [new file with mode: 0644]
queue-6.1/kvm-nvmx-add-a-helper-to-get-highest-pending-from-po.patch [new file with mode: 0644]
queue-6.1/kvm-nvmx-check-for-pending-posted-interrupts-when-lo.patch [new file with mode: 0644]
queue-6.1/kvm-nvmx-fold-requested-virtual-interrupt-check-into.patch [new file with mode: 0644]
queue-6.1/series
queue-6.12/eventpoll-drop-vestigial-__-prefix-from-ep_remove_-f.patch [new file with mode: 0644]
queue-6.12/eventpoll-fix-ep_remove-struct-eventpoll-struct-file.patch [new file with mode: 0644]
queue-6.12/eventpoll-kill-__ep_remove.patch [new file with mode: 0644]
queue-6.12/eventpoll-move-epi_fget-up.patch [new file with mode: 0644]
queue-6.12/eventpoll-rename-ep_remove_safe-back-to-ep_remove.patch [new file with mode: 0644]
queue-6.12/eventpoll-split-__ep_remove.patch [new file with mode: 0644]
queue-6.12/eventpoll-use-hlist_is_singular_node-in-__ep_remove.patch [new file with mode: 0644]
queue-6.12/iio-light-bh1780-fix-pm-runtime-leak-on-error-path.patch [new file with mode: 0644]
queue-6.12/net-drop-the-lock-in-skb_may_tx_timestamp.patch [new file with mode: 0644]
queue-6.12/series
queue-6.6/batman-adv-tt-prevent-tvlv-entry-number-overflow.patch [new file with mode: 0644]
queue-6.6/series
queue-7.0/lockd-fix-test-handling-when-not-all-permissions-are.patch [new file with mode: 0644]
queue-7.0/series

diff --git a/queue-5.10/batman-adv-tt-prevent-tvlv-entry-number-overflow.patch b/queue-5.10/batman-adv-tt-prevent-tvlv-entry-number-overflow.patch
new file mode 100644 (file)
index 0000000..3728630
--- /dev/null
@@ -0,0 +1,80 @@
+From 02012aff754be0708a52368a013eb79fdf2e88e1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 22:12:35 +0200
+Subject: batman-adv: tt: prevent TVLV entry number overflow
+
+From: Sven Eckelmann <sven@narfation.org>
+
+commit 99d9958fa10fb684b2a8e2c48a8d704122721420 upstream.
+
+The helpers to prepare the buffers for the local and global TT based
+replies are trying to sum up all TT entries which can be found for each
+VLAN. In theory, this sum can be too big for an u16 and therefore overflow.
+A too small buffer would then be allocated for the TVLV.
+
+The too small buffer will be handled gracefully by
+batadv_tt_tvlv_generate() and is not causing a buffer overflow - just a
+truncated reply. But this overflow shouldn't have happened in the first and
+the too small buffer should never have been allocated when an overflow was
+detected.
+
+Cc: stable@kernel.org
+Fixes: 7ea7b4a14275 ("batman-adv: make the TT CRC logic VLAN specific")
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/batman-adv/translation-table.c | 20 +++++++++++++++++---
+ 1 file changed, 17 insertions(+), 3 deletions(-)
+
+diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
+index fb51088494dcc6..79da90b9cf0659 100644
+--- a/net/batman-adv/translation-table.c
++++ b/net/batman-adv/translation-table.c
+@@ -854,11 +854,18 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
+       u16 total_entries = 0;
+       u8 *tt_change_ptr;
+       int vlan_entries;
++      u16 sum_entries;
+       spin_lock_bh(&orig_node->vlan_list_lock);
+       hlist_for_each_entry(vlan, &orig_node->vlan_list, list) {
+               vlan_entries = atomic_read(&vlan->tt.num_entries);
+-              total_entries += vlan_entries;
++
++              if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) {
++                      *tt_len = 0;
++                      goto out;
++              }
++
++              total_entries = sum_entries;
+               num_vlan++;
+       }
+@@ -945,15 +952,22 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
+       struct batadv_softif_vlan *vlan;
+       size_t change_offset;
+       u16 num_vlan = 0;
+-      u16 vlan_entries = 0;
+       u16 total_entries = 0;
+       u16 tvlv_len;
+       u8 *tt_change_ptr;
++      int vlan_entries;
++      u16 sum_entries;
+       spin_lock_bh(&bat_priv->softif_vlan_list_lock);
+       hlist_for_each_entry(vlan, &bat_priv->softif_vlan_list, list) {
+               vlan_entries = atomic_read(&vlan->tt.num_entries);
+-              total_entries += vlan_entries;
++
++              if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) {
++                      tvlv_len = 0;
++                      goto out;
++              }
++
++              total_entries = sum_entries;
+               num_vlan++;
+       }
+-- 
+2.53.0
+
diff --git a/queue-5.10/batman-adv-tt-reject-oversized-local-tvlv-buffers.patch b/queue-5.10/batman-adv-tt-reject-oversized-local-tvlv-buffers.patch
new file mode 100644 (file)
index 0000000..783b876
--- /dev/null
@@ -0,0 +1,62 @@
+From dfe89e43a6a607759308754aedeab2cd1ee7345e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 22:11:09 +0200
+Subject: batman-adv: tt: reject oversized local TVLV buffers
+
+From: Sven Eckelmann <sven@narfation.org>
+
+commit 1e9fab756f8395096d5bba7be0c373c4c8f5d165 upstream.
+
+The commit 3a359bf5c61d ("batman-adv: reject oversized global TT response
+buffers") added a check to ensure that a global return buffer size can be
+stored in an u16. The same buffer handling also exists for the local data
+buffer but was not touched.
+
+A similar check should be also be in place for the local TVLV buffer. It
+doesn't have the similar attack surface because it is only generated from
+locally discovered MAC addresses but the dynamic nature could still cause
+temporarily to large buffers.
+
+Cc: stable@kernel.org
+Fixes: 7ea7b4a14275 ("batman-adv: make the TT CRC logic VLAN specific")
+[ Context ]
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/batman-adv/translation-table.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
+index fa6dece492d3ab..fb51088494dcc6 100644
+--- a/net/batman-adv/translation-table.c
++++ b/net/batman-adv/translation-table.c
+@@ -943,12 +943,12 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
+ {
+       struct batadv_tvlv_tt_vlan_data *tt_vlan;
+       struct batadv_softif_vlan *vlan;
++      size_t change_offset;
+       u16 num_vlan = 0;
+       u16 vlan_entries = 0;
+       u16 total_entries = 0;
+       u16 tvlv_len;
+       u8 *tt_change_ptr;
+-      int change_offset;
+       spin_lock_bh(&bat_priv->softif_vlan_list_lock);
+       hlist_for_each_entry(vlan, &bat_priv->softif_vlan_list, list) {
+@@ -964,8 +964,10 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
+       if (*tt_len < 0)
+               *tt_len = batadv_tt_len(total_entries);
+-      tvlv_len = *tt_len;
+-      tvlv_len += change_offset;
++      if (check_add_overflow(*tt_len, change_offset, &tvlv_len)) {
++              tvlv_len = 0;
++              goto out;
++      }
+       *tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
+       if (!*tt_data) {
+-- 
+2.53.0
+
index aa62c35b04cacc6ea01fc2598dd224ba0e1494c5..5d89742506878de2e05b65846b96c167e4f488c3 100644 (file)
@@ -16,3 +16,6 @@ net-sched-cls_u32-use-skb_header_pointer_careful.patch
 drm-amd-display-use-krealloc_array-in-dal_vector_res.patch
 net-9p-fix-refcount-leak-in-p9_read_work-error-handl.patch
 netdevsim-fix-memory-leak-of-nsim_dev-fa_cookie.patch
+batman-adv-tt-reject-oversized-local-tvlv-buffers.patch
+batman-adv-tt-prevent-tvlv-entry-number-overflow.patch
+vfio-iommu_type1-replace-kfree-with-kvfree.patch
diff --git a/queue-5.10/vfio-iommu_type1-replace-kfree-with-kvfree.patch b/queue-5.10/vfio-iommu_type1-replace-kfree-with-kvfree.patch
new file mode 100644 (file)
index 0000000..41bd4f3
--- /dev/null
@@ -0,0 +1,38 @@
+From 9c332c79d76eecd1dcb9990ad02370af71cd31e0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 12 Dec 2021 01:16:00 -0800
+Subject: vfio/iommu_type1: replace kfree with kvfree
+
+From: Jiacheng Shi <billsjc@sjtu.edu.cn>
+
+[ Upstream commit 2bed2ced40c97b8540ff38df0149e8ecb2bf4c65 ]
+
+Variables allocated by kvzalloc should not be freed by kfree.
+Because they may be allocated by vmalloc.
+So we replace kfree with kvfree here.
+
+Fixes: d6a4c185660c ("vfio iommu: Implementation of ioctl for dirty pages tracking")
+Signed-off-by: Jiacheng Shi <billsjc@sjtu.edu.cn>
+Link: https://lore.kernel.org/r/20211212091600.2560-1-billsjc@sjtu.edu.cn
+Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vfio/vfio_iommu_type1.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
+index b2a543e7cac454..eee8d2ab03d683 100644
+--- a/drivers/vfio/vfio_iommu_type1.c
++++ b/drivers/vfio/vfio_iommu_type1.c
+@@ -228,7 +228,7 @@ static int vfio_dma_bitmap_alloc(struct vfio_dma *dma, size_t pgsize)
+ static void vfio_dma_bitmap_free(struct vfio_dma *dma)
+ {
+-      kfree(dma->bitmap);
++      kvfree(dma->bitmap);
+       dma->bitmap = NULL;
+ }
+-- 
+2.53.0
+
diff --git a/queue-5.15/batman-adv-tt-prevent-tvlv-entry-number-overflow.patch b/queue-5.15/batman-adv-tt-prevent-tvlv-entry-number-overflow.patch
new file mode 100644 (file)
index 0000000..4059ce7
--- /dev/null
@@ -0,0 +1,80 @@
+From aa89d06a63f2b16e8af824e5775e32b4e8f1b47e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 22:03:23 +0200
+Subject: batman-adv: tt: prevent TVLV entry number overflow
+
+From: Sven Eckelmann <sven@narfation.org>
+
+commit 99d9958fa10fb684b2a8e2c48a8d704122721420 upstream.
+
+The helpers to prepare the buffers for the local and global TT based
+replies are trying to sum up all TT entries which can be found for each
+VLAN. In theory, this sum can be too big for an u16 and therefore overflow.
+A too small buffer would then be allocated for the TVLV.
+
+The too small buffer will be handled gracefully by
+batadv_tt_tvlv_generate() and is not causing a buffer overflow - just a
+truncated reply. But this overflow shouldn't have happened in the first and
+the too small buffer should never have been allocated when an overflow was
+detected.
+
+Cc: stable@kernel.org
+Fixes: 7ea7b4a14275 ("batman-adv: make the TT CRC logic VLAN specific")
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/batman-adv/translation-table.c | 20 +++++++++++++++++---
+ 1 file changed, 17 insertions(+), 3 deletions(-)
+
+diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
+index 3849c348ff0344..8ab1257bade048 100644
+--- a/net/batman-adv/translation-table.c
++++ b/net/batman-adv/translation-table.c
+@@ -850,11 +850,18 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
+       u16 total_entries = 0;
+       u8 *tt_change_ptr;
+       int vlan_entries;
++      u16 sum_entries;
+       spin_lock_bh(&orig_node->vlan_list_lock);
+       hlist_for_each_entry(vlan, &orig_node->vlan_list, list) {
+               vlan_entries = atomic_read(&vlan->tt.num_entries);
+-              total_entries += vlan_entries;
++
++              if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) {
++                      *tt_len = 0;
++                      goto out;
++              }
++
++              total_entries = sum_entries;
+               num_vlan++;
+       }
+@@ -941,15 +948,22 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
+       struct batadv_softif_vlan *vlan;
+       size_t change_offset;
+       u16 num_vlan = 0;
+-      u16 vlan_entries = 0;
+       u16 total_entries = 0;
+       u16 tvlv_len;
+       u8 *tt_change_ptr;
++      int vlan_entries;
++      u16 sum_entries;
+       spin_lock_bh(&bat_priv->softif_vlan_list_lock);
+       hlist_for_each_entry(vlan, &bat_priv->softif_vlan_list, list) {
+               vlan_entries = atomic_read(&vlan->tt.num_entries);
+-              total_entries += vlan_entries;
++
++              if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) {
++                      tvlv_len = 0;
++                      goto out;
++              }
++
++              total_entries = sum_entries;
+               num_vlan++;
+       }
+-- 
+2.53.0
+
diff --git a/queue-5.15/batman-adv-tt-reject-oversized-local-tvlv-buffers.patch b/queue-5.15/batman-adv-tt-reject-oversized-local-tvlv-buffers.patch
new file mode 100644 (file)
index 0000000..8c579dc
--- /dev/null
@@ -0,0 +1,62 @@
+From 8bc28e5a230c15fa77b2f45d49ce0036a1cab9a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 22:02:01 +0200
+Subject: batman-adv: tt: reject oversized local TVLV buffers
+
+From: Sven Eckelmann <sven@narfation.org>
+
+commit 1e9fab756f8395096d5bba7be0c373c4c8f5d165 upstream.
+
+The commit 3a359bf5c61d ("batman-adv: reject oversized global TT response
+buffers") added a check to ensure that a global return buffer size can be
+stored in an u16. The same buffer handling also exists for the local data
+buffer but was not touched.
+
+A similar check should be also be in place for the local TVLV buffer. It
+doesn't have the similar attack surface because it is only generated from
+locally discovered MAC addresses but the dynamic nature could still cause
+temporarily to large buffers.
+
+Cc: stable@kernel.org
+Fixes: 7ea7b4a14275 ("batman-adv: make the TT CRC logic VLAN specific")
+[ Context ]
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/batman-adv/translation-table.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
+index e4d55b27f2551b..3849c348ff0344 100644
+--- a/net/batman-adv/translation-table.c
++++ b/net/batman-adv/translation-table.c
+@@ -939,12 +939,12 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
+ {
+       struct batadv_tvlv_tt_vlan_data *tt_vlan;
+       struct batadv_softif_vlan *vlan;
++      size_t change_offset;
+       u16 num_vlan = 0;
+       u16 vlan_entries = 0;
+       u16 total_entries = 0;
+       u16 tvlv_len;
+       u8 *tt_change_ptr;
+-      int change_offset;
+       spin_lock_bh(&bat_priv->softif_vlan_list_lock);
+       hlist_for_each_entry(vlan, &bat_priv->softif_vlan_list, list) {
+@@ -960,8 +960,10 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
+       if (*tt_len < 0)
+               *tt_len = batadv_tt_len(total_entries);
+-      tvlv_len = *tt_len;
+-      tvlv_len += change_offset;
++      if (check_add_overflow(*tt_len, change_offset, &tvlv_len)) {
++              tvlv_len = 0;
++              goto out;
++      }
+       *tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
+       if (!*tt_data) {
+-- 
+2.53.0
+
diff --git a/queue-5.15/iio-light-bh1780-fix-pm-runtime-leak-on-error-path.patch b/queue-5.15/iio-light-bh1780-fix-pm-runtime-leak-on-error-path.patch
new file mode 100644 (file)
index 0000000..9c15750
--- /dev/null
@@ -0,0 +1,48 @@
+From 39e0a0b4e6be4402b29ce0b4f88a79a9aaa709f3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jun 2026 17:34:43 +0300
+Subject: iio: light: bh1780: fix PM runtime leak on error path
+
+From: Antoniu Miclaus <antoniu.miclaus@analog.com>
+
+commit dd72e6c3cdea05cad24e99710939086f7a113fb5 upstream.
+
+Move pm_runtime_put_autosuspend() before the error check to ensure
+the PM runtime reference count is always decremented after
+pm_runtime_get_sync(), regardless of whether the read operation
+succeeds or fails.
+
+Fixes: 1f0477f18306 ("iio: light: new driver for the ROHM BH1780")
+Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
+Reviewed-by: Linus Walleij <linusw@kernel.org>
+Cc: <Stable@vger.kernel.org>
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+[ moved both pm_runtime_mark_last_busy() and pm_runtime_put_autosuspend() before the error check instead of just pm_runtime_put_autosuspend() ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Elizaveta Tereshkina <etereshkina@astralinux.ru>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/light/bh1780.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c
+index abbf2e662e7dbc..e0a72ff2ebf8b1 100644
+--- a/drivers/iio/light/bh1780.c
++++ b/drivers/iio/light/bh1780.c
+@@ -109,10 +109,10 @@ static int bh1780_read_raw(struct iio_dev *indio_dev,
+               case IIO_LIGHT:
+                       pm_runtime_get_sync(&bh1780->client->dev);
+                       value = bh1780_read_word(bh1780, BH1780_REG_DLOW);
+-                      if (value < 0)
+-                              return value;
+                       pm_runtime_mark_last_busy(&bh1780->client->dev);
+                       pm_runtime_put_autosuspend(&bh1780->client->dev);
++                      if (value < 0)
++                              return value;
+                       *val = value;
+                       return IIO_VAL_INT;
+-- 
+2.53.0
+
index eb8c43450920504b87e613006bcc1d788d8827e5..46ff72676817128d3dfd8079cbcdd150207b8ca3 100644 (file)
@@ -7,3 +7,7 @@ drm-amd-display-bound-vbios-record-chain-walk-loops.patch
 ip6_vti-set-netns_immutable-on-the-fallback-device.patch
 drm-v3d-store-the-active-job-inside-the-queue-s-stat.patch
 drm-v3d-skip-csd-when-it-has-zeroed-workgroups.patch
+batman-adv-tt-reject-oversized-local-tvlv-buffers.patch
+batman-adv-tt-prevent-tvlv-entry-number-overflow.patch
+iio-light-bh1780-fix-pm-runtime-leak-on-error-path.patch
+vfio-iommu_type1-replace-kfree-with-kvfree.patch
diff --git a/queue-5.15/vfio-iommu_type1-replace-kfree-with-kvfree.patch b/queue-5.15/vfio-iommu_type1-replace-kfree-with-kvfree.patch
new file mode 100644 (file)
index 0000000..af6dd26
--- /dev/null
@@ -0,0 +1,38 @@
+From 9641c9aebf8835b18240983f810a8b5af2ac2bf2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 12 Dec 2021 01:16:00 -0800
+Subject: vfio/iommu_type1: replace kfree with kvfree
+
+From: Jiacheng Shi <billsjc@sjtu.edu.cn>
+
+[ Upstream commit 2bed2ced40c97b8540ff38df0149e8ecb2bf4c65 ]
+
+Variables allocated by kvzalloc should not be freed by kfree.
+Because they may be allocated by vmalloc.
+So we replace kfree with kvfree here.
+
+Fixes: d6a4c185660c ("vfio iommu: Implementation of ioctl for dirty pages tracking")
+Signed-off-by: Jiacheng Shi <billsjc@sjtu.edu.cn>
+Link: https://lore.kernel.org/r/20211212091600.2560-1-billsjc@sjtu.edu.cn
+Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vfio/vfio_iommu_type1.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
+index 6a89bbec738f62..2bc79eee63d524 100644
+--- a/drivers/vfio/vfio_iommu_type1.c
++++ b/drivers/vfio/vfio_iommu_type1.c
+@@ -262,7 +262,7 @@ static int vfio_dma_bitmap_alloc(struct vfio_dma *dma, size_t pgsize)
+ static void vfio_dma_bitmap_free(struct vfio_dma *dma)
+ {
+-      kfree(dma->bitmap);
++      kvfree(dma->bitmap);
+       dma->bitmap = NULL;
+ }
+-- 
+2.53.0
+
diff --git a/queue-6.1/batman-adv-tt-prevent-tvlv-entry-number-overflow.patch b/queue-6.1/batman-adv-tt-prevent-tvlv-entry-number-overflow.patch
new file mode 100644 (file)
index 0000000..f0cfb1f
--- /dev/null
@@ -0,0 +1,80 @@
+From 645cecb9c727b252ce4ae685f7fb45b1103e5596 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 21:45:29 +0200
+Subject: batman-adv: tt: prevent TVLV entry number overflow
+
+From: Sven Eckelmann <sven@narfation.org>
+
+commit 99d9958fa10fb684b2a8e2c48a8d704122721420 upstream.
+
+The helpers to prepare the buffers for the local and global TT based
+replies are trying to sum up all TT entries which can be found for each
+VLAN. In theory, this sum can be too big for an u16 and therefore overflow.
+A too small buffer would then be allocated for the TVLV.
+
+The too small buffer will be handled gracefully by
+batadv_tt_tvlv_generate() and is not causing a buffer overflow - just a
+truncated reply. But this overflow shouldn't have happened in the first and
+the too small buffer should never have been allocated when an overflow was
+detected.
+
+Cc: stable@kernel.org
+Fixes: 7ea7b4a14275 ("batman-adv: make the TT CRC logic VLAN specific")
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/batman-adv/translation-table.c | 20 +++++++++++++++++---
+ 1 file changed, 17 insertions(+), 3 deletions(-)
+
+diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
+index e0503c8f24c353..53d2aadcafa154 100644
+--- a/net/batman-adv/translation-table.c
++++ b/net/batman-adv/translation-table.c
+@@ -850,11 +850,18 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
+       u16 total_entries = 0;
+       u8 *tt_change_ptr;
+       int vlan_entries;
++      u16 sum_entries;
+       spin_lock_bh(&orig_node->vlan_list_lock);
+       hlist_for_each_entry(vlan, &orig_node->vlan_list, list) {
+               vlan_entries = atomic_read(&vlan->tt.num_entries);
+-              total_entries += vlan_entries;
++
++              if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) {
++                      *tt_len = 0;
++                      goto out;
++              }
++
++              total_entries = sum_entries;
+               num_vlan++;
+       }
+@@ -941,15 +948,22 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
+       struct batadv_softif_vlan *vlan;
+       size_t change_offset;
+       u16 num_vlan = 0;
+-      u16 vlan_entries = 0;
+       u16 total_entries = 0;
+       u16 tvlv_len;
+       u8 *tt_change_ptr;
++      int vlan_entries;
++      u16 sum_entries;
+       spin_lock_bh(&bat_priv->softif_vlan_list_lock);
+       hlist_for_each_entry(vlan, &bat_priv->softif_vlan_list, list) {
+               vlan_entries = atomic_read(&vlan->tt.num_entries);
+-              total_entries += vlan_entries;
++
++              if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) {
++                      tvlv_len = 0;
++                      goto out;
++              }
++
++              total_entries = sum_entries;
+               num_vlan++;
+       }
+-- 
+2.53.0
+
diff --git a/queue-6.1/kvm-nvmx-add-a-helper-to-get-highest-pending-from-po.patch b/queue-6.1/kvm-nvmx-add-a-helper-to-get-highest-pending-from-po.patch
new file mode 100644 (file)
index 0000000..a974c0d
--- /dev/null
@@ -0,0 +1,85 @@
+From 4d698ca25b014b21734bb6df02bf16b7e4b9adfa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jun 2026 16:31:05 -0400
+Subject: KVM: nVMX: Add a helper to get highest pending from Posted Interrupt
+ vector
+
+From: Sean Christopherson <seanjc@google.com>
+
+commit d83c36d822be44db4bad0c43bea99c8908f54117 upstream.
+
+Add a helper to retrieve the highest pending vector given a Posted
+Interrupt descriptor.  While the actual operation is straightforward, it's
+surprisingly easy to mess up, e.g. if one tries to reuse lapic.c's
+find_highest_vector(), which doesn't work with PID.PIR due to the APIC's
+IRR and ISR component registers being physically discontiguous (they're
+4-byte registers aligned at 16-byte intervals).
+
+To make PIR handling more consistent with respect to IRR and ISR handling,
+return -1 to indicate "no interrupt pending".
+
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20240607172609.3205077-2-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+[ Nicholas Dudar: backport to 6.1.y. 6.1.y defines struct pi_desc in
+  posted_intr.h and predates the move to <asm/posted_intr.h>, so the helper
+  and the <linux/find.h> include go in posted_intr.h. ]
+Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kvm/vmx/nested.c      |  5 +++--
+ arch/x86/kvm/vmx/posted_intr.h | 10 ++++++++++
+ 2 files changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
+index bdc462944cb082..7d8e18dbe8531b 100644
+--- a/arch/x86/kvm/vmx/nested.c
++++ b/arch/x86/kvm/vmx/nested.c
+@@ -12,6 +12,7 @@
+ #include "mmu.h"
+ #include "nested.h"
+ #include "pmu.h"
++#include "posted_intr.h"
+ #include "sgx.h"
+ #include "trace.h"
+ #include "vmx.h"
+@@ -3818,8 +3819,8 @@ static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
+       if (!pi_test_and_clear_on(vmx->nested.pi_desc))
+               return 0;
+-      max_irr = find_last_bit((unsigned long *)vmx->nested.pi_desc->pir, 256);
+-      if (max_irr != 256) {
++      max_irr = pi_find_highest_vector(vmx->nested.pi_desc);
++      if (max_irr > 0) {
+               vapic_page = vmx->nested.virtual_apic_map.hva;
+               if (!vapic_page)
+                       goto mmio_needed;
+diff --git a/arch/x86/kvm/vmx/posted_intr.h b/arch/x86/kvm/vmx/posted_intr.h
+index 26992076552ef1..88cea0dac7204b 100644
+--- a/arch/x86/kvm/vmx/posted_intr.h
++++ b/arch/x86/kvm/vmx/posted_intr.h
+@@ -2,6 +2,8 @@
+ #ifndef __KVM_X86_VMX_POSTED_INTR_H
+ #define __KVM_X86_VMX_POSTED_INTR_H
++#include <linux/find.h>
++
+ #define POSTED_INTR_ON  0
+ #define POSTED_INTR_SN  1
+@@ -103,4 +105,12 @@ int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq,
+                      uint32_t guest_irq, bool set);
+ void vmx_pi_start_assignment(struct kvm *kvm);
++static inline int pi_find_highest_vector(struct pi_desc *pi_desc)
++{
++      int vec;
++
++      vec = find_last_bit((unsigned long *)pi_desc->pir, 256);
++      return vec < 256 ? vec : -1;
++}
++
+ #endif /* __KVM_X86_VMX_POSTED_INTR_H */
+-- 
+2.53.0
+
diff --git a/queue-6.1/kvm-nvmx-check-for-pending-posted-interrupts-when-lo.patch b/queue-6.1/kvm-nvmx-check-for-pending-posted-interrupts-when-lo.patch
new file mode 100644 (file)
index 0000000..71aba5b
--- /dev/null
@@ -0,0 +1,86 @@
+From a17c10283ca19ad7d0a629310f8e27d80f2ec122 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jun 2026 16:31:06 -0400
+Subject: KVM: nVMX: Check for pending posted interrupts when looking for
+ nested events
+
+From: Sean Christopherson <seanjc@google.com>
+
+commit 27c4fa42b11af780d49ce704f7fa67b3c2544df4 upstream.
+
+Check for pending (and notified!) posted interrupts when checking if L2
+has a pending wake event, as fully posted/notified virtual interrupt is a
+valid wake event for HLT.
+
+Note that KVM must check vmx->nested.pi_pending to avoid prematurely
+waking L2, e.g. even if KVM sees a non-zero PID.PIR and PID.0N=1, the
+virtual interrupt won't actually be recognized until a notification IRQ is
+received by the vCPU or the vCPU does (nested) VM-Enter.
+
+Fixes: 26844fee6ade ("KVM: x86: never write to memory from kvm_vcpu_check_block()")
+Cc: stable@vger.kernel.org
+Cc: Maxim Levitsky <mlevitsk@redhat.com>
+Reported-by: Jim Mattson <jmattson@google.com>
+Closes: https://lore.kernel.org/all/20231207010302.2240506-1-jmattson@google.com
+Link: https://lore.kernel.org/r/20240607172609.3205077-5-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+[ Nicholas Dudar: backport to 6.1.y. Prerequisite for the next patch, which
+  folds its check into the vmx_has_nested_events() body this patch builds.
+  Applies cleanly. The for_injection path still returns preemption_timer ||
+  mtf, as the previous 6.1.y body did. ]
+Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kvm/vmx/nested.c | 36 ++++++++++++++++++++++++++++++++++--
+ 1 file changed, 34 insertions(+), 2 deletions(-)
+
+diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
+index 7d8e18dbe8531b..ad07e83d2c1d5b 100644
+--- a/arch/x86/kvm/vmx/nested.c
++++ b/arch/x86/kvm/vmx/nested.c
+@@ -3953,8 +3953,40 @@ static bool nested_vmx_preemption_timer_pending(struct kvm_vcpu *vcpu)
+ static bool vmx_has_nested_events(struct kvm_vcpu *vcpu, bool for_injection)
+ {
+-      return nested_vmx_preemption_timer_pending(vcpu) ||
+-             to_vmx(vcpu)->nested.mtf_pending;
++      struct vcpu_vmx *vmx = to_vmx(vcpu);
++      void *vapic = vmx->nested.virtual_apic_map.hva;
++      int max_irr, vppr;
++
++      if (nested_vmx_preemption_timer_pending(vcpu) ||
++          vmx->nested.mtf_pending)
++              return true;
++
++      /*
++       * Virtual Interrupt Delivery doesn't require manual injection.  Either
++       * the interrupt is already in GUEST_RVI and will be recognized by CPU
++       * at VM-Entry, or there is a KVM_REQ_EVENT pending and KVM will move
++       * the interrupt from the PIR to RVI prior to entering the guest.
++       */
++      if (for_injection)
++              return false;
++
++      if (!nested_cpu_has_vid(get_vmcs12(vcpu)) ||
++          __vmx_interrupt_blocked(vcpu))
++              return false;
++
++      if (!vapic)
++              return false;
++
++      vppr = *((u32 *)(vapic + APIC_PROCPRI));
++
++      if (vmx->nested.pi_pending && vmx->nested.pi_desc &&
++          pi_test_on(vmx->nested.pi_desc)) {
++              max_irr = pi_find_highest_vector(vmx->nested.pi_desc);
++              if (max_irr > 0 && (max_irr & 0xf0) > (vppr & 0xf0))
++                      return true;
++      }
++
++      return false;
+ }
+ /*
+-- 
+2.53.0
+
diff --git a/queue-6.1/kvm-nvmx-fold-requested-virtual-interrupt-check-into.patch b/queue-6.1/kvm-nvmx-fold-requested-virtual-interrupt-check-into.patch
new file mode 100644 (file)
index 0000000..b1ef12a
--- /dev/null
@@ -0,0 +1,148 @@
+From 92d8cc54210672204f960849fc948f3614ea8702 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jun 2026 16:31:07 -0400
+Subject: KVM: nVMX: Fold requested virtual interrupt check into
+ has_nested_events()
+
+From: Sean Christopherson <seanjc@google.com>
+
+commit 321ef62b0c5f6f57bb8500a2ca5986052675abbf upstream.
+
+Check for a Requested Virtual Interrupt, i.e. a virtual interrupt that is
+pending delivery, in vmx_has_nested_events() and drop the one-off
+kvm_x86_ops.guest_apic_has_interrupt() hook.
+
+In addition to dropping a superfluous hook, this fixes a bug where KVM
+would incorrectly treat virtual interrupts _for L2_ as always enabled due
+to kvm_arch_interrupt_allowed(), by way of vmx_interrupt_blocked(),
+treating IRQs as enabled if L2 is active and vmcs12 is configured to exit
+on IRQs, i.e. KVM would treat a virtual interrupt for L2 as a valid wake
+event based on L1's IRQ blocking status.
+
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20240607172609.3205077-6-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+[ Nicholas Dudar: backport to 6.1.y. 6.1.y predates the vmx main.c /
+  x86_ops.h split, so drop .guest_apic_has_interrupt from vmx_x86_ops in
+  vmx.c rather than vt_x86_ops in main.c. The function is static in vmx.c, so
+  upstream's x86_ops.h prototype removal does not apply. 6.1.y keeps the
+  current hwapic_isr_update signature. ]
+Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/kvm-x86-ops.h |  1 -
+ arch/x86/include/asm/kvm_host.h    |  1 -
+ arch/x86/kvm/vmx/nested.c          |  4 ++++
+ arch/x86/kvm/vmx/vmx.c             | 21 ---------------------
+ arch/x86/kvm/x86.c                 | 10 +---------
+ 5 files changed, 5 insertions(+), 32 deletions(-)
+
+diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h
+index c068565fe95474..1cfe83263b213b 100644
+--- a/arch/x86/include/asm/kvm-x86-ops.h
++++ b/arch/x86/include/asm/kvm-x86-ops.h
+@@ -81,7 +81,6 @@ KVM_X86_OP(check_apicv_inhibit_reasons)
+ KVM_X86_OP(refresh_apicv_exec_ctrl)
+ KVM_X86_OP_OPTIONAL(hwapic_irr_update)
+ KVM_X86_OP_OPTIONAL(hwapic_isr_update)
+-KVM_X86_OP_OPTIONAL_RET0(guest_apic_has_interrupt)
+ KVM_X86_OP_OPTIONAL(load_eoi_exitmap)
+ KVM_X86_OP_OPTIONAL(set_virtual_apic_mode)
+ KVM_X86_OP_OPTIONAL(set_apic_access_page_addr)
+diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
+index fe5c0f86ae389d..31395c43416dd7 100644
+--- a/arch/x86/include/asm/kvm_host.h
++++ b/arch/x86/include/asm/kvm_host.h
+@@ -1549,7 +1549,6 @@ struct kvm_x86_ops {
+       void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu);
+       void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr);
+       void (*hwapic_isr_update)(struct kvm_vcpu *vcpu, int isr);
+-      bool (*guest_apic_has_interrupt)(struct kvm_vcpu *vcpu);
+       void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
+       void (*set_virtual_apic_mode)(struct kvm_vcpu *vcpu);
+       void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu);
+diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
+index ad07e83d2c1d5b..f7a790a28b9eee 100644
+--- a/arch/x86/kvm/vmx/nested.c
++++ b/arch/x86/kvm/vmx/nested.c
+@@ -3979,6 +3979,10 @@ static bool vmx_has_nested_events(struct kvm_vcpu *vcpu, bool for_injection)
+       vppr = *((u32 *)(vapic + APIC_PROCPRI));
++      max_irr = vmx_get_rvi();
++      if ((max_irr & 0xf0) > (vppr & 0xf0))
++              return true;
++
+       if (vmx->nested.pi_pending && vmx->nested.pi_desc &&
+           pi_test_on(vmx->nested.pi_desc)) {
+               max_irr = pi_find_highest_vector(vmx->nested.pi_desc);
+diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
+index e5d162e97f5031..2e6454e4cca4b4 100644
+--- a/arch/x86/kvm/vmx/vmx.c
++++ b/arch/x86/kvm/vmx/vmx.c
+@@ -4063,26 +4063,6 @@ void pt_update_intercept_for_msr(struct kvm_vcpu *vcpu)
+       }
+ }
+-static bool vmx_guest_apic_has_interrupt(struct kvm_vcpu *vcpu)
+-{
+-      struct vcpu_vmx *vmx = to_vmx(vcpu);
+-      void *vapic_page;
+-      u32 vppr;
+-      int rvi;
+-
+-      if (WARN_ON_ONCE(!is_guest_mode(vcpu)) ||
+-              !nested_cpu_has_vid(get_vmcs12(vcpu)) ||
+-              WARN_ON_ONCE(!vmx->nested.virtual_apic_map.gfn))
+-              return false;
+-
+-      rvi = vmx_get_rvi();
+-
+-      vapic_page = vmx->nested.virtual_apic_map.hva;
+-      vppr = *((u32 *)(vapic_page + APIC_PROCPRI));
+-
+-      return ((rvi & 0xf0) > (vppr & 0xf0));
+-}
+-
+ static void vmx_msr_filter_changed(struct kvm_vcpu *vcpu)
+ {
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+@@ -8266,7 +8246,6 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
+       .check_apicv_inhibit_reasons = vmx_check_apicv_inhibit_reasons,
+       .hwapic_irr_update = vmx_hwapic_irr_update,
+       .hwapic_isr_update = vmx_hwapic_isr_update,
+-      .guest_apic_has_interrupt = vmx_guest_apic_has_interrupt,
+       .sync_pir_to_irr = vmx_sync_pir_to_irr,
+       .deliver_interrupt = vmx_deliver_interrupt,
+       .dy_apicv_has_pending_interrupt = pi_has_pending_interrupt,
+diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
+index 10ef8a4353b32e..208a713d7ecd75 100644
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -13046,12 +13046,6 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
+       kvm_page_track_flush_slot(kvm, slot);
+ }
+-static inline bool kvm_guest_apic_has_interrupt(struct kvm_vcpu *vcpu)
+-{
+-      return (is_guest_mode(vcpu) &&
+-              static_call(kvm_x86_guest_apic_has_interrupt)(vcpu));
+-}
+-
+ static inline bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu)
+ {
+       if (!list_empty_careful(&vcpu->async_pf.done))
+@@ -13077,9 +13071,7 @@ static inline bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu)
+            static_call(kvm_x86_smi_allowed)(vcpu, false)))
+               return true;
+-      if (kvm_arch_interrupt_allowed(vcpu) &&
+-          (kvm_cpu_has_interrupt(vcpu) ||
+-          kvm_guest_apic_has_interrupt(vcpu)))
++      if (kvm_arch_interrupt_allowed(vcpu) && kvm_cpu_has_interrupt(vcpu))
+               return true;
+       if (kvm_hv_has_stimer_pending(vcpu))
+-- 
+2.53.0
+
index 33d9e82774e693e885f214c4e58ff066c1430cc7..b64168d7f740475b6155a8a532d398ccbaa83232 100644 (file)
@@ -14,3 +14,7 @@ selftests-bpf-move-get_time_ns-to-testing_helpers.h.patch
 selftests-bpf-check-for-timeout-in-perf_link-test.patch
 drm-v3d-store-the-active-job-inside-the-queue-s-stat.patch
 drm-v3d-skip-csd-when-it-has-zeroed-workgroups.patch
+batman-adv-tt-prevent-tvlv-entry-number-overflow.patch
+kvm-nvmx-add-a-helper-to-get-highest-pending-from-po.patch
+kvm-nvmx-check-for-pending-posted-interrupts-when-lo.patch
+kvm-nvmx-fold-requested-virtual-interrupt-check-into.patch
diff --git a/queue-6.12/eventpoll-drop-vestigial-__-prefix-from-ep_remove_-f.patch b/queue-6.12/eventpoll-drop-vestigial-__-prefix-from-ep_remove_-f.patch
new file mode 100644 (file)
index 0000000..bb271bf
--- /dev/null
@@ -0,0 +1,70 @@
+From 851deb0057ba0b1d96a60ebecc260e2696b3a840 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jun 2026 16:58:44 +0200
+Subject: eventpoll: drop vestigial __ prefix from ep_remove_{file,epi}()
+
+From: Christian Brauner <brauner@kernel.org>
+
+[ Upstream commit 0feaf644f7180c4a91b6b405a881afbfd958f1cf ]
+
+With __ep_remove() gone, the double-underscore on __ep_remove_file()
+and __ep_remove_epi() no longer contrasts with a __-less parent and
+just reads as noise. Rename both to ep_remove_file() and
+ep_remove_epi(). No functional change.
+
+Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
+Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
+Signed-off-by: Quentin Schulz <quentin.schulz@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/eventpoll.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/fs/eventpoll.c b/fs/eventpoll.c
+index 3ac8a26c3522f6..dc747f382dd954 100644
+--- a/fs/eventpoll.c
++++ b/fs/eventpoll.c
+@@ -801,7 +801,7 @@ static void ep_free(struct eventpoll *ep)
+  * Called with &file->f_lock held,
+  * returns with it released
+  */
+-static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi,
++static void ep_remove_file(struct eventpoll *ep, struct epitem *epi,
+                            struct file *file)
+ {
+       struct epitems_head *to_free = NULL;
+@@ -825,7 +825,7 @@ static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi,
+       free_ephead(to_free);
+ }
+-static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
++static bool ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
+ {
+       lockdep_assert_held(&ep->mtx);
+@@ -871,9 +871,9 @@ static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi)
+               spin_unlock(&file->f_lock);
+               return;
+       }
+-      __ep_remove_file(ep, epi, file);
++      ep_remove_file(ep, epi, file);
+-      if (__ep_remove_epi(ep, epi))
++      if (ep_remove_epi(ep, epi))
+               WARN_ON_ONCE(ep_refcount_dec_and_test(ep));
+ }
+@@ -1118,8 +1118,8 @@ void eventpoll_release_file(struct file *file)
+               ep_unregister_pollwait(ep, epi);
+               spin_lock(&file->f_lock);
+-              __ep_remove_file(ep, epi, file);
+-              dispose = __ep_remove_epi(ep, epi);
++              ep_remove_file(ep, epi, file);
++              dispose = ep_remove_epi(ep, epi);
+               mutex_unlock(&ep->mtx);
+-- 
+2.53.0
+
diff --git a/queue-6.12/eventpoll-fix-ep_remove-struct-eventpoll-struct-file.patch b/queue-6.12/eventpoll-fix-ep_remove-struct-eventpoll-struct-file.patch
new file mode 100644 (file)
index 0000000..48c0ac0
--- /dev/null
@@ -0,0 +1,100 @@
+From 381447b51758bdc1f73a47bb030a8097d5d41077 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jun 2026 16:58:47 +0200
+Subject: eventpoll: fix ep_remove struct eventpoll / struct file UAF
+
+From: Christian Brauner <brauner@kernel.org>
+
+[ Upstream commit a6dc643c69311677c574a0f17a3f4d66a5f3744b ]
+
+ep_remove() (via ep_remove_file()) cleared file->f_ep under
+file->f_lock but then kept using @file inside the critical section
+(is_file_epoll(), hlist_del_rcu() through the head, spin_unlock).
+A concurrent __fput() taking the eventpoll_release() fastpath in
+that window observed the transient NULL, skipped
+eventpoll_release_file() and ran to f_op->release / file_free().
+
+For the epoll-watches-epoll case, f_op->release is
+ep_eventpoll_release() -> ep_clear_and_put() -> ep_free(), which
+kfree()s the watched struct eventpoll. Its embedded ->refs
+hlist_head is exactly where epi->fllink.pprev points, so the
+subsequent hlist_del_rcu()'s "*pprev = next" scribbles into freed
+kmalloc-192 memory.
+
+In addition, struct file is SLAB_TYPESAFE_BY_RCU, so the slot
+backing @file could be recycled by alloc_empty_file() --
+reinitializing f_lock and f_ep -- while ep_remove() is still
+nominally inside that lock. The upshot is an attacker-controllable
+kmem_cache_free() against the wrong slab cache.
+
+Pin @file via epi_fget() at the top of ep_remove() and gate the
+critical section on the pin succeeding. With the pin held @file
+cannot reach refcount zero, which holds __fput() off and
+transitively keeps the watched struct eventpoll alive across the
+hlist_del_rcu() and the f_lock use, closing both UAFs.
+
+If the pin fails @file has already reached refcount zero and its
+__fput() is in flight. Because we bailed before clearing f_ep,
+that path takes the eventpoll_release() slow path into
+eventpoll_release_file() and blocks on ep->mtx until the waiter
+side's ep_clear_and_put() drops it. The bailed epi's share of
+ep->refcount stays intact, so the trailing ep_refcount_dec_and_test()
+in ep_clear_and_put() cannot free the eventpoll out from under
+eventpoll_release_file(); the orphaned epi is then cleaned up
+there.
+
+A successful pin also proves we are not racing
+eventpoll_release_file() on this epi, so drop the now-redundant
+re-check of epi->dying under f_lock. The cheap lockless
+READ_ONCE(epi->dying) fast-path bailout stays.
+
+Fixes: 58c9b016e128 ("epoll: use refcount to reduce ep_mutex contention")
+Reported-by: Jaeyoung Chung <jjy600901@snu.ac.kr>
+Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-6-2470f9eec0f5@kernel.org
+Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
+Signed-off-by: Quentin Schulz <quentin.schulz@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/eventpoll.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/fs/eventpoll.c b/fs/eventpoll.c
+index 2993b76c21f682..22605fbc12ded5 100644
+--- a/fs/eventpoll.c
++++ b/fs/eventpoll.c
+@@ -883,22 +883,26 @@ static bool ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
+  */
+ static void ep_remove(struct eventpoll *ep, struct epitem *epi)
+ {
+-      struct file *file = epi->ffd.file;
++      struct file *file __free(fput) = NULL;
+       lockdep_assert_irqs_enabled();
+       lockdep_assert_held(&ep->mtx);
+       ep_unregister_pollwait(ep, epi);
+-      /* sync with eventpoll_release_file() */
++      /* cheap sync with eventpoll_release_file() */
+       if (unlikely(READ_ONCE(epi->dying)))
+               return;
+-      spin_lock(&file->f_lock);
+-      if (epi->dying) {
+-              spin_unlock(&file->f_lock);
++      /*
++       * If we manage to grab a reference it means we're not in
++       * eventpoll_release_file() and aren't going to be.
++       */
++      file = epi_fget(epi);
++      if (!file)
+               return;
+-      }
++
++      spin_lock(&file->f_lock);
+       ep_remove_file(ep, epi, file);
+       if (ep_remove_epi(ep, epi))
+-- 
+2.53.0
+
diff --git a/queue-6.12/eventpoll-kill-__ep_remove.patch b/queue-6.12/eventpoll-kill-__ep_remove.patch
new file mode 100644 (file)
index 0000000..c8cafbf
--- /dev/null
@@ -0,0 +1,133 @@
+From 51131e558347cdc5cf60f668ec3e6c2a5cfb73f4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jun 2026 16:58:43 +0200
+Subject: eventpoll: kill __ep_remove()
+
+From: Christian Brauner <brauner@kernel.org>
+
+[ Upstream commit e9e5cd40d7c403e19f21d0f7b8b8ba3a76b58330 ]
+
+Remove the boolean conditional in __ep_remove() and restructure the code
+so the check for racing with eventpoll_release_file() are only done in
+the ep_remove_safe() path where they belong.
+
+Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-3-2470f9eec0f5@kernel.org
+Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
+Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
+Signed-off-by: Quentin Schulz <quentin.schulz@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/eventpoll.c | 67 ++++++++++++++++++++++----------------------------
+ 1 file changed, 30 insertions(+), 37 deletions(-)
+
+diff --git a/fs/eventpoll.c b/fs/eventpoll.c
+index 1cba4ae4a076bc..3ac8a26c3522f6 100644
+--- a/fs/eventpoll.c
++++ b/fs/eventpoll.c
+@@ -797,49 +797,18 @@ static void ep_free(struct eventpoll *ep)
+       kfree_rcu(ep, rcu);
+ }
+-static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file);
+-static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi);
+-
+-/*
+- * Removes a "struct epitem" from the eventpoll RB tree and deallocates
+- * all the associated resources. Must be called with "mtx" held.
+- * If the dying flag is set, do the removal only if force is true.
+- * This prevents ep_clear_and_put() from dropping all the ep references
+- * while running concurrently with eventpoll_release_file().
+- * Returns true if the eventpoll can be disposed.
+- */
+-static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
+-{
+-      struct file *file = epi->ffd.file;
+-
+-      lockdep_assert_irqs_enabled();
+-
+-      /*
+-       * Removes poll wait queue hooks.
+-       */
+-      ep_unregister_pollwait(ep, epi);
+-
+-      /* Remove the current item from the list of epoll hooks */
+-      spin_lock(&file->f_lock);
+-      if (epi->dying && !force) {
+-              spin_unlock(&file->f_lock);
+-              return false;
+-      }
+-
+-      __ep_remove_file(ep, epi, file);
+-      return __ep_remove_epi(ep, epi);
+-}
+-
+ /*
+  * Called with &file->f_lock held,
+  * returns with it released
+  */
+-static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file)
++static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi,
++                           struct file *file)
+ {
+       struct epitems_head *to_free = NULL;
+       struct hlist_head *head = file->f_ep;
+       lockdep_assert_held(&ep->mtx);
++      lockdep_assert_held(&file->f_lock);
+       if (hlist_is_singular_node(&epi->fllink, head)) {
+               /* See eventpoll_release() for details. */
+@@ -886,7 +855,25 @@ static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
+  */
+ static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi)
+ {
+-      if (__ep_remove(ep, epi, false))
++      struct file *file = epi->ffd.file;
++
++      lockdep_assert_irqs_enabled();
++      lockdep_assert_held(&ep->mtx);
++
++      ep_unregister_pollwait(ep, epi);
++
++      /* sync with eventpoll_release_file() */
++      if (unlikely(READ_ONCE(epi->dying)))
++              return;
++
++      spin_lock(&file->f_lock);
++      if (epi->dying) {
++              spin_unlock(&file->f_lock);
++              return;
++      }
++      __ep_remove_file(ep, epi, file);
++
++      if (__ep_remove_epi(ep, epi))
+               WARN_ON_ONCE(ep_refcount_dec_and_test(ep));
+ }
+@@ -1118,7 +1105,7 @@ void eventpoll_release_file(struct file *file)
+       spin_lock(&file->f_lock);
+       if (file->f_ep && file->f_ep->first) {
+               epi = hlist_entry(file->f_ep->first, struct epitem, fllink);
+-              epi->dying = true;
++              WRITE_ONCE(epi->dying, true);
+               spin_unlock(&file->f_lock);
+               /*
+@@ -1127,7 +1114,13 @@ void eventpoll_release_file(struct file *file)
+                */
+               ep = epi->ep;
+               mutex_lock(&ep->mtx);
+-              dispose = __ep_remove(ep, epi, true);
++
++              ep_unregister_pollwait(ep, epi);
++
++              spin_lock(&file->f_lock);
++              __ep_remove_file(ep, epi, file);
++              dispose = __ep_remove_epi(ep, epi);
++
+               mutex_unlock(&ep->mtx);
+               if (dispose && ep_refcount_dec_and_test(ep))
+-- 
+2.53.0
+
diff --git a/queue-6.12/eventpoll-move-epi_fget-up.patch b/queue-6.12/eventpoll-move-epi_fget-up.patch
new file mode 100644 (file)
index 0000000..1e66f57
--- /dev/null
@@ -0,0 +1,101 @@
+From 9e9cee9f453d44ebed0952904ef11a4473962a93 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jun 2026 16:58:46 +0200
+Subject: eventpoll: move epi_fget() up
+
+From: Christian Brauner <brauner@kernel.org>
+
+[ Upstream commit 86e87059e6d1fd5115a31949726450ed03c1073b ]
+
+We'll need it when removing files so move it up. No functional change.
+
+Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-5-2470f9eec0f5@kernel.org
+Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
+Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
+[file_ref_get(&file->f_ref) from original commit left as
+ atomic_long_inc_not_zero(&file->f_count) due to v6.12.y missing commit
+ 90ee6ed776c0 ("fs: port files to file_ref") and its dependent commit
+ 08ef26ea9ab3 ("fs: add file_ref")]
+Signed-off-by: Quentin Schulz <quentin.schulz@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/eventpoll.c | 56 +++++++++++++++++++++++++-------------------------
+ 1 file changed, 28 insertions(+), 28 deletions(-)
+
+diff --git a/fs/eventpoll.c b/fs/eventpoll.c
+index 27280ba4f3d5be..2993b76c21f682 100644
+--- a/fs/eventpoll.c
++++ b/fs/eventpoll.c
+@@ -797,6 +797,34 @@ static void ep_free(struct eventpoll *ep)
+       kfree_rcu(ep, rcu);
+ }
++/*
++ * The ffd.file pointer may be in the process of being torn down due to
++ * being closed, but we may not have finished eventpoll_release() yet.
++ *
++ * Normally, even with the atomic_long_inc_not_zero, the file may have
++ * been free'd and then gotten re-allocated to something else (since
++ * files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU).
++ *
++ * But for epoll, users hold the ep->mtx mutex, and as such any file in
++ * the process of being free'd will block in eventpoll_release_file()
++ * and thus the underlying file allocation will not be free'd, and the
++ * file re-use cannot happen.
++ *
++ * For the same reason we can avoid a rcu_read_lock() around the
++ * operation - 'ffd.file' cannot go away even if the refcount has
++ * reached zero (but we must still not call out to ->poll() functions
++ * etc).
++ */
++static struct file *epi_fget(const struct epitem *epi)
++{
++      struct file *file;
++
++      file = epi->ffd.file;
++      if (!atomic_long_inc_not_zero(&file->f_count))
++              file = NULL;
++      return file;
++}
++
+ /*
+  * Called with &file->f_lock held,
+  * returns with it released
+@@ -989,34 +1017,6 @@ static __poll_t __ep_eventpoll_poll(struct file *file, poll_table *wait, int dep
+       return res;
+ }
+-/*
+- * The ffd.file pointer may be in the process of being torn down due to
+- * being closed, but we may not have finished eventpoll_release() yet.
+- *
+- * Normally, even with the atomic_long_inc_not_zero, the file may have
+- * been free'd and then gotten re-allocated to something else (since
+- * files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU).
+- *
+- * But for epoll, users hold the ep->mtx mutex, and as such any file in
+- * the process of being free'd will block in eventpoll_release_file()
+- * and thus the underlying file allocation will not be free'd, and the
+- * file re-use cannot happen.
+- *
+- * For the same reason we can avoid a rcu_read_lock() around the
+- * operation - 'ffd.file' cannot go away even if the refcount has
+- * reached zero (but we must still not call out to ->poll() functions
+- * etc).
+- */
+-static struct file *epi_fget(const struct epitem *epi)
+-{
+-      struct file *file;
+-
+-      file = epi->ffd.file;
+-      if (!atomic_long_inc_not_zero(&file->f_count))
+-              file = NULL;
+-      return file;
+-}
+-
+ /*
+  * Differs from ep_eventpoll_poll() in that internal callers already have
+  * the ep->mtx so we need to start from depth=1, such that mutex_lock_nested()
+-- 
+2.53.0
+
diff --git a/queue-6.12/eventpoll-rename-ep_remove_safe-back-to-ep_remove.patch b/queue-6.12/eventpoll-rename-ep_remove_safe-back-to-ep_remove.patch
new file mode 100644 (file)
index 0000000..833196b
--- /dev/null
@@ -0,0 +1,97 @@
+From 2ed0844a1214b3fa930312190f1ebb882dd4dca3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jun 2026 16:58:45 +0200
+Subject: eventpoll: rename ep_remove_safe() back to ep_remove()
+
+From: Christian Brauner <brauner@kernel.org>
+
+[ Upstream commit 0bade234723e40e4937be912e105785d6a51464e ]
+
+The current name is just confusing and doesn't clarify anything.
+
+Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-4-2470f9eec0f5@kernel.org
+Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
+Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
+Signed-off-by: Quentin Schulz <quentin.schulz@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/eventpoll.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/fs/eventpoll.c b/fs/eventpoll.c
+index dc747f382dd954..27280ba4f3d5be 100644
+--- a/fs/eventpoll.c
++++ b/fs/eventpoll.c
+@@ -853,7 +853,7 @@ static bool ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
+ /*
+  * ep_remove variant for callers owing an additional reference to the ep
+  */
+-static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi)
++static void ep_remove(struct eventpoll *ep, struct epitem *epi)
+ {
+       struct file *file = epi->ffd.file;
+@@ -900,7 +900,7 @@ static void ep_clear_and_put(struct eventpoll *ep)
+       /*
+        * Walks through the whole tree and try to free each "struct epitem".
+-       * Note that ep_remove_safe() will not remove the epitem in case of a
++       * Note that ep_remove() will not remove the epitem in case of a
+        * racing eventpoll_release_file(); the latter will do the removal.
+        * At this point we are sure no poll callbacks will be lingering around.
+        * Since we still own a reference to the eventpoll struct, the loop can't
+@@ -909,7 +909,7 @@ static void ep_clear_and_put(struct eventpoll *ep)
+       for (rbp = rb_first_cached(&ep->rbr); rbp; rbp = next) {
+               next = rb_next(rbp);
+               epi = rb_entry(rbp, struct epitem, rbn);
+-              ep_remove_safe(ep, epi);
++              ep_remove(ep, epi);
+               cond_resched();
+       }
+@@ -1602,21 +1602,21 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event,
+               mutex_unlock(&tep->mtx);
+       /*
+-       * ep_remove_safe() calls in the later error paths can't lead to
++       * ep_remove() calls in the later error paths can't lead to
+        * ep_free() as the ep file itself still holds an ep reference.
+        */
+       ep_get(ep);
+       /* now check if we've created too many backpaths */
+       if (unlikely(full_check && reverse_path_check())) {
+-              ep_remove_safe(ep, epi);
++              ep_remove(ep, epi);
+               return -EINVAL;
+       }
+       if (epi->event.events & EPOLLWAKEUP) {
+               error = ep_create_wakeup_source(epi);
+               if (error) {
+-                      ep_remove_safe(ep, epi);
++                      ep_remove(ep, epi);
+                       return error;
+               }
+       }
+@@ -1640,7 +1640,7 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event,
+        * high memory pressure.
+        */
+       if (unlikely(!epq.epi)) {
+-              ep_remove_safe(ep, epi);
++              ep_remove(ep, epi);
+               return -ENOMEM;
+       }
+@@ -2329,7 +2329,7 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
+                        * The eventpoll itself is still alive: the refcount
+                        * can't go to zero here.
+                        */
+-                      ep_remove_safe(ep, epi);
++                      ep_remove(ep, epi);
+                       error = 0;
+               } else {
+                       error = -ENOENT;
+-- 
+2.53.0
+
diff --git a/queue-6.12/eventpoll-split-__ep_remove.patch b/queue-6.12/eventpoll-split-__ep_remove.patch
new file mode 100644 (file)
index 0000000..d74ed26
--- /dev/null
@@ -0,0 +1,83 @@
+From 94d7e05595a78e48b1e0b4c8341c2887bf3d2e74 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jun 2026 16:58:42 +0200
+Subject: eventpoll: split __ep_remove()
+
+From: Christian Brauner <brauner@kernel.org>
+
+[ Upstream commit 0f7bdfd413000985de09fc39eb9efa1e091a3ce0 ]
+
+Split __ep_remove() to delineate file removal from epoll item removal.
+
+Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
+Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-2-2470f9eec0f5@kernel.org
+Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
+Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
+Signed-off-by: Quentin Schulz <quentin.schulz@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/eventpoll.c | 27 +++++++++++++++++++++++----
+ 1 file changed, 23 insertions(+), 4 deletions(-)
+
+diff --git a/fs/eventpoll.c b/fs/eventpoll.c
+index 8f9dc2f4891ff5..1cba4ae4a076bc 100644
+--- a/fs/eventpoll.c
++++ b/fs/eventpoll.c
+@@ -797,6 +797,9 @@ static void ep_free(struct eventpoll *ep)
+       kfree_rcu(ep, rcu);
+ }
++static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file);
++static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi);
++
+ /*
+  * Removes a "struct epitem" from the eventpoll RB tree and deallocates
+  * all the associated resources. Must be called with "mtx" held.
+@@ -808,8 +811,6 @@ static void ep_free(struct eventpoll *ep)
+ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
+ {
+       struct file *file = epi->ffd.file;
+-      struct epitems_head *to_free;
+-      struct hlist_head *head;
+       lockdep_assert_irqs_enabled();
+@@ -825,8 +826,21 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
+               return false;
+       }
+-      to_free = NULL;
+-      head = file->f_ep;
++      __ep_remove_file(ep, epi, file);
++      return __ep_remove_epi(ep, epi);
++}
++
++/*
++ * Called with &file->f_lock held,
++ * returns with it released
++ */
++static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file)
++{
++      struct epitems_head *to_free = NULL;
++      struct hlist_head *head = file->f_ep;
++
++      lockdep_assert_held(&ep->mtx);
++
+       if (hlist_is_singular_node(&epi->fllink, head)) {
+               /* See eventpoll_release() for details. */
+               WRITE_ONCE(file->f_ep, NULL);
+@@ -840,6 +854,11 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
+       hlist_del_rcu(&epi->fllink);
+       spin_unlock(&file->f_lock);
+       free_ephead(to_free);
++}
++
++static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
++{
++      lockdep_assert_held(&ep->mtx);
+       rb_erase_cached(&epi->rbn, &ep->rbr);
+-- 
+2.53.0
+
diff --git a/queue-6.12/eventpoll-use-hlist_is_singular_node-in-__ep_remove.patch b/queue-6.12/eventpoll-use-hlist_is_singular_node-in-__ep_remove.patch
new file mode 100644 (file)
index 0000000..36d0456
--- /dev/null
@@ -0,0 +1,38 @@
+From 0465405e6dd7594206d3acdf685aecefde95ddd5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jun 2026 16:58:41 +0200
+Subject: eventpoll: use hlist_is_singular_node() in __ep_remove()
+
+From: Christian Brauner <brauner@kernel.org>
+
+[ Upstream commit 3d9fd0abc94d8cd430cc7cd7d37ce5e5aae2cd2b ]
+
+Replace the open-coded "epi is the only entry in file->f_ep" check
+with hlist_is_singular_node(). Same semantics, and the helper avoids
+the head-cacheline access in the common false case.
+
+Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-1-2470f9eec0f5@kernel.org
+Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
+Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
+Signed-off-by: Quentin Schulz <quentin.schulz@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/eventpoll.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/eventpoll.c b/fs/eventpoll.c
+index a860cb54658a3b..8f9dc2f4891ff5 100644
+--- a/fs/eventpoll.c
++++ b/fs/eventpoll.c
+@@ -827,7 +827,7 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
+       to_free = NULL;
+       head = file->f_ep;
+-      if (head->first == &epi->fllink && !epi->fllink.next) {
++      if (hlist_is_singular_node(&epi->fllink, head)) {
+               /* See eventpoll_release() for details. */
+               WRITE_ONCE(file->f_ep, NULL);
+               if (!is_file_epoll(file)) {
+-- 
+2.53.0
+
diff --git a/queue-6.12/iio-light-bh1780-fix-pm-runtime-leak-on-error-path.patch b/queue-6.12/iio-light-bh1780-fix-pm-runtime-leak-on-error-path.patch
new file mode 100644 (file)
index 0000000..efcabb7
--- /dev/null
@@ -0,0 +1,48 @@
+From b783059f8941aeff714a79e69cb05b1e663b6da1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jun 2026 17:34:43 +0300
+Subject: iio: light: bh1780: fix PM runtime leak on error path
+
+From: Antoniu Miclaus <antoniu.miclaus@analog.com>
+
+commit dd72e6c3cdea05cad24e99710939086f7a113fb5 upstream.
+
+Move pm_runtime_put_autosuspend() before the error check to ensure
+the PM runtime reference count is always decremented after
+pm_runtime_get_sync(), regardless of whether the read operation
+succeeds or fails.
+
+Fixes: 1f0477f18306 ("iio: light: new driver for the ROHM BH1780")
+Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
+Reviewed-by: Linus Walleij <linusw@kernel.org>
+Cc: <Stable@vger.kernel.org>
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+[ moved both pm_runtime_mark_last_busy() and pm_runtime_put_autosuspend() before the error check instead of just pm_runtime_put_autosuspend() ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Elizaveta Tereshkina <etereshkina@astralinux.ru>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/light/bh1780.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c
+index 475f44954f6110..f478f12640d536 100644
+--- a/drivers/iio/light/bh1780.c
++++ b/drivers/iio/light/bh1780.c
+@@ -109,10 +109,10 @@ static int bh1780_read_raw(struct iio_dev *indio_dev,
+               case IIO_LIGHT:
+                       pm_runtime_get_sync(&bh1780->client->dev);
+                       value = bh1780_read_word(bh1780, BH1780_REG_DLOW);
+-                      if (value < 0)
+-                              return value;
+                       pm_runtime_mark_last_busy(&bh1780->client->dev);
+                       pm_runtime_put_autosuspend(&bh1780->client->dev);
++                      if (value < 0)
++                              return value;
+                       *val = value;
+                       return IIO_VAL_INT;
+-- 
+2.53.0
+
diff --git a/queue-6.12/net-drop-the-lock-in-skb_may_tx_timestamp.patch b/queue-6.12/net-drop-the-lock-in-skb_may_tx_timestamp.patch
new file mode 100644 (file)
index 0000000..e18d3ec
--- /dev/null
@@ -0,0 +1,120 @@
+From 0932116d93c9eb0cc6462922ddc0dc47e69a07e1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jun 2026 17:20:12 +0200
+Subject: net: Drop the lock in skb_may_tx_timestamp()
+
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+[ Upstream commit 983512f3a87fd8dc4c94dfa6b596b6e57df5aad7 ]
+
+skb_may_tx_timestamp() may acquire sock::sk_callback_lock. The lock must
+not be taken in IRQ context, only softirq is okay. A few drivers receive
+the timestamp via a dedicated interrupt and complete the TX timestamp
+from that handler. This will lead to a deadlock if the lock is already
+write-locked on the same CPU.
+
+Taking the lock can be avoided. The socket (pointed by the skb) will
+remain valid until the skb is released. The ->sk_socket and ->file
+member will be set to NULL once the user closes the socket which may
+happen before the timestamp arrives.
+If we happen to observe the pointer while the socket is closing but
+before the pointer is set to NULL then we may use it because both
+pointer (and the file's cred member) are RCU freed.
+
+Drop the lock. Use READ_ONCE() to obtain the individual pointer. Add a
+matching WRITE_ONCE() where the pointer are cleared.
+
+Link: https://lore.kernel.org/all/20260205145104.iWinkXHv@linutronix.de
+Fixes: b245be1f4db1a ("net-timestamp: no-payload only sysctl")
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260220183858.N4ERjFW6@linutronix.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[adapted sk_set_socket() in include/net/sock.h to fix the conflict  from
+ not having commit 5d6b58c932ec ("net: lockless sock_i_ino()") and the
+ additional previous changes required by it.
+ It comes down to just now having the lines of
+    if (sock) {
+            WRITE_ONCE(sk->sk_uid, SOCK_INODE(sock)->i_uid);
+            WRITE_ONCE(sk->sk_ino, SOCK_INODE(sock)->i_ino);
+    }
+ below the changed line.
+ I've tested this on a device running an nfs-root and did some
+ additional network stress-testing.]
+Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/sock.h |  2 +-
+ net/core/skbuff.c  | 23 ++++++++++++++++++-----
+ net/socket.c       |  2 +-
+ 3 files changed, 20 insertions(+), 7 deletions(-)
+
+diff --git a/include/net/sock.h b/include/net/sock.h
+index 0d77a87929f938..dffbaaa7fe493d 100644
+--- a/include/net/sock.h
++++ b/include/net/sock.h
+@@ -2040,7 +2040,7 @@ static inline int sk_rx_queue_get(const struct sock *sk)
+ static inline void sk_set_socket(struct sock *sk, struct socket *sock)
+ {
+-      sk->sk_socket = sock;
++      WRITE_ONCE(sk->sk_socket, sock);
+ }
+ static inline wait_queue_head_t *sk_sleep(struct sock *sk)
+diff --git a/net/core/skbuff.c b/net/core/skbuff.c
+index 4be699bd3a17f7..fede3aa3ddbc10 100644
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -5525,15 +5525,28 @@ static void __skb_complete_tx_timestamp(struct sk_buff *skb,
+ static bool skb_may_tx_timestamp(struct sock *sk, bool tsonly)
+ {
+-      bool ret;
++      struct socket *sock;
++      struct file *file;
++      bool ret = false;
+       if (likely(READ_ONCE(sysctl_tstamp_allow_data) || tsonly))
+               return true;
+-      read_lock_bh(&sk->sk_callback_lock);
+-      ret = sk->sk_socket && sk->sk_socket->file &&
+-            file_ns_capable(sk->sk_socket->file, &init_user_ns, CAP_NET_RAW);
+-      read_unlock_bh(&sk->sk_callback_lock);
++      /* The sk pointer remains valid as long as the skb is. The sk_socket and
++       * file pointer may become NULL if the socket is closed. Both structures
++       * (including file->cred) are RCU freed which means they can be accessed
++       * within a RCU read section.
++       */
++      rcu_read_lock();
++      sock = READ_ONCE(sk->sk_socket);
++      if (!sock)
++              goto out;
++      file = READ_ONCE(sock->file);
++      if (!file)
++              goto out;
++      ret = file_ns_capable(file, &init_user_ns, CAP_NET_RAW);
++out:
++      rcu_read_unlock();
+       return ret;
+ }
+diff --git a/net/socket.c b/net/socket.c
+index 5c5dd9f6605a94..723bc3a1ba5cdd 100644
+--- a/net/socket.c
++++ b/net/socket.c
+@@ -652,7 +652,7 @@ static void __sock_release(struct socket *sock, struct inode *inode)
+               iput(SOCK_INODE(sock));
+               return;
+       }
+-      sock->file = NULL;
++      WRITE_ONCE(sock->file, NULL);
+ }
+ /**
+-- 
+2.53.0
+
index fd2301629cd8536060c18e21ef83eb6d8e35720d..56395f1fcc4c85c55984ae468717043be3cb2b03 100644 (file)
@@ -9,3 +9,12 @@ io_uring-net-avoid-msghdr-on-op_connect-op_bind-asyn.patch
 drm-xe-display-fix-oops-in-suspend-shutdown-without-.patch
 drm-v3d-store-the-active-job-inside-the-queue-s-stat.patch
 drm-v3d-skip-csd-when-it-has-zeroed-workgroups.patch
+eventpoll-use-hlist_is_singular_node-in-__ep_remove.patch
+eventpoll-split-__ep_remove.patch
+eventpoll-kill-__ep_remove.patch
+eventpoll-drop-vestigial-__-prefix-from-ep_remove_-f.patch
+eventpoll-rename-ep_remove_safe-back-to-ep_remove.patch
+eventpoll-move-epi_fget-up.patch
+eventpoll-fix-ep_remove-struct-eventpoll-struct-file.patch
+iio-light-bh1780-fix-pm-runtime-leak-on-error-path.patch
+net-drop-the-lock-in-skb_may_tx_timestamp.patch
diff --git a/queue-6.6/batman-adv-tt-prevent-tvlv-entry-number-overflow.patch b/queue-6.6/batman-adv-tt-prevent-tvlv-entry-number-overflow.patch
new file mode 100644 (file)
index 0000000..23491f2
--- /dev/null
@@ -0,0 +1,80 @@
+From 1b2939af68d968ba49ed30d70caa6069408ed018 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 20:16:39 +0200
+Subject: batman-adv: tt: prevent TVLV entry number overflow
+
+From: Sven Eckelmann <sven@narfation.org>
+
+commit 99d9958fa10fb684b2a8e2c48a8d704122721420 upstream.
+
+The helpers to prepare the buffers for the local and global TT based
+replies are trying to sum up all TT entries which can be found for each
+VLAN. In theory, this sum can be too big for an u16 and therefore overflow.
+A too small buffer would then be allocated for the TVLV.
+
+The too small buffer will be handled gracefully by
+batadv_tt_tvlv_generate() and is not causing a buffer overflow - just a
+truncated reply. But this overflow shouldn't have happened in the first and
+the too small buffer should never have been allocated when an overflow was
+detected.
+
+Cc: stable@kernel.org
+Fixes: 7ea7b4a14275 ("batman-adv: make the TT CRC logic VLAN specific")
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/batman-adv/translation-table.c | 20 +++++++++++++++++---
+ 1 file changed, 17 insertions(+), 3 deletions(-)
+
+diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
+index 4045ddefc29b47..7041cd69e20070 100644
+--- a/net/batman-adv/translation-table.c
++++ b/net/batman-adv/translation-table.c
+@@ -850,11 +850,18 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
+       u16 total_entries = 0;
+       u8 *tt_change_ptr;
+       int vlan_entries;
++      u16 sum_entries;
+       spin_lock_bh(&orig_node->vlan_list_lock);
+       hlist_for_each_entry(vlan, &orig_node->vlan_list, list) {
+               vlan_entries = atomic_read(&vlan->tt.num_entries);
+-              total_entries += vlan_entries;
++
++              if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) {
++                      *tt_len = 0;
++                      goto out;
++              }
++
++              total_entries = sum_entries;
+               num_vlan++;
+       }
+@@ -941,15 +948,22 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
+       struct batadv_softif_vlan *vlan;
+       size_t change_offset;
+       u16 num_vlan = 0;
+-      u16 vlan_entries = 0;
+       u16 total_entries = 0;
+       u16 tvlv_len;
+       u8 *tt_change_ptr;
++      int vlan_entries;
++      u16 sum_entries;
+       spin_lock_bh(&bat_priv->softif_vlan_list_lock);
+       hlist_for_each_entry(vlan, &bat_priv->softif_vlan_list, list) {
+               vlan_entries = atomic_read(&vlan->tt.num_entries);
+-              total_entries += vlan_entries;
++
++              if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) {
++                      tvlv_len = 0;
++                      goto out;
++              }
++
++              total_entries = sum_entries;
+               num_vlan++;
+       }
+-- 
+2.53.0
+
index a07ea873201298452d795ac0eaf1e97d7152759d..3b9cc6db80d4286217c84ade8c945754e9b76d76 100644 (file)
@@ -4,3 +4,4 @@ drm-amd-display-bound-vbios-record-chain-walk-loops.patch
 ip6_vti-set-netns_immutable-on-the-fallback-device.patch
 drm-v3d-store-the-active-job-inside-the-queue-s-stat.patch
 drm-v3d-skip-csd-when-it-has-zeroed-workgroups.patch
+batman-adv-tt-prevent-tvlv-entry-number-overflow.patch
diff --git a/queue-7.0/lockd-fix-test-handling-when-not-all-permissions-are.patch b/queue-7.0/lockd-fix-test-handling-when-not-all-permissions-are.patch
new file mode 100644 (file)
index 0000000..baf5b74
--- /dev/null
@@ -0,0 +1,254 @@
+From 56dae8562b2e5c209ec70fd26768e059905c1e51 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jun 2026 16:47:50 -0400
+Subject: lockd: fix TEST handling when not all permissions are available.
+
+From: NeilBrown <neil@brown.name>
+
+[ Upstream commit 0b474240327cebeff08ad429e8ed3cfc6c8ee816 ]
+
+The F_GETLK fcntl can work with either read access or write access or
+both.  It can query F_RDLCK and F_WRLCK locks in either case.
+
+However lockd currently treats F_GETLK similar to F_SETLK in that read
+access is required to query an F_RDLCK lock and write access is required
+to query a F_WRLCK lock.
+
+This is wrong and can cause problems - e.g.  when qemu accesses a
+read-only (e.g. iso) filesystem image over NFS (though why it queries
+if it can get a write lock - I don't know.  But it does, and this works
+with local filesystems).
+
+So we need TEST requests to be handled differently.  To do this:
+
+- change nlm_do_fopen() to accept O_RDWR as a mode and in that case
+  succeed if either a O_RDONLY or O_WRONLY file can be opened.
+- change nlm_lookup_file() to accept a mode argument from caller,
+  instead of deducing base on lock time, and pass that on to nlm_do_fopen()
+- change nlm4svc_retrieve_args() and nlmsvc_retrieve_args() to detect
+  TEST requests and pass O_RDWR as a mode to nlm_lookup_file, passing
+  the same mode as before for other requests.  Also set
+   lock->fl.c.flc_file to whichever file is available for TEST requests.
+- change nlmsvc_testlock() to also not calculate the mode, but to use
+  whatever was stored in lock->fl.c.flc_file.
+
+This behaviour of lockd - requesting O_WRONLY access to TEST for
+exclusive locks - has been present at least since git history began.
+However it was hidden until recently because knfsd ignored the access
+requested by lockd and required only READ access for all locking
+requests (unless the underlying filesystem provided an f_op->open
+function which checked access permissions).
+
+The commit mentioned in Fixes: below changed nfsd_permission() to NOT
+override the access request for LOCK requests and this exposed the bug
+that we are now fixing.
+
+Note that there is another issue that this patch does not address.
+The flock(.., LOCK_EX) call is permitted on a read-only file descriptor.
+Linux NFS maps this to NLM locking as whole-file byte-range locks.
+nfsd will see this as though it were fcntl( F_SETLK (F_WRLCK)) and will
+now require write access, which it might not be able to get.
+It is not clear if this is a problem in practice, or what the best
+solution might be.  So no attempt is made to address it.
+
+Reported-by: Tj <tj.iam.tj@proton.me>
+Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1128861
+Fixes: 4cc9b9f2bf4d ("nfsd: refine and rename NFSD_MAY_LOCK")
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: NeilBrown <neil@brown.name>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/lockd/svc4proc.c         | 13 ++++++++++---
+ fs/lockd/svclock.c          |  4 +---
+ fs/lockd/svcproc.c          | 15 ++++++++++++---
+ fs/lockd/svcsubs.c          | 35 +++++++++++++++++++++++++----------
+ include/linux/lockd/lockd.h |  2 +-
+ 5 files changed, 49 insertions(+), 20 deletions(-)
+
+diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
+index 4b6f18d977343d..75e020a8bfd072 100644
+--- a/fs/lockd/svc4proc.c
++++ b/fs/lockd/svc4proc.c
+@@ -26,6 +26,8 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
+       struct nlm_host         *host = NULL;
+       struct nlm_file         *file = NULL;
+       struct nlm_lock         *lock = &argp->lock;
++      bool                    is_test = (rqstp->rq_proc == NLMPROC_TEST ||
++                                         rqstp->rq_proc == NLMPROC_TEST_MSG);
+       __be32                  error = 0;
+       /* nfsd callbacks must have been installed for this procedure */
+@@ -46,15 +48,20 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
+       if (filp != NULL) {
+               int mode = lock_to_openmode(&lock->fl);
++              if (is_test)
++                      mode = O_RDWR;
++
+               lock->fl.c.flc_flags = FL_POSIX;
+-              error = nlm_lookup_file(rqstp, &file, lock);
++              error = nlm_lookup_file(rqstp, &file, lock, mode);
+               if (error)
+                       goto no_locks;
+               *filp = file;
+-
+               /* Set up the missing parts of the file_lock structure */
+-              lock->fl.c.flc_file = file->f_file[mode];
++              if (is_test)
++                      lock->fl.c.flc_file = nlmsvc_file_file(file);
++              else
++                      lock->fl.c.flc_file = file->f_file[mode];
+               lock->fl.c.flc_pid = current->tgid;
+               lock->fl.fl_start = (loff_t)lock->lock_start;
+               lock->fl.fl_end = lock->lock_len ?
+diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
+index abc65dc79f8543..382bf0d93ed1c1 100644
+--- a/fs/lockd/svclock.c
++++ b/fs/lockd/svclock.c
+@@ -619,7 +619,6 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
+               struct nlm_lock *conflock)
+ {
+       int                     error;
+-      int                     mode;
+       __be32                  ret;
+       dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
+@@ -637,14 +636,13 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
+               goto out;
+       }
+-      mode = lock_to_openmode(&lock->fl);
+       locks_init_lock(&conflock->fl);
+       /* vfs_test_lock only uses start, end, and owner, but tests flc_file */
+       conflock->fl.c.flc_file = lock->fl.c.flc_file;
+       conflock->fl.fl_start = lock->fl.fl_start;
+       conflock->fl.fl_end = lock->fl.fl_end;
+       conflock->fl.c.flc_owner = lock->fl.c.flc_owner;
+-      error = vfs_test_lock(file->f_file[mode], &conflock->fl);
++      error = vfs_test_lock(lock->fl.c.flc_file, &conflock->fl);
+       if (error) {
+               ret = nlm_lck_denied_nolocks;
+               goto out;
+diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
+index 5817ef272332d9..d98e8d684376b7 100644
+--- a/fs/lockd/svcproc.c
++++ b/fs/lockd/svcproc.c
+@@ -55,6 +55,8 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
+       struct nlm_host         *host = NULL;
+       struct nlm_file         *file = NULL;
+       struct nlm_lock         *lock = &argp->lock;
++      bool                    is_test = (rqstp->rq_proc == NLMPROC_TEST ||
++                                         rqstp->rq_proc == NLMPROC_TEST_MSG);
+       int                     mode;
+       __be32                  error = 0;
+@@ -70,15 +72,22 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
+       /* Obtain file pointer. Not used by FREE_ALL call. */
+       if (filp != NULL) {
+-              error = cast_status(nlm_lookup_file(rqstp, &file, lock));
++              mode = lock_to_openmode(&lock->fl);
++
++              if (is_test)
++                      mode = O_RDWR;
++
++              error = cast_status(nlm_lookup_file(rqstp, &file, lock, mode));
+               if (error != 0)
+                       goto no_locks;
+               *filp = file;
+               /* Set up the missing parts of the file_lock structure */
+-              mode = lock_to_openmode(&lock->fl);
+               lock->fl.c.flc_flags = FL_POSIX;
+-              lock->fl.c.flc_file  = file->f_file[mode];
++              if (is_test)
++                      lock->fl.c.flc_file = nlmsvc_file_file(file);
++              else
++                      lock->fl.c.flc_file = file->f_file[mode];
+               lock->fl.c.flc_pid = current->tgid;
+               lock->fl.fl_lmops = &nlmsvc_lock_operations;
+               nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid);
+diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
+index dd0214dcb69503..b83e6ecd5be34f 100644
+--- a/fs/lockd/svcsubs.c
++++ b/fs/lockd/svcsubs.c
+@@ -82,18 +82,35 @@ int lock_to_openmode(struct file_lock *lock)
+  *
+  * We have to make sure we have the right credential to open
+  * the file.
++ *
++ * mode can be O_RDONLY(0), O_WRONLY(1) or O_RDWR(2). The latter
++ * means success can be achieved with EITHER O_RDONLY or O_WRONLY.
++ * It does NOT mean both read and write are required.
+  */
+ static __be32 nlm_do_fopen(struct svc_rqst *rqstp,
+                          struct nlm_file *file, int mode)
+ {
+-      struct file **fp = &file->f_file[mode];
+-      __be32  nfserr;
++      __be32 nfserr = nlm_lck_denied_nolocks;
++      __be32 deferred = 0;
++      struct file **fp;
++      int m;
+-      if (*fp)
+-              return 0;
+-      nfserr = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, mode);
+-      if (nfserr)
+-              dprintk("lockd: open failed (error %d)\n", nfserr);
++      for (m = O_RDONLY ; m <= O_WRONLY ; m++) {
++              if (mode != O_RDWR && mode != m)
++                      continue;
++
++              fp = &file->f_file[m];
++              if (*fp)
++                      return 0;
++              nfserr = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, m);
++              if (!nfserr)
++                      return 0;
++              if (nfserr == nlm_drop_reply)
++                      deferred = nfserr;
++      }
++      if (deferred)
++              return deferred;
++      dprintk("lockd: open failed (error %d)\n", ntohl(nfserr));
+       return nfserr;
+ }
+@@ -103,17 +120,15 @@ static __be32 nlm_do_fopen(struct svc_rqst *rqstp,
+  */
+ __be32
+ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
+-                                      struct nlm_lock *lock)
++              struct nlm_lock *lock, int mode)
+ {
+       struct nlm_file *file;
+       unsigned int    hash;
+       __be32          nfserr;
+-      int             mode;
+       nlm_debug_print_fh("nlm_lookup_file", &lock->fh);
+       hash = file_hash(&lock->fh);
+-      mode = lock_to_openmode(&lock->fl);
+       /* Lock file table */
+       mutex_lock(&nlm_file_mutex);
+diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
+index 330e38776bb20d..fe5cdd4d66f484 100644
+--- a/include/linux/lockd/lockd.h
++++ b/include/linux/lockd/lockd.h
+@@ -294,7 +294,7 @@ void                 nlmsvc_locks_init_private(struct file_lock *, struct nlm_host *, pid_t);
+  * File handling for the server personality
+  */
+ __be32                  nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
+-                                      struct nlm_lock *);
++                                struct nlm_lock *, int);
+ void            nlm_release_file(struct nlm_file *);
+ void            nlmsvc_put_lockowner(struct nlm_lockowner *);
+ void            nlmsvc_release_lockowner(struct nlm_lock *);
+-- 
+2.53.0
+
index b09b947a96bd65f7555f5bef1d5be216fd1e8fde..d9a77aef582c186fa30b88ffa77246008d626da4 100644 (file)
@@ -1,2 +1,3 @@
 io_uring-net-avoid-msghdr-on-op_connect-op_bind-asyn.patch
 arm64-entry-fix-arm64-specific-rseq-brokenness.patch
+lockd-fix-test-handling-when-not-all-permissions-are.patch