From 22ff3ae9025122b77218155628b5cd799bc7de42 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 20 Jul 2023 20:10:14 +0200 Subject: [PATCH] 6.1-stable patches 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 --- ...ion-state-check-in-smb2_find_smb_ses.patch | 37 ++ ...lug-event-after-registering-a-client.patch | 176 +++++++ .../fs-ntfs3-check-fields-while-reading.patch | 487 ++++++++++++++++++ ...inter-dereference-in-ovl_get_acl_rcu.patch | 106 ++++ ...ovl_i_path_real-return-the-realinode.patch | 74 +++ queue-6.1/series | 5 + 6 files changed, 885 insertions(+) create mode 100644 queue-6.1/cifs-fix-session-state-check-in-smb2_find_smb_ses.patch create mode 100644 queue-6.1/drm-client-send-hotplug-event-after-registering-a-client.patch create mode 100644 queue-6.1/fs-ntfs3-check-fields-while-reading.patch create mode 100644 queue-6.1/ovl-fix-null-pointer-dereference-in-ovl_get_acl_rcu.patch create mode 100644 queue-6.1/ovl-let-helper-ovl_i_path_real-return-the-realinode.patch 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 index 00000000000..297cf02bd25 --- /dev/null +++ b/queue-6.1/cifs-fix-session-state-check-in-smb2_find_smb_ses.patch @@ -0,0 +1,37 @@ +From 66be5c48ee1b5b8c919cc329fe6d32e16badaa40 Mon Sep 17 00:00:00 2001 +From: Winston Wen +Date: Mon, 26 Jun 2023 11:42:57 +0800 +Subject: cifs: fix session state check in smb2_find_smb_ses + +From: Winston Wen + +commit 66be5c48ee1b5b8c919cc329fe6d32e16badaa40 upstream. + +Chech the session state and skip it if it's exiting. + +Signed-off-by: Winston Wen +Reviewed-by: Shyam Prasad N +Cc: stable@vger.kernel.org +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..d343383a0d7 --- /dev/null +++ b/queue-6.1/drm-client-send-hotplug-event-after-registering-a-client.patch @@ -0,0 +1,176 @@ +From 27655b9bb9f0d9c32b8de8bec649b676898c52d5 Mon Sep 17 00:00:00 2001 +From: Thomas Zimmermann +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 + +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 +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 +Tested-by: Moritz Duge +Tested-by: Torsten Krah +Tested-by: Paul Schyska +Cc: Daniel Vetter +Cc: David Airlie +Cc: Noralf Trønnes +Cc: Maarten Lankhorst +Cc: Maxime Ripard +Cc: Javier Martinez Canillas +Cc: Russell King +Cc: Inki Dae +Cc: Seung-Woo Kim +Cc: Kyungmin Park +Cc: Krzysztof Kozlowski +Cc: Patrik Jakobsson +Cc: Rob Clark +Cc: Abhinav Kumar +Cc: Dmitry Baryshkov +Cc: Tomi Valkeinen +Cc: Alex Deucher +Cc: "Christian König" +Cc: "Pan, Xinhui" +Cc: Thierry Reding +Cc: Mikko Perttunen +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: # v5.2+ +Reviewed-by: Javier Martinez Canillas +Reviewed-by: Dmitry Baryshkov # 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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..df57b7c0fcb --- /dev/null +++ b/queue-6.1/fs-ntfs3-check-fields-while-reading.patch @@ -0,0 +1,487 @@ +From 0e8235d28f3a0e9eda9f02ff67ee566d5f42b66b Mon Sep 17 00:00:00 2001 +From: Konstantin Komarov +Date: Mon, 10 Oct 2022 13:15:33 +0300 +Subject: fs/ntfs3: Check fields while reading + +From: Konstantin Komarov + +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 +Signed-off-by: Konstantin Komarov +Fixes: 82cae269cfa95 ("fs/ntfs3: Add initialization of super block") +Signed-off-by: Lee Jones +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..2b809bb9d2f --- /dev/null +++ b/queue-6.1/ovl-fix-null-pointer-dereference-in-ovl_get_acl_rcu.patch @@ -0,0 +1,106 @@ +From stable-owner@vger.kernel.org Mon Jul 17 05:11:21 2023 +From: Zhihao Cheng +Date: Mon, 17 Jul 2023 11:09:04 +0800 +Subject: ovl: fix null pointer dereference in ovl_get_acl_rcu() +To: , , +Cc: , , +Message-ID: <20230717030904.1669754-3-chengzhihao1@huawei.com> + +From: Zhihao Cheng + +[ 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] + [ 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: # v5.15 +Signed-off-by: Zhihao Cheng +Suggested-by: Christian Brauner +Suggested-by: Amir Goldstein +Signed-off-by: Amir Goldstein +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..0d1ef326441 --- /dev/null +++ b/queue-6.1/ovl-let-helper-ovl_i_path_real-return-the-realinode.patch @@ -0,0 +1,74 @@ +From stable-owner@vger.kernel.org Mon Jul 17 05:11:20 2023 +From: Zhihao Cheng +Date: Mon, 17 Jul 2023 11:09:03 +0800 +Subject: ovl: let helper ovl_i_path_real() return the realinode +To: , , +Cc: , , +Message-ID: <20230717030904.1669754-2-chengzhihao1@huawei.com> + +From: Zhihao Cheng + +[ 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 +Signed-off-by: Amir Goldstein +Fixes: ffa5723c6d25 ("ovl: store lower path in ovl_inode") +Cc: # v5.19 +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman +--- + 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); diff --git a/queue-6.1/series b/queue-6.1/series index 9cdf1ddc373..3a77e048e85 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -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 -- 2.47.3