]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 20 Jul 2023 18:10:14 +0000 (20:10 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 20 Jul 2023 18:10:14 +0000 (20:10 +0200)
added patches:
cifs-fix-session-state-check-in-smb2_find_smb_ses.patch
drm-client-send-hotplug-event-after-registering-a-client.patch
fs-ntfs3-check-fields-while-reading.patch
ovl-fix-null-pointer-dereference-in-ovl_get_acl_rcu.patch
ovl-let-helper-ovl_i_path_real-return-the-realinode.patch

queue-6.1/cifs-fix-session-state-check-in-smb2_find_smb_ses.patch [new file with mode: 0644]
queue-6.1/drm-client-send-hotplug-event-after-registering-a-client.patch [new file with mode: 0644]
queue-6.1/fs-ntfs3-check-fields-while-reading.patch [new file with mode: 0644]
queue-6.1/ovl-fix-null-pointer-dereference-in-ovl_get_acl_rcu.patch [new file with mode: 0644]
queue-6.1/ovl-let-helper-ovl_i_path_real-return-the-realinode.patch [new file with mode: 0644]
queue-6.1/series

diff --git a/queue-6.1/cifs-fix-session-state-check-in-smb2_find_smb_ses.patch b/queue-6.1/cifs-fix-session-state-check-in-smb2_find_smb_ses.patch
new file mode 100644 (file)
index 0000000..297cf02
--- /dev/null
@@ -0,0 +1,37 @@
+From 66be5c48ee1b5b8c919cc329fe6d32e16badaa40 Mon Sep 17 00:00:00 2001
+From: Winston Wen <wentao@uniontech.com>
+Date: Mon, 26 Jun 2023 11:42:57 +0800
+Subject: cifs: fix session state check in smb2_find_smb_ses
+
+From: Winston Wen <wentao@uniontech.com>
+
+commit 66be5c48ee1b5b8c919cc329fe6d32e16badaa40 upstream.
+
+Chech the session state and skip it if it's exiting.
+
+Signed-off-by: Winston Wen <wentao@uniontech.com>
+Reviewed-by: Shyam Prasad N <sprasad@microsoft.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/client/smb2transport.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/fs/smb/client/smb2transport.c
++++ b/fs/smb/client/smb2transport.c
+@@ -153,7 +153,14 @@ smb2_find_smb_ses_unlocked(struct TCP_Se
+       list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
+               if (ses->Suid != ses_id)
+                       continue;
++
++              spin_lock(&ses->ses_lock);
++              if (ses->ses_status == SES_EXITING) {
++                      spin_unlock(&ses->ses_lock);
++                      continue;
++              }
+               ++ses->ses_count;
++              spin_unlock(&ses->ses_lock);
+               return ses;
+       }
diff --git a/queue-6.1/drm-client-send-hotplug-event-after-registering-a-client.patch b/queue-6.1/drm-client-send-hotplug-event-after-registering-a-client.patch
new file mode 100644 (file)
index 0000000..d343383
--- /dev/null
@@ -0,0 +1,176 @@
+From 27655b9bb9f0d9c32b8de8bec649b676898c52d5 Mon Sep 17 00:00:00 2001
+From: Thomas Zimmermann <tzimmermann@suse.de>
+Date: Mon, 10 Jul 2023 11:10:17 +0200
+Subject: drm/client: Send hotplug event after registering a client
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Zimmermann <tzimmermann@suse.de>
+
+commit 27655b9bb9f0d9c32b8de8bec649b676898c52d5 upstream.
+
+Generate a hotplug event after registering a client to allow the
+client to configure its display. Remove the hotplug calls from the
+existing clients for fbdev emulation. This change fixes a concurrency
+bug between registering a client and receiving events from the DRM
+core. The bug is present in the fbdev emulation of all drivers.
+
+The fbdev emulation currently generates a hotplug event before
+registering the client to the device. For each new output, the DRM
+core sends an additional hotplug event to each registered client.
+
+If the DRM core detects first output between sending the artificial
+hotplug and registering the device, the output's hotplug event gets
+lost. If this is the first output, the fbdev console display remains
+dark. This has been observed with amdgpu and fbdev-generic.
+
+Fix this by adding hotplug generation directly to the client's
+register helper drm_client_register(). Registering the client and
+receiving events are serialized by struct drm_device.clientlist_mutex.
+So an output is either configured by the initial hotplug event, or
+the client has already been registered.
+
+The bug was originally added in commit 6e3f17ee73f7 ("drm/fb-helper:
+generic: Call drm_client_add() after setup is done"), in which adding
+a client and receiving a hotplug event switched order. It was hidden,
+as most hardware and drivers have at least on static output configured.
+Other drivers didn't use the internal DRM client or still had struct
+drm_mode_config_funcs.output_poll_changed set. That callback handled
+hotplug events as well. After not setting the callback in amdgpu in
+commit 0e3172bac3f4 ("drm/amdgpu: Don't set struct
+drm_driver.output_poll_changed"), amdgpu did not show a framebuffer
+console if output events got lost. The bug got copy-pasted from
+fbdev-generic into the other fbdev emulation.
+
+Reported-by: Moritz Duge <MoritzDuge@kolahilft.de>
+Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/2649
+Fixes: 6e3f17ee73f7 ("drm/fb-helper: generic: Call drm_client_add() after setup is done")
+Fixes: 8ab59da26bc0 ("drm/fb-helper: Move generic fbdev emulation into separate source file")
+Fixes: b79fe9abd58b ("drm/fbdev-dma: Implement fbdev emulation for GEM DMA helpers")
+Fixes: 63c381552f69 ("drm/armada: Implement fbdev emulation as in-kernel client")
+Fixes: 49953b70e7d3 ("drm/exynos: Implement fbdev emulation as in-kernel client")
+Fixes: 8f1aaccb04b7 ("drm/gma500: Implement client-based fbdev emulation")
+Fixes: 940b869c2f2f ("drm/msm: Implement fbdev emulation as in-kernel client")
+Fixes: 9e69bcd88e45 ("drm/omapdrm: Implement fbdev emulation as in-kernel client")
+Fixes: e317a69fe891 ("drm/radeon: Implement client-based fbdev emulation")
+Fixes: 71ec16f45ef8 ("drm/tegra: Implement fbdev emulation as in-kernel client")
+Fixes: 0e3172bac3f4 ("drm/amdgpu: Don't set struct drm_driver.output_poll_changed")
+Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
+Tested-by: Moritz Duge <MoritzDuge@kolahilft.de>
+Tested-by: Torsten Krah <krah.tm@gmail.com>
+Tested-by: Paul Schyska <pschyska@gmail.com>
+Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
+Cc: David Airlie <airlied@gmail.com>
+Cc: Noralf Trønnes <noralf@tronnes.org>
+Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Cc: Maxime Ripard <mripard@kernel.org>
+Cc: Javier Martinez Canillas <javierm@redhat.com>
+Cc: Russell King <linux@armlinux.org.uk>
+Cc: Inki Dae <inki.dae@samsung.com>
+Cc: Seung-Woo Kim <sw0312.kim@samsung.com>
+Cc: Kyungmin Park <kyungmin.park@samsung.com>
+Cc: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Cc: Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
+Cc: Rob Clark <robdclark@gmail.com>
+Cc: Abhinav Kumar <quic_abhinavk@quicinc.com>
+Cc: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Cc: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Cc: "Christian König" <christian.koenig@amd.com>
+Cc: "Pan, Xinhui" <Xinhui.Pan@amd.com>
+Cc: Thierry Reding <thierry.reding@gmail.com>
+Cc: Mikko Perttunen <mperttunen@nvidia.com>
+Cc: dri-devel@lists.freedesktop.org
+Cc: linux-kernel@vger.kernel.org
+Cc: linux-arm-kernel@lists.infradead.org
+Cc: linux-samsung-soc@vger.kernel.org
+Cc: linux-arm-msm@vger.kernel.org
+Cc: freedreno@lists.freedesktop.org
+Cc: amd-gfx@lists.freedesktop.org
+Cc: linux-tegra@vger.kernel.org
+Cc: dri-devel@lists.freedesktop.org
+Cc: <stable@vger.kernel.org> # v5.2+
+Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> # msm
+Link: https://patchwork.freedesktop.org/patch/msgid/20230710091029.27503-1-tzimmermann@suse.de
+(cherry picked from commit 27655b9bb9f0d9c32b8de8bec649b676898c52d5)
+[ Dropped changes to drivers/gpu/drm/armada/armada_fbdev.c as
+  174c3c38e3a2 drm/armada: Initialize fbdev DRM client
+  was introduced in 6.5-rc1.
+
+  Dropped changes to exynos, msm, omapdrm, radeon, tegra drivers
+  as missing code these commits introduced:
+
+  99286486d674 drm/exynos: Initialize fbdev DRM client
+  841ef552b141 drm/msm: Initialize fbdev DRM client
+  9e69bcd88e45 drm/omapdrm: Implement fbdev emulation as in-kernel client
+  e317a69fe891 drm/radeon: Implement client-based fbdev emulation
+  9b926bcf2636 drm/radeon: Only build fbdev if DRM_FBDEV_EMULATION is set
+  25dda38e0b07 drm/tegra: Initialize fbdev DRM client
+  8f1aaccb04b7 drm/gma500: Implement client-based fbdev emulation
+  b79fe9abd58b drm/fbdev-dma: Implement fbdev emulation for GEM DMA helpers
+
+  Move code for drm-fbdev-generic.c to matching file in 6.1.y because
+  these commits haven't happened in 6.1.y.
+  8ab59da26bc0 drm/fb-helper: Move generic fbdev emulation into separate source file
+  b9c93f4ec737 drm/fbdev-generic: Rename symbols ]
+Cc: alexandru.gagniuc@hp.com
+Link: https://lore.kernel.org/stable/SJ0PR84MB20882EEA1ABB36F60E845E378F5AA@SJ0PR84MB2088.NAMPRD84.PROD.OUTLOOK.COM/
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/drm_client.c    |   21 +++++++++++++++++++++
+ drivers/gpu/drm/drm_fb_helper.c |    4 ----
+ 2 files changed, 21 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/drm_client.c
++++ b/drivers/gpu/drm/drm_client.c
+@@ -122,13 +122,34 @@ EXPORT_SYMBOL(drm_client_init);
+  * drm_client_register() it is no longer permissible to call drm_client_release()
+  * directly (outside the unregister callback), instead cleanup will happen
+  * automatically on driver unload.
++ *
++ * Registering a client generates a hotplug event that allows the client
++ * to set up its display from pre-existing outputs. The client must have
++ * initialized its state to able to handle the hotplug event successfully.
+  */
+ void drm_client_register(struct drm_client_dev *client)
+ {
+       struct drm_device *dev = client->dev;
++      int ret;
+       mutex_lock(&dev->clientlist_mutex);
+       list_add(&client->list, &dev->clientlist);
++
++      if (client->funcs && client->funcs->hotplug) {
++              /*
++               * Perform an initial hotplug event to pick up the
++               * display configuration for the client. This step
++               * has to be performed *after* registering the client
++               * in the list of clients, or a concurrent hotplug
++               * event might be lost; leaving the display off.
++               *
++               * Hold the clientlist_mutex as for a regular hotplug
++               * event.
++               */
++              ret = client->funcs->hotplug(client);
++              if (ret)
++                      drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
++      }
+       mutex_unlock(&dev->clientlist_mutex);
+ }
+ EXPORT_SYMBOL(drm_client_register);
+--- a/drivers/gpu/drm/drm_fb_helper.c
++++ b/drivers/gpu/drm/drm_fb_helper.c
+@@ -2634,10 +2634,6 @@ void drm_fbdev_generic_setup(struct drm_
+               preferred_bpp = 32;
+       fb_helper->preferred_bpp = preferred_bpp;
+-      ret = drm_fbdev_client_hotplug(&fb_helper->client);
+-      if (ret)
+-              drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
+-
+       drm_client_register(&fb_helper->client);
+ }
+ EXPORT_SYMBOL(drm_fbdev_generic_setup);
diff --git a/queue-6.1/fs-ntfs3-check-fields-while-reading.patch b/queue-6.1/fs-ntfs3-check-fields-while-reading.patch
new file mode 100644 (file)
index 0000000..df57b7c
--- /dev/null
@@ -0,0 +1,487 @@
+From 0e8235d28f3a0e9eda9f02ff67ee566d5f42b66b Mon Sep 17 00:00:00 2001
+From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
+Date: Mon, 10 Oct 2022 13:15:33 +0300
+Subject: fs/ntfs3: Check fields while reading
+
+From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
+
+commit 0e8235d28f3a0e9eda9f02ff67ee566d5f42b66b upstream.
+
+Added new functions index_hdr_check and index_buf_check.
+Now we check all stuff for correctness while reading from disk.
+Also fixed bug with stale nfs data.
+
+Reported-by: van fantasy <g1042620637@gmail.com>
+Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
+Fixes: 82cae269cfa95 ("fs/ntfs3: Add initialization of super block")
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ntfs3/index.c   |   84 ++++++++++++++++++++++++++++++++++++----
+ fs/ntfs3/inode.c   |   18 ++++----
+ fs/ntfs3/ntfs_fs.h |    4 -
+ fs/ntfs3/run.c     |    7 ++-
+ fs/ntfs3/xattr.c   |  109 ++++++++++++++++++++++++++++++++++-------------------
+ 5 files changed, 164 insertions(+), 58 deletions(-)
+
+--- a/fs/ntfs3/index.c
++++ b/fs/ntfs3/index.c
+@@ -605,11 +605,58 @@ static const struct NTFS_DE *hdr_insert_
+       return e;
+ }
++/*
++ * index_hdr_check
++ *
++ * return true if INDEX_HDR is valid
++ */
++static bool index_hdr_check(const struct INDEX_HDR *hdr, u32 bytes)
++{
++      u32 end = le32_to_cpu(hdr->used);
++      u32 tot = le32_to_cpu(hdr->total);
++      u32 off = le32_to_cpu(hdr->de_off);
++
++      if (!IS_ALIGNED(off, 8) || tot > bytes || end > tot ||
++          off + sizeof(struct NTFS_DE) > end) {
++              /* incorrect index buffer. */
++              return false;
++      }
++
++      return true;
++}
++
++/*
++ * index_buf_check
++ *
++ * return true if INDEX_BUFFER seems is valid
++ */
++static bool index_buf_check(const struct INDEX_BUFFER *ib, u32 bytes,
++                          const CLST *vbn)
++{
++      const struct NTFS_RECORD_HEADER *rhdr = &ib->rhdr;
++      u16 fo = le16_to_cpu(rhdr->fix_off);
++      u16 fn = le16_to_cpu(rhdr->fix_num);
++
++      if (bytes <= offsetof(struct INDEX_BUFFER, ihdr) ||
++          rhdr->sign != NTFS_INDX_SIGNATURE ||
++          fo < sizeof(struct INDEX_BUFFER)
++          /* Check index buffer vbn. */
++          || (vbn && *vbn != le64_to_cpu(ib->vbn)) || (fo % sizeof(short)) ||
++          fo + fn * sizeof(short) >= bytes ||
++          fn != ((bytes >> SECTOR_SHIFT) + 1)) {
++              /* incorrect index buffer. */
++              return false;
++      }
++
++      return index_hdr_check(&ib->ihdr,
++                             bytes - offsetof(struct INDEX_BUFFER, ihdr));
++}
++
+ void fnd_clear(struct ntfs_fnd *fnd)
+ {
+       int i;
+-      for (i = 0; i < fnd->level; i++) {
++      for (i = fnd->level - 1; i >= 0; i--) {
+               struct indx_node *n = fnd->nodes[i];
+               if (!n)
+@@ -828,9 +875,16 @@ int indx_init(struct ntfs_index *indx, s
+       u32 t32;
+       const struct INDEX_ROOT *root = resident_data(attr);
++      t32 = le32_to_cpu(attr->res.data_size);
++      if (t32 <= offsetof(struct INDEX_ROOT, ihdr) ||
++          !index_hdr_check(&root->ihdr,
++                           t32 - offsetof(struct INDEX_ROOT, ihdr))) {
++              goto out;
++      }
++
+       /* Check root fields. */
+       if (!root->index_block_clst)
+-              return -EINVAL;
++              goto out;
+       indx->type = type;
+       indx->idx2vbn_bits = __ffs(root->index_block_clst);
+@@ -842,19 +896,19 @@ int indx_init(struct ntfs_index *indx, s
+       if (t32 < sbi->cluster_size) {
+               /* Index record is smaller than a cluster, use 512 blocks. */
+               if (t32 != root->index_block_clst * SECTOR_SIZE)
+-                      return -EINVAL;
++                      goto out;
+               /* Check alignment to a cluster. */
+               if ((sbi->cluster_size >> SECTOR_SHIFT) &
+                   (root->index_block_clst - 1)) {
+-                      return -EINVAL;
++                      goto out;
+               }
+               indx->vbn2vbo_bits = SECTOR_SHIFT;
+       } else {
+               /* Index record must be a multiple of cluster size. */
+               if (t32 != root->index_block_clst << sbi->cluster_bits)
+-                      return -EINVAL;
++                      goto out;
+               indx->vbn2vbo_bits = sbi->cluster_bits;
+       }
+@@ -862,7 +916,14 @@ int indx_init(struct ntfs_index *indx, s
+       init_rwsem(&indx->run_lock);
+       indx->cmp = get_cmp_func(root);
+-      return indx->cmp ? 0 : -EINVAL;
++      if (!indx->cmp)
++              goto out;
++
++      return 0;
++
++out:
++      ntfs_set_state(sbi, NTFS_DIRTY_DIRTY);
++      return -EINVAL;
+ }
+ static struct indx_node *indx_new(struct ntfs_index *indx,
+@@ -1020,6 +1081,13 @@ int indx_read(struct ntfs_index *indx, s
+               goto out;
+ ok:
++      if (!index_buf_check(ib, bytes, &vbn)) {
++              ntfs_inode_err(&ni->vfs_inode, "directory corrupted");
++              ntfs_set_state(ni->mi.sbi, NTFS_DIRTY_ERROR);
++              err = -EINVAL;
++              goto out;
++      }
++
+       if (err == -E_NTFS_FIXUP) {
+               ntfs_write_bh(ni->mi.sbi, &ib->rhdr, &in->nb, 0);
+               err = 0;
+@@ -1607,9 +1675,9 @@ static int indx_insert_into_root(struct
+       if (err) {
+               /* Restore root. */
+-              if (mi_resize_attr(mi, attr, -ds_root))
++              if (mi_resize_attr(mi, attr, -ds_root)) {
+                       memcpy(attr, a_root, asize);
+-              else {
++              } else {
+                       /* Bug? */
+                       ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
+               }
+--- a/fs/ntfs3/inode.c
++++ b/fs/ntfs3/inode.c
+@@ -81,7 +81,7 @@ static struct inode *ntfs_read_mft(struc
+                        le16_to_cpu(ref->seq), le16_to_cpu(rec->seq));
+               goto out;
+       } else if (!is_rec_inuse(rec)) {
+-              err = -EINVAL;
++              err = -ESTALE;
+               ntfs_err(sb, "Inode r=%x is not in use!", (u32)ino);
+               goto out;
+       }
+@@ -92,8 +92,10 @@ static struct inode *ntfs_read_mft(struc
+               goto out;
+       }
+-      if (!is_rec_base(rec))
+-              goto Ok;
++      if (!is_rec_base(rec)) {
++              err = -EINVAL;
++              goto out;
++      }
+       /* Record should contain $I30 root. */
+       is_dir = rec->flags & RECORD_FLAG_DIR;
+@@ -472,7 +474,6 @@ end_enum:
+               inode->i_flags |= S_NOSEC;
+       }
+-Ok:
+       if (ino == MFT_REC_MFT && !sb->s_root)
+               sbi->mft.ni = NULL;
+@@ -526,6 +527,9 @@ struct inode *ntfs_iget5(struct super_bl
+               _ntfs_bad_inode(inode);
+       }
++      if (IS_ERR(inode) && name)
++              ntfs_set_state(sb->s_fs_info, NTFS_DIRTY_ERROR);
++
+       return inode;
+ }
+@@ -1641,10 +1645,8 @@ out6:
+               ntfs_remove_reparse(sbi, IO_REPARSE_TAG_SYMLINK, &new_de->ref);
+ out5:
+-      if (S_ISDIR(mode) || run_is_empty(&ni->file.run))
+-              goto out4;
+-
+-      run_deallocate(sbi, &ni->file.run, false);
++      if (!S_ISDIR(mode))
++              run_deallocate(sbi, &ni->file.run, false);
+ out4:
+       clear_rec_inuse(rec);
+--- a/fs/ntfs3/ntfs_fs.h
++++ b/fs/ntfs3/ntfs_fs.h
+@@ -794,12 +794,12 @@ int run_pack(const struct runs_tree *run
+            u32 run_buf_size, CLST *packed_vcns);
+ int run_unpack(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
+              CLST svcn, CLST evcn, CLST vcn, const u8 *run_buf,
+-             u32 run_buf_size);
++             int run_buf_size);
+ #ifdef NTFS3_CHECK_FREE_CLST
+ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
+                 CLST svcn, CLST evcn, CLST vcn, const u8 *run_buf,
+-                u32 run_buf_size);
++                int run_buf_size);
+ #else
+ #define run_unpack_ex run_unpack
+ #endif
+--- a/fs/ntfs3/run.c
++++ b/fs/ntfs3/run.c
+@@ -919,12 +919,15 @@ out:
+  */
+ int run_unpack(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
+              CLST svcn, CLST evcn, CLST vcn, const u8 *run_buf,
+-             u32 run_buf_size)
++             int run_buf_size)
+ {
+       u64 prev_lcn, vcn64, lcn, next_vcn;
+       const u8 *run_last, *run_0;
+       bool is_mft = ino == MFT_REC_MFT;
++      if (run_buf_size < 0)
++              return -EINVAL;
++
+       /* Check for empty. */
+       if (evcn + 1 == svcn)
+               return 0;
+@@ -1046,7 +1049,7 @@ int run_unpack(struct runs_tree *run, st
+  */
+ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
+                 CLST svcn, CLST evcn, CLST vcn, const u8 *run_buf,
+-                u32 run_buf_size)
++                int run_buf_size)
+ {
+       int ret, err;
+       CLST next_vcn, lcn, len;
+--- a/fs/ntfs3/xattr.c
++++ b/fs/ntfs3/xattr.c
+@@ -42,28 +42,26 @@ static inline size_t packed_ea_size(cons
+  * Assume there is at least one xattr in the list.
+  */
+ static inline bool find_ea(const struct EA_FULL *ea_all, u32 bytes,
+-                         const char *name, u8 name_len, u32 *off)
++                         const char *name, u8 name_len, u32 *off, u32 *ea_sz)
+ {
+-      *off = 0;
++      u32 ea_size;
+-      if (!ea_all || !bytes)
++      *off = 0;
++      if (!ea_all)
+               return false;
+-      for (;;) {
++      for (; *off < bytes; *off += ea_size) {
+               const struct EA_FULL *ea = Add2Ptr(ea_all, *off);
+-              u32 next_off = *off + unpacked_ea_size(ea);
+-
+-              if (next_off > bytes)
+-                      return false;
+-
++              ea_size = unpacked_ea_size(ea);
+               if (ea->name_len == name_len &&
+-                  !memcmp(ea->name, name, name_len))
++                  !memcmp(ea->name, name, name_len)) {
++                      if (ea_sz)
++                              *ea_sz = ea_size;
+                       return true;
+-
+-              *off = next_off;
+-              if (next_off >= bytes)
+-                      return false;
++              }
+       }
++
++      return false;
+ }
+ /*
+@@ -74,12 +72,12 @@ static inline bool find_ea(const struct
+ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
+                       size_t add_bytes, const struct EA_INFO **info)
+ {
+-      int err;
++      int err = -EINVAL;
+       struct ntfs_sb_info *sbi = ni->mi.sbi;
+       struct ATTR_LIST_ENTRY *le = NULL;
+       struct ATTRIB *attr_info, *attr_ea;
+       void *ea_p;
+-      u32 size;
++      u32 size, off, ea_size;
+       static_assert(le32_to_cpu(ATTR_EA_INFO) < le32_to_cpu(ATTR_EA));
+@@ -96,24 +94,31 @@ static int ntfs_read_ea(struct ntfs_inod
+       *info = resident_data_ex(attr_info, sizeof(struct EA_INFO));
+       if (!*info)
+-              return -EINVAL;
++              goto out;
+       /* Check Ea limit. */
+       size = le32_to_cpu((*info)->size);
+-      if (size > sbi->ea_max_size)
+-              return -EFBIG;
++      if (size > sbi->ea_max_size) {
++              err = -EFBIG;
++              goto out;
++      }
+-      if (attr_size(attr_ea) > sbi->ea_max_size)
+-              return -EFBIG;
++      if (attr_size(attr_ea) > sbi->ea_max_size) {
++              err = -EFBIG;
++              goto out;
++      }
++
++      if (!size) {
++              /* EA info persists, but xattr is empty. Looks like EA problem. */
++              goto out;
++      }
+       /* Allocate memory for packed Ea. */
+       ea_p = kmalloc(size_add(size, add_bytes), GFP_NOFS);
+       if (!ea_p)
+               return -ENOMEM;
+-      if (!size) {
+-              /* EA info persists, but xattr is empty. Looks like EA problem. */
+-      } else if (attr_ea->non_res) {
++      if (attr_ea->non_res) {
+               struct runs_tree run;
+               run_init(&run);
+@@ -124,24 +129,52 @@ static int ntfs_read_ea(struct ntfs_inod
+               run_close(&run);
+               if (err)
+-                      goto out;
++                      goto out1;
+       } else {
+               void *p = resident_data_ex(attr_ea, size);
+-              if (!p) {
+-                      err = -EINVAL;
+-                      goto out;
+-              }
++              if (!p)
++                      goto out1;
+               memcpy(ea_p, p, size);
+       }
+       memset(Add2Ptr(ea_p, size), 0, add_bytes);
++
++      /* Check all attributes for consistency. */
++      for (off = 0; off < size; off += ea_size) {
++              const struct EA_FULL *ef = Add2Ptr(ea_p, off);
++              u32 bytes = size - off;
++
++              /* Check if we can use field ea->size. */
++              if (bytes < sizeof(ef->size))
++                      goto out1;
++
++              if (ef->size) {
++                      ea_size = le32_to_cpu(ef->size);
++                      if (ea_size > bytes)
++                              goto out1;
++                      continue;
++              }
++
++              /* Check if we can use fields ef->name_len and ef->elength. */
++              if (bytes < offsetof(struct EA_FULL, name))
++                      goto out1;
++
++              ea_size = ALIGN(struct_size(ef, name,
++                                          1 + ef->name_len +
++                                                  le16_to_cpu(ef->elength)),
++                              4);
++              if (ea_size > bytes)
++                      goto out1;
++      }
++
+       *ea = ea_p;
+       return 0;
+-out:
++out1:
+       kfree(ea_p);
+-      *ea = NULL;
++out:
++      ntfs_set_state(sbi, NTFS_DIRTY_DIRTY);
+       return err;
+ }
+@@ -163,6 +196,7 @@ static ssize_t ntfs_list_ea(struct ntfs_
+       const struct EA_FULL *ea;
+       u32 off, size;
+       int err;
++      int ea_size;
+       size_t ret;
+       err = ntfs_read_ea(ni, &ea_all, 0, &info);
+@@ -175,8 +209,9 @@ static ssize_t ntfs_list_ea(struct ntfs_
+       size = le32_to_cpu(info->size);
+       /* Enumerate all xattrs. */
+-      for (ret = 0, off = 0; off < size; off += unpacked_ea_size(ea)) {
++      for (ret = 0, off = 0; off < size; off += ea_size) {
+               ea = Add2Ptr(ea_all, off);
++              ea_size = unpacked_ea_size(ea);
+               if (!ea->name_len)
+                       break;
+@@ -230,7 +265,8 @@ static int ntfs_get_ea(struct inode *ino
+               goto out;
+       /* Enumerate all xattrs. */
+-      if (!find_ea(ea_all, le32_to_cpu(info->size), name, name_len, &off)) {
++      if (!find_ea(ea_all, le32_to_cpu(info->size), name, name_len, &off,
++                   NULL)) {
+               err = -ENODATA;
+               goto out;
+       }
+@@ -272,7 +308,7 @@ static noinline int ntfs_set_ea(struct i
+       struct EA_FULL *new_ea;
+       struct EA_FULL *ea_all = NULL;
+       size_t add, new_pack;
+-      u32 off, size;
++      u32 off, size, ea_sz;
+       __le16 size_pack;
+       struct ATTRIB *attr;
+       struct ATTR_LIST_ENTRY *le;
+@@ -307,9 +343,8 @@ static noinline int ntfs_set_ea(struct i
+               size_pack = ea_info.size_pack;
+       }
+-      if (info && find_ea(ea_all, size, name, name_len, &off)) {
++      if (info && find_ea(ea_all, size, name, name_len, &off, &ea_sz)) {
+               struct EA_FULL *ea;
+-              size_t ea_sz;
+               if (flags & XATTR_CREATE) {
+                       err = -EEXIST;
+@@ -332,8 +367,6 @@ static noinline int ntfs_set_ea(struct i
+               if (ea->flags & FILE_NEED_EA)
+                       le16_add_cpu(&ea_info.count, -1);
+-              ea_sz = unpacked_ea_size(ea);
+-
+               le16_add_cpu(&ea_info.size_pack, 0 - packed_ea_size(ea));
+               memmove(ea, Add2Ptr(ea, ea_sz), size - off - ea_sz);
diff --git a/queue-6.1/ovl-fix-null-pointer-dereference-in-ovl_get_acl_rcu.patch b/queue-6.1/ovl-fix-null-pointer-dereference-in-ovl_get_acl_rcu.patch
new file mode 100644 (file)
index 0000000..2b809bb
--- /dev/null
@@ -0,0 +1,106 @@
+From stable-owner@vger.kernel.org Mon Jul 17 05:11:21 2023
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+Date: Mon, 17 Jul 2023 11:09:04 +0800
+Subject: ovl: fix null pointer dereference in ovl_get_acl_rcu()
+To: <amir73il@gmail.com>, <gregkh@linuxfoundation.org>, <miklos@szeredi.hu>
+Cc: <linux-unionfs@vger.kernel.org>, <stable@vger.kernel.org>, <sashal@kernel.org>
+Message-ID: <20230717030904.1669754-3-chengzhihao1@huawei.com>
+
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+
+[ Upstream commit f4e19e595cc2e76a8a58413eb19d3d9c51328b53 ]
+
+Following process:
+         P1                     P2
+ path_openat
+  link_path_walk
+   may_lookup
+    inode_permission(rcu)
+     ovl_permission
+      acl_permission_check
+       check_acl
+        get_cached_acl_rcu
+        ovl_get_inode_acl
+         realinode = ovl_inode_real(ovl_inode)
+                             drop_cache
+                              __dentry_kill(ovl_dentry)
+                               iput(ovl_inode)
+                                ovl_destroy_inode(ovl_inode)
+                                 dput(oi->__upperdentry)
+                                  dentry_kill(upperdentry)
+                                   dentry_unlink_inode
+                                    upperdentry->d_inode = NULL
+           ovl_inode_upper
+            upperdentry = ovl_i_dentry_upper(ovl_inode)
+            d_inode(upperdentry) // returns NULL
+         IS_POSIXACL(realinode) // NULL pointer dereference
+, will trigger an null pointer dereference at realinode:
+  [  205.472797] BUG: kernel NULL pointer dereference, address:
+                 0000000000000028
+  [  205.476701] CPU: 2 PID: 2713 Comm: ls Not tainted
+                 6.3.0-12064-g2edfa098e750-dirty #1216
+  [  205.478754] RIP: 0010:do_ovl_get_acl+0x5d/0x300
+  [  205.489584] Call Trace:
+  [  205.489812]  <TASK>
+  [  205.490014]  ovl_get_inode_acl+0x26/0x30
+  [  205.490466]  get_cached_acl_rcu+0x61/0xa0
+  [  205.490908]  generic_permission+0x1bf/0x4e0
+  [  205.491447]  ovl_permission+0x79/0x1b0
+  [  205.491917]  inode_permission+0x15e/0x2c0
+  [  205.492425]  link_path_walk+0x115/0x550
+  [  205.493311]  path_lookupat.isra.0+0xb2/0x200
+  [  205.493803]  filename_lookup+0xda/0x240
+  [  205.495747]  vfs_fstatat+0x7b/0xb0
+
+Fetch a reproducer in [Link].
+
+Use the helper ovl_i_path_realinode() to get realinode and then do
+non-nullptr checking.
+
+There are some changes from upstream commit:
+1. Corrusponds to do_ovl_get_acl() in 6.1 is ovl_get_acl()
+2. Context conflicts caused by 6c0a8bfb84af8f3 ("ovl: implement get acl
+   method") is handled.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=217404
+Fixes: 332f606b32b6 ("ovl: enable RCU'd ->get_acl()")
+Cc: <stable@vger.kernel.org> # v5.15
+Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
+Suggested-by: Christian Brauner <brauner@kernel.org>
+Suggested-by: Amir Goldstein <amir73il@gmail.com>
+Signed-off-by: Amir Goldstein <amir73il@gmail.com>
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/overlayfs/inode.c |   12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/fs/overlayfs/inode.c
++++ b/fs/overlayfs/inode.c
+@@ -497,20 +497,20 @@ static void ovl_idmap_posix_acl(struct i
+  */
+ struct posix_acl *ovl_get_acl(struct inode *inode, int type, bool rcu)
+ {
+-      struct inode *realinode = ovl_inode_real(inode);
++      struct inode *realinode;
+       struct posix_acl *acl, *clone;
+       struct path realpath;
+-      if (!IS_POSIXACL(realinode))
+-              return NULL;
+-
+       /* Careful in RCU walk mode */
+-      ovl_i_path_real(inode, &realpath);
+-      if (!realpath.dentry) {
++      realinode = ovl_i_path_real(inode, &realpath);
++      if (!realinode) {
+               WARN_ON(!rcu);
+               return ERR_PTR(-ECHILD);
+       }
++      if (!IS_POSIXACL(realinode))
++              return NULL;
++
+       if (rcu) {
+               acl = get_cached_acl_rcu(realinode, type);
+       } else {
diff --git a/queue-6.1/ovl-let-helper-ovl_i_path_real-return-the-realinode.patch b/queue-6.1/ovl-let-helper-ovl_i_path_real-return-the-realinode.patch
new file mode 100644 (file)
index 0000000..0d1ef32
--- /dev/null
@@ -0,0 +1,74 @@
+From stable-owner@vger.kernel.org Mon Jul 17 05:11:20 2023
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+Date: Mon, 17 Jul 2023 11:09:03 +0800
+Subject: ovl: let helper ovl_i_path_real() return the realinode
+To: <amir73il@gmail.com>, <gregkh@linuxfoundation.org>, <miklos@szeredi.hu>
+Cc: <linux-unionfs@vger.kernel.org>, <stable@vger.kernel.org>, <sashal@kernel.org>
+Message-ID: <20230717030904.1669754-2-chengzhihao1@huawei.com>
+
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+
+[ Upstream commit b2dd05f107b11966e26fe52a313b418364cf497b ]
+
+Let helper ovl_i_path_real() return the realinode to prepare for
+checking non-null realinode in RCU walking path.
+
+[msz] Use d_inode_rcu() since we are depending on the consitency
+between dentry and inode being non-NULL in an RCU setting.
+
+There are some changes from upstream commit:
+1. Context conflicts caused by 73db6a063c785bc ("ovl: port to
+   vfs{g,u}id_t and associated helpers") is handled.
+
+Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
+Signed-off-by: Amir Goldstein <amir73il@gmail.com>
+Fixes: ffa5723c6d25 ("ovl: store lower path in ovl_inode")
+Cc: <stable@vger.kernel.org> # v5.19
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/overlayfs/overlayfs.h |    2 +-
+ fs/overlayfs/util.c      |    7 ++++---
+ 2 files changed, 5 insertions(+), 4 deletions(-)
+
+--- a/fs/overlayfs/overlayfs.h
++++ b/fs/overlayfs/overlayfs.h
+@@ -369,7 +369,7 @@ enum ovl_path_type ovl_path_type(struct
+ void ovl_path_upper(struct dentry *dentry, struct path *path);
+ void ovl_path_lower(struct dentry *dentry, struct path *path);
+ void ovl_path_lowerdata(struct dentry *dentry, struct path *path);
+-void ovl_i_path_real(struct inode *inode, struct path *path);
++struct inode *ovl_i_path_real(struct inode *inode, struct path *path);
+ enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path);
+ enum ovl_path_type ovl_path_realdata(struct dentry *dentry, struct path *path);
+ struct dentry *ovl_dentry_upper(struct dentry *dentry);
+--- a/fs/overlayfs/util.c
++++ b/fs/overlayfs/util.c
+@@ -266,7 +266,7 @@ struct dentry *ovl_i_dentry_upper(struct
+       return ovl_upperdentry_dereference(OVL_I(inode));
+ }
+-void ovl_i_path_real(struct inode *inode, struct path *path)
++struct inode *ovl_i_path_real(struct inode *inode, struct path *path)
+ {
+       path->dentry = ovl_i_dentry_upper(inode);
+       if (!path->dentry) {
+@@ -275,6 +275,8 @@ void ovl_i_path_real(struct inode *inode
+       } else {
+               path->mnt = ovl_upper_mnt(OVL_FS(inode->i_sb));
+       }
++
++      return path->dentry ? d_inode_rcu(path->dentry) : NULL;
+ }
+ struct inode *ovl_inode_upper(struct inode *inode)
+@@ -1121,8 +1123,7 @@ void ovl_copyattr(struct inode *inode)
+       struct inode *realinode;
+       struct user_namespace *real_mnt_userns;
+-      ovl_i_path_real(inode, &realpath);
+-      realinode = d_inode(realpath.dentry);
++      realinode = ovl_i_path_real(inode, &realpath);
+       real_mnt_userns = mnt_user_ns(realpath.mnt);
+       inode->i_uid = i_uid_into_mnt(real_mnt_userns, realinode);
index 9cdf1ddc373f617a3c1edf6db38b7ac5b4ed47ff..3a77e048e85f17f264ae358661fc65a271f82951 100644 (file)
@@ -62,3 +62,8 @@ wifi-rtw89-debug-fix-error-code-in-rtw89_debug_priv_.patch
 net-sched-sch_qfq-refactor-parsing-of-netlink-parame.patch
 net-sched-sch_qfq-account-for-stab-overhead-in-qfq_e.patch
 nvme-pci-fix-dma-direction-of-unmapping-integrity-da.patch
+fs-ntfs3-check-fields-while-reading.patch
+ovl-let-helper-ovl_i_path_real-return-the-realinode.patch
+ovl-fix-null-pointer-dereference-in-ovl_get_acl_rcu.patch
+cifs-fix-session-state-check-in-smb2_find_smb_ses.patch
+drm-client-send-hotplug-event-after-registering-a-client.patch