From: Greg Kroah-Hartman Date: Mon, 7 Oct 2024 10:24:55 +0000 (+0200) Subject: 6.1-stable patches X-Git-Tag: v6.6.55~100 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bd96cf3acee3b04927b30eeb9ba181ffd816c63c;p=thirdparty%2Fkernel%2Fstable-queue.git 6.1-stable patches added patches: ext4-aovid-use-after-free-in-ext4_ext_insert_extent.patch ext4-correct-encrypted-dentry-name-hash-when-not-casefolded.patch ext4-dax-fix-overflowing-extents-beyond-inode-size-when-partially-writing.patch ext4-drop-ppath-from-ext4_ext_replay_update_ex-to-avoid-double-free.patch ext4-fix-double-brelse-the-buffer-of-the-extents-path.patch ext4-fix-fast-commit-inode-enqueueing-during-a-full-journal-commit.patch ext4-fix-incorrect-tid-assumption-in-__jbd2_log_wait_for_space.patch ext4-fix-incorrect-tid-assumption-in-ext4_fc_mark_ineligible.patch ext4-fix-incorrect-tid-assumption-in-ext4_wait_for_tail_page_commit.patch ext4-fix-incorrect-tid-assumption-in-jbd2_journal_shrink_checkpoint_list.patch ext4-fix-slab-use-after-free-in-ext4_split_extent_at.patch ext4-mark-fc-as-ineligible-using-an-handle-in-ext4_xattr_set.patch ext4-no-need-to-continue-when-the-number-of-entries-is-1.patch ext4-propagate-errors-from-ext4_find_extent-in-ext4_insert_range.patch ext4-update-orig_path-in-ext4_find_extent.patch ext4-use-handle-to-mark-fc-as-ineligible-in-__track_dentry_update.patch --- diff --git a/queue-6.1/ext4-aovid-use-after-free-in-ext4_ext_insert_extent.patch b/queue-6.1/ext4-aovid-use-after-free-in-ext4_ext_insert_extent.patch new file mode 100644 index 00000000000..97bc96ab812 --- /dev/null +++ b/queue-6.1/ext4-aovid-use-after-free-in-ext4_ext_insert_extent.patch @@ -0,0 +1,85 @@ +From a164f3a432aae62ca23d03e6d926b122ee5b860d Mon Sep 17 00:00:00 2001 +From: Baokun Li +Date: Thu, 22 Aug 2024 10:35:26 +0800 +Subject: ext4: aovid use-after-free in ext4_ext_insert_extent() + +From: Baokun Li + +commit a164f3a432aae62ca23d03e6d926b122ee5b860d upstream. + +As Ojaswin mentioned in Link, in ext4_ext_insert_extent(), if the path is +reallocated in ext4_ext_create_new_leaf(), we'll use the stale path and +cause UAF. Below is a sample trace with dummy values: + +ext4_ext_insert_extent + path = *ppath = 2000 + ext4_ext_create_new_leaf(ppath) + ext4_find_extent(ppath) + path = *ppath = 2000 + if (depth > path[0].p_maxdepth) + kfree(path = 2000); + *ppath = path = NULL; + path = kcalloc() = 3000 + *ppath = 3000; + return path; + /* here path is still 2000, UAF! */ + eh = path[depth].p_hdr + +================================================================== +BUG: KASAN: slab-use-after-free in ext4_ext_insert_extent+0x26d4/0x3330 +Read of size 8 at addr ffff8881027bf7d0 by task kworker/u36:1/179 +CPU: 3 UID: 0 PID: 179 Comm: kworker/u6:1 Not tainted 6.11.0-rc2-dirty #866 +Call Trace: + + ext4_ext_insert_extent+0x26d4/0x3330 + ext4_ext_map_blocks+0xe22/0x2d40 + ext4_map_blocks+0x71e/0x1700 + ext4_do_writepages+0x1290/0x2800 +[...] + +Allocated by task 179: + ext4_find_extent+0x81c/0x1f70 + ext4_ext_map_blocks+0x146/0x2d40 + ext4_map_blocks+0x71e/0x1700 + ext4_do_writepages+0x1290/0x2800 + ext4_writepages+0x26d/0x4e0 + do_writepages+0x175/0x700 +[...] + +Freed by task 179: + kfree+0xcb/0x240 + ext4_find_extent+0x7c0/0x1f70 + ext4_ext_insert_extent+0xa26/0x3330 + ext4_ext_map_blocks+0xe22/0x2d40 + ext4_map_blocks+0x71e/0x1700 + ext4_do_writepages+0x1290/0x2800 + ext4_writepages+0x26d/0x4e0 + do_writepages+0x175/0x700 +[...] +================================================================== + +So use *ppath to update the path to avoid the above problem. + +Reported-by: Ojaswin Mujoo +Closes: https://lore.kernel.org/r/ZqyL6rmtwl6N4MWR@li-bb2b2a4c-3307-11b2-a85c-8fa5c3a69313.ibm.com +Fixes: 10809df84a4d ("ext4: teach ext4_ext_find_extent() to realloc path if necessary") +Cc: stable@kernel.org +Signed-off-by: Baokun Li +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20240822023545.1994557-7-libaokun@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/extents.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -2103,6 +2103,7 @@ prepend: + ppath, newext); + if (err) + goto cleanup; ++ path = *ppath; + depth = ext_depth(inode); + eh = path[depth].p_hdr; + diff --git a/queue-6.1/ext4-correct-encrypted-dentry-name-hash-when-not-casefolded.patch b/queue-6.1/ext4-correct-encrypted-dentry-name-hash-when-not-casefolded.patch new file mode 100644 index 00000000000..d9831b27617 --- /dev/null +++ b/queue-6.1/ext4-correct-encrypted-dentry-name-hash-when-not-casefolded.patch @@ -0,0 +1,48 @@ +From 70dd7b573afeba9b8f8a33f2ae1e4a9a2ec8c1ec Mon Sep 17 00:00:00 2001 +From: "yao.ly" +Date: Mon, 1 Jul 2024 14:43:39 +0800 +Subject: ext4: correct encrypted dentry name hash when not casefolded + +From: yao.ly + +commit 70dd7b573afeba9b8f8a33f2ae1e4a9a2ec8c1ec upstream. + +EXT4_DIRENT_HASH and EXT4_DIRENT_MINOR_HASH will access struct +ext4_dir_entry_hash followed ext4_dir_entry. But there is no ext4_dir_entry_hash +followed when inode is encrypted and not casefolded + +Signed-off-by: yao.ly +Link: https://patch.msgid.link/1719816219-128287-1-git-send-email-yao.ly@linux.alibaba.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/dir.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +--- a/fs/ext4/dir.c ++++ b/fs/ext4/dir.c +@@ -279,12 +279,20 @@ static int ext4_readdir(struct file *fil + struct fscrypt_str de_name = + FSTR_INIT(de->name, + de->name_len); ++ u32 hash; ++ u32 minor_hash; ++ ++ if (IS_CASEFOLDED(inode)) { ++ hash = EXT4_DIRENT_HASH(de); ++ minor_hash = EXT4_DIRENT_MINOR_HASH(de); ++ } else { ++ hash = 0; ++ minor_hash = 0; ++ } + + /* Directory is encrypted */ + err = fscrypt_fname_disk_to_usr(inode, +- EXT4_DIRENT_HASH(de), +- EXT4_DIRENT_MINOR_HASH(de), +- &de_name, &fstr); ++ hash, minor_hash, &de_name, &fstr); + de_name = fstr; + fstr.len = save_len; + if (err) diff --git a/queue-6.1/ext4-dax-fix-overflowing-extents-beyond-inode-size-when-partially-writing.patch b/queue-6.1/ext4-dax-fix-overflowing-extents-beyond-inode-size-when-partially-writing.patch new file mode 100644 index 00000000000..dc29e5cf94b --- /dev/null +++ b/queue-6.1/ext4-dax-fix-overflowing-extents-beyond-inode-size-when-partially-writing.patch @@ -0,0 +1,83 @@ +From dda898d7ffe85931f9cca6d702a51f33717c501e Mon Sep 17 00:00:00 2001 +From: Zhihao Cheng +Date: Fri, 9 Aug 2024 20:15:32 +0800 +Subject: ext4: dax: fix overflowing extents beyond inode size when partially writing + +From: Zhihao Cheng + +commit dda898d7ffe85931f9cca6d702a51f33717c501e upstream. + +The dax_iomap_rw() does two things in each iteration: map written blocks +and copy user data to blocks. If the process is killed by user(See signal +handling in dax_iomap_iter()), the copied data will be returned and added +on inode size, which means that the length of written extents may exceed +the inode size, then fsck will fail. An example is given as: + +dd if=/dev/urandom of=file bs=4M count=1 + dax_iomap_rw + iomap_iter // round 1 + ext4_iomap_begin + ext4_iomap_alloc // allocate 0~2M extents(written flag) + dax_iomap_iter // copy 2M data + iomap_iter // round 2 + iomap_iter_advance + iter->pos += iter->processed // iter->pos = 2M + ext4_iomap_begin + ext4_iomap_alloc // allocate 2~4M extents(written flag) + dax_iomap_iter + fatal_signal_pending + done = iter->pos - iocb->ki_pos // done = 2M + ext4_handle_inode_extension + ext4_update_inode_size // inode size = 2M + +fsck reports: Inode 13, i_size is 2097152, should be 4194304. Fix? + +Fix the problem by truncating extents if the written length is smaller +than expected. + +Fixes: 776722e85d3b ("ext4: DAX iomap write support") +CC: stable@vger.kernel.org +Link: https://bugzilla.kernel.org/show_bug.cgi?id=219136 +Signed-off-by: Zhihao Cheng +Reviewed-by: Jan Kara +Reviewed-by: Zhihao Cheng +Link: https://patch.msgid.link/20240809121532.2105494-1-chengzhihao@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/file.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/fs/ext4/file.c ++++ b/fs/ext4/file.c +@@ -324,10 +324,10 @@ static ssize_t ext4_handle_inode_extensi + * Clean up the inode after DIO or DAX extending write has completed and the + * inode size has been updated using ext4_handle_inode_extension(). + */ +-static void ext4_inode_extension_cleanup(struct inode *inode, ssize_t count) ++static void ext4_inode_extension_cleanup(struct inode *inode, bool need_trunc) + { + lockdep_assert_held_write(&inode->i_rwsem); +- if (count < 0) { ++ if (need_trunc) { + ext4_truncate_failed_write(inode); + /* + * If the truncate operation failed early, then the inode may +@@ -567,7 +567,7 @@ static ssize_t ext4_dio_write_iter(struc + * writeback of delalloc blocks. + */ + WARN_ON_ONCE(ret == -EIOCBQUEUED); +- ext4_inode_extension_cleanup(inode, ret); ++ ext4_inode_extension_cleanup(inode, ret < 0); + } + + out: +@@ -651,7 +651,7 @@ ext4_dax_write_iter(struct kiocb *iocb, + + if (extend) { + ret = ext4_handle_inode_extension(inode, offset, ret); +- ext4_inode_extension_cleanup(inode, ret); ++ ext4_inode_extension_cleanup(inode, ret < (ssize_t)count); + } + out: + inode_unlock(inode); diff --git a/queue-6.1/ext4-drop-ppath-from-ext4_ext_replay_update_ex-to-avoid-double-free.patch b/queue-6.1/ext4-drop-ppath-from-ext4_ext_replay_update_ex-to-avoid-double-free.patch new file mode 100644 index 00000000000..d5c3311c192 --- /dev/null +++ b/queue-6.1/ext4-drop-ppath-from-ext4_ext_replay_update_ex-to-avoid-double-free.patch @@ -0,0 +1,95 @@ +From 5c0f4cc84d3a601c99bc5e6e6eb1cbda542cce95 Mon Sep 17 00:00:00 2001 +From: Baokun Li +Date: Thu, 22 Aug 2024 10:35:27 +0800 +Subject: ext4: drop ppath from ext4_ext_replay_update_ex() to avoid double-free + +From: Baokun Li + +commit 5c0f4cc84d3a601c99bc5e6e6eb1cbda542cce95 upstream. + +When calling ext4_force_split_extent_at() in ext4_ext_replay_update_ex(), +the 'ppath' is updated but it is the 'path' that is freed, thus potentially +triggering a double-free in the following process: + +ext4_ext_replay_update_ex + ppath = path + ext4_force_split_extent_at(&ppath) + ext4_split_extent_at + ext4_ext_insert_extent + ext4_ext_create_new_leaf + ext4_ext_grow_indepth + ext4_find_extent + if (depth > path[0].p_maxdepth) + kfree(path) ---> path First freed + *orig_path = path = NULL ---> null ppath + kfree(path) ---> path double-free !!! + +So drop the unnecessary ppath and use path directly to avoid this problem. +And use ext4_find_extent() directly to update path, avoiding unnecessary +memory allocation and freeing. Also, propagate the error returned by +ext4_find_extent() instead of using strange error codes. + +Fixes: 8016e29f4362 ("ext4: fast commit recovery path") +Cc: stable@kernel.org +Signed-off-by: Baokun Li +Reviewed-by: Jan Kara +Reviewed-by: Ojaswin Mujoo +Tested-by: Ojaswin Mujoo +Link: https://patch.msgid.link/20240822023545.1994557-8-libaokun@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/extents.c | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -5926,7 +5926,7 @@ out: + int ext4_ext_replay_update_ex(struct inode *inode, ext4_lblk_t start, + int len, int unwritten, ext4_fsblk_t pblk) + { +- struct ext4_ext_path *path = NULL, *ppath; ++ struct ext4_ext_path *path; + struct ext4_extent *ex; + int ret; + +@@ -5942,30 +5942,29 @@ int ext4_ext_replay_update_ex(struct ino + if (le32_to_cpu(ex->ee_block) != start || + ext4_ext_get_actual_len(ex) != len) { + /* We need to split this extent to match our extent first */ +- ppath = path; + down_write(&EXT4_I(inode)->i_data_sem); +- ret = ext4_force_split_extent_at(NULL, inode, &ppath, start, 1); ++ ret = ext4_force_split_extent_at(NULL, inode, &path, start, 1); + up_write(&EXT4_I(inode)->i_data_sem); + if (ret) + goto out; +- kfree(path); +- path = ext4_find_extent(inode, start, NULL, 0); ++ ++ path = ext4_find_extent(inode, start, &path, 0); + if (IS_ERR(path)) +- return -1; +- ppath = path; ++ return PTR_ERR(path); + ex = path[path->p_depth].p_ext; + WARN_ON(le32_to_cpu(ex->ee_block) != start); ++ + if (ext4_ext_get_actual_len(ex) != len) { + down_write(&EXT4_I(inode)->i_data_sem); +- ret = ext4_force_split_extent_at(NULL, inode, &ppath, ++ ret = ext4_force_split_extent_at(NULL, inode, &path, + start + len, 1); + up_write(&EXT4_I(inode)->i_data_sem); + if (ret) + goto out; +- kfree(path); +- path = ext4_find_extent(inode, start, NULL, 0); ++ ++ path = ext4_find_extent(inode, start, &path, 0); + if (IS_ERR(path)) +- return -EINVAL; ++ return PTR_ERR(path); + ex = path[path->p_depth].p_ext; + } + } diff --git a/queue-6.1/ext4-fix-double-brelse-the-buffer-of-the-extents-path.patch b/queue-6.1/ext4-fix-double-brelse-the-buffer-of-the-extents-path.patch new file mode 100644 index 00000000000..e309cf24d81 --- /dev/null +++ b/queue-6.1/ext4-fix-double-brelse-the-buffer-of-the-extents-path.patch @@ -0,0 +1,100 @@ +From dcaa6c31134c0f515600111c38ed7750003e1b9c Mon Sep 17 00:00:00 2001 +From: Baokun Li +Date: Thu, 22 Aug 2024 10:35:28 +0800 +Subject: ext4: fix double brelse() the buffer of the extents path + +From: Baokun Li + +commit dcaa6c31134c0f515600111c38ed7750003e1b9c upstream. + +In ext4_ext_try_to_merge_up(), set path[1].p_bh to NULL after it has been +released, otherwise it may be released twice. An example of what triggers +this is as follows: + + split2 map split1 +|--------|-------|--------| + +ext4_ext_map_blocks + ext4_ext_handle_unwritten_extents + ext4_split_convert_extents + // path->p_depth == 0 + ext4_split_extent + // 1. do split1 + ext4_split_extent_at + |ext4_ext_insert_extent + | ext4_ext_create_new_leaf + | ext4_ext_grow_indepth + | le16_add_cpu(&neh->eh_depth, 1) + | ext4_find_extent + | // return -ENOMEM + |// get error and try zeroout + |path = ext4_find_extent + | path->p_depth = 1 + |ext4_ext_try_to_merge + | ext4_ext_try_to_merge_up + | path->p_depth = 0 + | brelse(path[1].p_bh) ---> not set to NULL here + |// zeroout success + // 2. update path + ext4_find_extent + // 3. do split2 + ext4_split_extent_at + ext4_ext_insert_extent + ext4_ext_create_new_leaf + ext4_ext_grow_indepth + le16_add_cpu(&neh->eh_depth, 1) + ext4_find_extent + path[0].p_bh = NULL; + path->p_depth = 1 + read_extent_tree_block ---> return err + // path[1].p_bh is still the old value + ext4_free_ext_path + ext4_ext_drop_refs + // path->p_depth == 1 + brelse(path[1].p_bh) ---> brelse a buffer twice + +Finally got the following WARRNING when removing the buffer from lru: + +============================================ +VFS: brelse: Trying to free free buffer +WARNING: CPU: 2 PID: 72 at fs/buffer.c:1241 __brelse+0x58/0x90 +CPU: 2 PID: 72 Comm: kworker/u19:1 Not tainted 6.9.0-dirty #716 +RIP: 0010:__brelse+0x58/0x90 +Call Trace: + + __find_get_block+0x6e7/0x810 + bdev_getblk+0x2b/0x480 + __ext4_get_inode_loc+0x48a/0x1240 + ext4_get_inode_loc+0xb2/0x150 + ext4_reserve_inode_write+0xb7/0x230 + __ext4_mark_inode_dirty+0x144/0x6a0 + ext4_ext_insert_extent+0x9c8/0x3230 + ext4_ext_map_blocks+0xf45/0x2dc0 + ext4_map_blocks+0x724/0x1700 + ext4_do_writepages+0x12d6/0x2a70 +[...] +============================================ + +Fixes: ecb94f5fdf4b ("ext4: collapse a single extent tree block into the inode if possible") +Cc: stable@kernel.org +Signed-off-by: Baokun Li +Reviewed-by: Jan Kara +Reviewed-by: Ojaswin Mujoo +Tested-by: Ojaswin Mujoo +Link: https://patch.msgid.link/20240822023545.1994557-9-libaokun@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/extents.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -1877,6 +1877,7 @@ static void ext4_ext_try_to_merge_up(han + path[0].p_hdr->eh_max = cpu_to_le16(max_root); + + brelse(path[1].p_bh); ++ path[1].p_bh = NULL; + ext4_free_blocks(handle, inode, NULL, blk, 1, + EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); + } diff --git a/queue-6.1/ext4-fix-fast-commit-inode-enqueueing-during-a-full-journal-commit.patch b/queue-6.1/ext4-fix-fast-commit-inode-enqueueing-during-a-full-journal-commit.patch new file mode 100644 index 00000000000..f8d8e195fb0 --- /dev/null +++ b/queue-6.1/ext4-fix-fast-commit-inode-enqueueing-during-a-full-journal-commit.patch @@ -0,0 +1,77 @@ +From 6db3c1575a750fd417a70e0178bdf6efa0dd5037 Mon Sep 17 00:00:00 2001 +From: "Luis Henriques (SUSE)" +Date: Wed, 17 Jul 2024 18:22:20 +0100 +Subject: ext4: fix fast commit inode enqueueing during a full journal commit + +From: Luis Henriques (SUSE) + +commit 6db3c1575a750fd417a70e0178bdf6efa0dd5037 upstream. + +When a full journal commit is on-going, any fast commit has to be enqueued +into a different queue: FC_Q_STAGING instead of FC_Q_MAIN. This enqueueing +is done only once, i.e. if an inode is already queued in a previous fast +commit entry it won't be enqueued again. However, if a full commit starts +_after_ the inode is enqueued into FC_Q_MAIN, the next fast commit needs to +be done into FC_Q_STAGING. And this is not being done in function +ext4_fc_track_template(). + +This patch fixes the issue by re-enqueuing an inode into the STAGING queue +during the fast commit clean-up callback when doing a full commit. However, +to prevent a race with a fast-commit, the clean-up callback has to be called +with the journal locked. + +This bug was found using fstest generic/047. This test creates several 32k +bytes files, sync'ing each of them after it's creation, and then shutting +down the filesystem. Some data may be loss in this operation; for example a +file may have it's size truncated to zero. + +Suggested-by: Jan Kara +Signed-off-by: Luis Henriques (SUSE) +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20240717172220.14201-1-luis.henriques@linux.dev +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/fast_commit.c | 15 ++++++++++++++- + fs/jbd2/journal.c | 2 +- + 2 files changed, 15 insertions(+), 2 deletions(-) + +--- a/fs/ext4/fast_commit.c ++++ b/fs/ext4/fast_commit.c +@@ -1317,8 +1317,21 @@ static void ext4_fc_cleanup(journal_t *j + list_del_init(&iter->i_fc_list); + ext4_clear_inode_state(&iter->vfs_inode, + EXT4_STATE_FC_COMMITTING); +- if (tid_geq(tid, iter->i_sync_tid)) ++ if (tid_geq(tid, iter->i_sync_tid)) { + ext4_fc_reset_inode(&iter->vfs_inode); ++ } else if (full) { ++ /* ++ * We are called after a full commit, inode has been ++ * modified while the commit was running. Re-enqueue ++ * the inode into STAGING, which will then be splice ++ * back into MAIN. This cannot happen during ++ * fastcommit because the journal is locked all the ++ * time in that case (and tid doesn't increase so ++ * tid check above isn't reliable). ++ */ ++ list_add_tail(&EXT4_I(&iter->vfs_inode)->i_fc_list, ++ &sbi->s_fc_q[FC_Q_STAGING]); ++ } + /* Make sure EXT4_STATE_FC_COMMITTING bit is clear */ + smp_mb(); + #if (BITS_PER_LONG < 64) +--- a/fs/jbd2/journal.c ++++ b/fs/jbd2/journal.c +@@ -767,9 +767,9 @@ EXPORT_SYMBOL(jbd2_fc_begin_commit); + */ + static int __jbd2_fc_end_commit(journal_t *journal, tid_t tid, bool fallback) + { +- jbd2_journal_unlock_updates(journal); + if (journal->j_fc_cleanup_callback) + journal->j_fc_cleanup_callback(journal, 0, tid); ++ jbd2_journal_unlock_updates(journal); + write_lock(&journal->j_state_lock); + journal->j_flags &= ~JBD2_FAST_COMMIT_ONGOING; + if (fallback) diff --git a/queue-6.1/ext4-fix-incorrect-tid-assumption-in-__jbd2_log_wait_for_space.patch b/queue-6.1/ext4-fix-incorrect-tid-assumption-in-__jbd2_log_wait_for_space.patch new file mode 100644 index 00000000000..31cda8c6063 --- /dev/null +++ b/queue-6.1/ext4-fix-incorrect-tid-assumption-in-__jbd2_log_wait_for_space.patch @@ -0,0 +1,48 @@ +From 972090651ee15e51abfb2160e986fa050cfc7a40 Mon Sep 17 00:00:00 2001 +From: "Luis Henriques (SUSE)" +Date: Wed, 24 Jul 2024 17:11:16 +0100 +Subject: ext4: fix incorrect tid assumption in __jbd2_log_wait_for_space() + +From: Luis Henriques (SUSE) + +commit 972090651ee15e51abfb2160e986fa050cfc7a40 upstream. + +Function __jbd2_log_wait_for_space() assumes that '0' is not a valid value +for transaction IDs, which is incorrect. Don't assume that and invoke +jbd2_log_wait_commit() if the journal had a committing transaction instead. + +Signed-off-by: Luis Henriques (SUSE) +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20240724161119.13448-3-luis.henriques@linux.dev +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/jbd2/checkpoint.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/fs/jbd2/checkpoint.c ++++ b/fs/jbd2/checkpoint.c +@@ -91,9 +91,12 @@ __releases(&journal->j_state_lock) + if (space_left < nblocks) { + int chkpt = journal->j_checkpoint_transactions != NULL; + tid_t tid = 0; ++ bool has_transaction = false; + +- if (journal->j_committing_transaction) ++ if (journal->j_committing_transaction) { + tid = journal->j_committing_transaction->t_tid; ++ has_transaction = true; ++ } + spin_unlock(&journal->j_list_lock); + write_unlock(&journal->j_state_lock); + if (chkpt) { +@@ -101,7 +104,7 @@ __releases(&journal->j_state_lock) + } else if (jbd2_cleanup_journal_tail(journal) == 0) { + /* We were able to recover space; yay! */ + ; +- } else if (tid) { ++ } else if (has_transaction) { + /* + * jbd2_journal_commit_transaction() may want + * to take the checkpoint_mutex if JBD2_FLUSHED diff --git a/queue-6.1/ext4-fix-incorrect-tid-assumption-in-ext4_fc_mark_ineligible.patch b/queue-6.1/ext4-fix-incorrect-tid-assumption-in-ext4_fc_mark_ineligible.patch new file mode 100644 index 00000000000..ed924e7b1df --- /dev/null +++ b/queue-6.1/ext4-fix-incorrect-tid-assumption-in-ext4_fc_mark_ineligible.patch @@ -0,0 +1,63 @@ +From ebc4b2c1ac92fc0f8bf3f5a9c285a871d5084a6b Mon Sep 17 00:00:00 2001 +From: "Luis Henriques (SUSE)" +Date: Wed, 24 Jul 2024 17:11:18 +0100 +Subject: ext4: fix incorrect tid assumption in ext4_fc_mark_ineligible() + +From: Luis Henriques (SUSE) + +commit ebc4b2c1ac92fc0f8bf3f5a9c285a871d5084a6b upstream. + +Function jbd2_journal_shrink_checkpoint_list() assumes that '0' is not a +valid value for transaction IDs, which is incorrect. + +Furthermore, the sbi->s_fc_ineligible_tid handling also makes the same +assumption by being initialised to '0'. Fortunately, the sb flag +EXT4_MF_FC_INELIGIBLE can be used to check whether sbi->s_fc_ineligible_tid +has been previously set instead of comparing it with '0'. + +Signed-off-by: Luis Henriques (SUSE) +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20240724161119.13448-5-luis.henriques@linux.dev +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/fast_commit.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +--- a/fs/ext4/fast_commit.c ++++ b/fs/ext4/fast_commit.c +@@ -339,22 +339,29 @@ void ext4_fc_mark_ineligible(struct supe + { + struct ext4_sb_info *sbi = EXT4_SB(sb); + tid_t tid; ++ bool has_transaction = true; ++ bool is_ineligible; + + if (ext4_fc_disabled(sb)) + return; + +- ext4_set_mount_flag(sb, EXT4_MF_FC_INELIGIBLE); + if (handle && !IS_ERR(handle)) + tid = handle->h_transaction->t_tid; + else { + read_lock(&sbi->s_journal->j_state_lock); +- tid = sbi->s_journal->j_running_transaction ? +- sbi->s_journal->j_running_transaction->t_tid : 0; ++ if (sbi->s_journal->j_running_transaction) ++ tid = sbi->s_journal->j_running_transaction->t_tid; ++ else ++ has_transaction = false; + read_unlock(&sbi->s_journal->j_state_lock); + } + spin_lock(&sbi->s_fc_lock); +- if (tid_gt(tid, sbi->s_fc_ineligible_tid)) ++ is_ineligible = ext4_test_mount_flag(sb, EXT4_MF_FC_INELIGIBLE); ++ if (has_transaction && ++ (!is_ineligible || ++ (is_ineligible && tid_gt(tid, sbi->s_fc_ineligible_tid)))) + sbi->s_fc_ineligible_tid = tid; ++ ext4_set_mount_flag(sb, EXT4_MF_FC_INELIGIBLE); + spin_unlock(&sbi->s_fc_lock); + WARN_ON(reason >= EXT4_FC_REASON_MAX); + sbi->s_fc_stats.fc_ineligible_reason_count[reason]++; diff --git a/queue-6.1/ext4-fix-incorrect-tid-assumption-in-ext4_wait_for_tail_page_commit.patch b/queue-6.1/ext4-fix-incorrect-tid-assumption-in-ext4_wait_for_tail_page_commit.patch new file mode 100644 index 00000000000..49050182782 --- /dev/null +++ b/queue-6.1/ext4-fix-incorrect-tid-assumption-in-ext4_wait_for_tail_page_commit.patch @@ -0,0 +1,54 @@ +From dd589b0f1445e1ea1085b98edca6e4d5dedb98d0 Mon Sep 17 00:00:00 2001 +From: "Luis Henriques (SUSE)" +Date: Wed, 24 Jul 2024 17:11:15 +0100 +Subject: ext4: fix incorrect tid assumption in ext4_wait_for_tail_page_commit() + +From: Luis Henriques (SUSE) + +commit dd589b0f1445e1ea1085b98edca6e4d5dedb98d0 upstream. + +Function ext4_wait_for_tail_page_commit() assumes that '0' is not a valid +value for transaction IDs, which is incorrect. Don't assume that and invoke +jbd2_log_wait_commit() if the journal had a committing transaction instead. + +Signed-off-by: Luis Henriques (SUSE) +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20240724161119.13448-2-luis.henriques@linux.dev +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/inode.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -5350,8 +5350,9 @@ static void ext4_wait_for_tail_page_comm + { + unsigned offset; + journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; +- tid_t commit_tid = 0; ++ tid_t commit_tid; + int ret; ++ bool has_transaction; + + offset = inode->i_size & (PAGE_SIZE - 1); + /* +@@ -5376,12 +5377,14 @@ static void ext4_wait_for_tail_page_comm + folio_put(folio); + if (ret != -EBUSY) + return; +- commit_tid = 0; ++ has_transaction = false; + read_lock(&journal->j_state_lock); +- if (journal->j_committing_transaction) ++ if (journal->j_committing_transaction) { + commit_tid = journal->j_committing_transaction->t_tid; ++ has_transaction = true; ++ } + read_unlock(&journal->j_state_lock); +- if (commit_tid) ++ if (has_transaction) + jbd2_log_wait_commit(journal, commit_tid); + } + } diff --git a/queue-6.1/ext4-fix-incorrect-tid-assumption-in-jbd2_journal_shrink_checkpoint_list.patch b/queue-6.1/ext4-fix-incorrect-tid-assumption-in-jbd2_journal_shrink_checkpoint_list.patch new file mode 100644 index 00000000000..3b5b90cffa8 --- /dev/null +++ b/queue-6.1/ext4-fix-incorrect-tid-assumption-in-jbd2_journal_shrink_checkpoint_list.patch @@ -0,0 +1,55 @@ +From 7a6443e1dad70281f99f0bd394d7fd342481a632 Mon Sep 17 00:00:00 2001 +From: "Luis Henriques (SUSE)" +Date: Wed, 24 Jul 2024 17:11:17 +0100 +Subject: ext4: fix incorrect tid assumption in jbd2_journal_shrink_checkpoint_list() + +From: Luis Henriques (SUSE) + +commit 7a6443e1dad70281f99f0bd394d7fd342481a632 upstream. + +Function jbd2_journal_shrink_checkpoint_list() assumes that '0' is not a +valid value for transaction IDs, which is incorrect. Don't assume that and +use two extra boolean variables to control the loop iterations and keep +track of the first and last tid. + +Signed-off-by: Luis Henriques (SUSE) +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20240724161119.13448-4-luis.henriques@linux.dev +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/jbd2/checkpoint.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/fs/jbd2/checkpoint.c ++++ b/fs/jbd2/checkpoint.c +@@ -424,6 +424,7 @@ unsigned long jbd2_journal_shrink_checkp + tid_t tid = 0; + unsigned long nr_freed = 0; + unsigned long freed; ++ bool first_set = false; + + again: + spin_lock(&journal->j_list_lock); +@@ -443,8 +444,10 @@ again: + else + transaction = journal->j_checkpoint_transactions; + +- if (!first_tid) ++ if (!first_set) { + first_tid = transaction->t_tid; ++ first_set = true; ++ } + last_transaction = journal->j_checkpoint_transactions->t_cpprev; + next_transaction = transaction; + last_tid = last_transaction->t_tid; +@@ -474,7 +477,7 @@ again: + spin_unlock(&journal->j_list_lock); + cond_resched(); + +- if (*nr_to_scan && next_tid) ++ if (*nr_to_scan && journal->j_shrink_transaction) + goto again; + out: + trace_jbd2_shrink_checkpoint_list(journal, first_tid, tid, last_tid, diff --git a/queue-6.1/ext4-fix-slab-use-after-free-in-ext4_split_extent_at.patch b/queue-6.1/ext4-fix-slab-use-after-free-in-ext4_split_extent_at.patch new file mode 100644 index 00000000000..4d4bb897d65 --- /dev/null +++ b/queue-6.1/ext4-fix-slab-use-after-free-in-ext4_split_extent_at.patch @@ -0,0 +1,127 @@ +From c26ab35702f8cd0cdc78f96aa5856bfb77be798f Mon Sep 17 00:00:00 2001 +From: Baokun Li +Date: Thu, 22 Aug 2024 10:35:23 +0800 +Subject: ext4: fix slab-use-after-free in ext4_split_extent_at() + +From: Baokun Li + +commit c26ab35702f8cd0cdc78f96aa5856bfb77be798f upstream. + +We hit the following use-after-free: + +================================================================== +BUG: KASAN: slab-use-after-free in ext4_split_extent_at+0xba8/0xcc0 +Read of size 2 at addr ffff88810548ed08 by task kworker/u20:0/40 +CPU: 0 PID: 40 Comm: kworker/u20:0 Not tainted 6.9.0-dirty #724 +Call Trace: + + kasan_report+0x93/0xc0 + ext4_split_extent_at+0xba8/0xcc0 + ext4_split_extent.isra.0+0x18f/0x500 + ext4_split_convert_extents+0x275/0x750 + ext4_ext_handle_unwritten_extents+0x73e/0x1580 + ext4_ext_map_blocks+0xe20/0x2dc0 + ext4_map_blocks+0x724/0x1700 + ext4_do_writepages+0x12d6/0x2a70 +[...] + +Allocated by task 40: + __kmalloc_noprof+0x1ac/0x480 + ext4_find_extent+0xf3b/0x1e70 + ext4_ext_map_blocks+0x188/0x2dc0 + ext4_map_blocks+0x724/0x1700 + ext4_do_writepages+0x12d6/0x2a70 +[...] + +Freed by task 40: + kfree+0xf1/0x2b0 + ext4_find_extent+0xa71/0x1e70 + ext4_ext_insert_extent+0xa22/0x3260 + ext4_split_extent_at+0x3ef/0xcc0 + ext4_split_extent.isra.0+0x18f/0x500 + ext4_split_convert_extents+0x275/0x750 + ext4_ext_handle_unwritten_extents+0x73e/0x1580 + ext4_ext_map_blocks+0xe20/0x2dc0 + ext4_map_blocks+0x724/0x1700 + ext4_do_writepages+0x12d6/0x2a70 +[...] +================================================================== + +The flow of issue triggering is as follows: + +ext4_split_extent_at + path = *ppath + ext4_ext_insert_extent(ppath) + ext4_ext_create_new_leaf(ppath) + ext4_find_extent(orig_path) + path = *orig_path + read_extent_tree_block + // return -ENOMEM or -EIO + ext4_free_ext_path(path) + kfree(path) + *orig_path = NULL + a. If err is -ENOMEM: + ext4_ext_dirty(path + path->p_depth) + // path use-after-free !!! + b. If err is -EIO and we have EXT_DEBUG defined: + ext4_ext_show_leaf(path) + eh = path[depth].p_hdr + // path also use-after-free !!! + +So when trying to zeroout or fix the extent length, call ext4_find_extent() +to update the path. + +In addition we use *ppath directly as an ext4_ext_show_leaf() input to +avoid possible use-after-free when EXT_DEBUG is defined, and to avoid +unnecessary path updates. + +Fixes: dfe5080939ea ("ext4: drop EXT4_EX_NOFREE_ON_ERR from rest of extents handling code") +Cc: stable@kernel.org +Signed-off-by: Baokun Li +Reviewed-by: Jan Kara +Reviewed-by: Ojaswin Mujoo +Tested-by: Ojaswin Mujoo +Link: https://patch.msgid.link/20240822023545.1994557-4-libaokun@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/extents.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -3232,6 +3232,25 @@ static int ext4_split_extent_at(handle_t + if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + goto out; + ++ /* ++ * Update path is required because previous ext4_ext_insert_extent() ++ * may have freed or reallocated the path. Using EXT4_EX_NOFAIL ++ * guarantees that ext4_find_extent() will not return -ENOMEM, ++ * otherwise -ENOMEM will cause a retry in do_writepages(), and a ++ * WARN_ON may be triggered in ext4_da_update_reserve_space() due to ++ * an incorrect ee_len causing the i_reserved_data_blocks exception. ++ */ ++ path = ext4_find_extent(inode, ee_block, ppath, ++ flags | EXT4_EX_NOFAIL); ++ if (IS_ERR(path)) { ++ EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", ++ split, PTR_ERR(path)); ++ return PTR_ERR(path); ++ } ++ depth = ext_depth(inode); ++ ex = path[depth].p_ext; ++ *ppath = path; ++ + if (EXT4_EXT_MAY_ZEROOUT & split_flag) { + if (split_flag & (EXT4_EXT_DATA_VALID1|EXT4_EXT_DATA_VALID2)) { + if (split_flag & EXT4_EXT_DATA_VALID1) { +@@ -3284,7 +3303,7 @@ fix_extent_len: + ext4_ext_dirty(handle, inode, path + path->p_depth); + return err; + out: +- ext4_ext_show_leaf(inode, path); ++ ext4_ext_show_leaf(inode, *ppath); + return err; + } + diff --git a/queue-6.1/ext4-mark-fc-as-ineligible-using-an-handle-in-ext4_xattr_set.patch b/queue-6.1/ext4-mark-fc-as-ineligible-using-an-handle-in-ext4_xattr_set.patch new file mode 100644 index 00000000000..cd5334e3ad1 --- /dev/null +++ b/queue-6.1/ext4-mark-fc-as-ineligible-using-an-handle-in-ext4_xattr_set.patch @@ -0,0 +1,46 @@ +From 04e6ce8f06d161399e5afde3df5dcfa9455b4952 Mon Sep 17 00:00:00 2001 +From: "Luis Henriques (SUSE)" +Date: Mon, 23 Sep 2024 11:49:09 +0100 +Subject: ext4: mark fc as ineligible using an handle in ext4_xattr_set() + +From: Luis Henriques (SUSE) + +commit 04e6ce8f06d161399e5afde3df5dcfa9455b4952 upstream. + +Calling ext4_fc_mark_ineligible() with a NULL handle is racy and may result +in a fast-commit being done before the filesystem is effectively marked as +ineligible. This patch moves the call to this function so that an handle +can be used. If a transaction fails to start, then there's not point in +trying to mark the filesystem as ineligible, and an error will eventually be +returned to user-space. + +Suggested-by: Jan Kara +Signed-off-by: Luis Henriques (SUSE) +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20240923104909.18342-3-luis.henriques@linux.dev +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/xattr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -2505,6 +2505,8 @@ retry: + + error = ext4_xattr_set_handle(handle, inode, name_index, name, + value, value_len, flags); ++ ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR, ++ handle); + error2 = ext4_journal_stop(handle); + if (error == -ENOSPC && + ext4_should_retry_alloc(sb, &retries)) +@@ -2512,7 +2514,6 @@ retry: + if (error == 0) + error = error2; + } +- ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR, NULL); + + return error; + } diff --git a/queue-6.1/ext4-no-need-to-continue-when-the-number-of-entries-is-1.patch b/queue-6.1/ext4-no-need-to-continue-when-the-number-of-entries-is-1.patch new file mode 100644 index 00000000000..6da5da81172 --- /dev/null +++ b/queue-6.1/ext4-no-need-to-continue-when-the-number-of-entries-is-1.patch @@ -0,0 +1,33 @@ +From 1a00a393d6a7fb1e745a41edd09019bd6a0ad64c Mon Sep 17 00:00:00 2001 +From: Edward Adam Davis +Date: Mon, 1 Jul 2024 22:25:03 +0800 +Subject: ext4: no need to continue when the number of entries is 1 + +From: Edward Adam Davis + +commit 1a00a393d6a7fb1e745a41edd09019bd6a0ad64c upstream. + +Fixes: ac27a0ec112a ("[PATCH] ext4: initial copy of files from ext3") +Reported-by: syzbot+ae688d469e36fb5138d0@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=ae688d469e36fb5138d0 +Signed-off-by: Edward Adam Davis +Reported-and-tested-by: syzbot+ae688d469e36fb5138d0@syzkaller.appspotmail.com +Link: https://patch.msgid.link/tencent_BE7AEE6C7C2D216CB8949CE8E6EE7ECC2C0A@qq.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/namei.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -2047,7 +2047,7 @@ static struct ext4_dir_entry_2 *do_split + split = count/2; + + hash2 = map[split].hash; +- continued = hash2 == map[split - 1].hash; ++ continued = split > 0 ? hash2 == map[split - 1].hash : 0; + dxtrace(printk(KERN_INFO "Split block %lu at %x, %i/%i\n", + (unsigned long)dx_get_block(frame->at), + hash2, split, count-split)); diff --git a/queue-6.1/ext4-propagate-errors-from-ext4_find_extent-in-ext4_insert_range.patch b/queue-6.1/ext4-propagate-errors-from-ext4_find_extent-in-ext4_insert_range.patch new file mode 100644 index 00000000000..8962ad57e1b --- /dev/null +++ b/queue-6.1/ext4-propagate-errors-from-ext4_find_extent-in-ext4_insert_range.patch @@ -0,0 +1,37 @@ +From 369c944ed1d7c3fb7b35f24e4735761153afe7b3 Mon Sep 17 00:00:00 2001 +From: Baokun Li +Date: Thu, 22 Aug 2024 10:35:30 +0800 +Subject: ext4: propagate errors from ext4_find_extent() in ext4_insert_range() + +From: Baokun Li + +commit 369c944ed1d7c3fb7b35f24e4735761153afe7b3 upstream. + +Even though ext4_find_extent() returns an error, ext4_insert_range() still +returns 0. This may confuse the user as to why fallocate returns success, +but the contents of the file are not as expected. So propagate the error +returned by ext4_find_extent() to avoid inconsistencies. + +Fixes: 331573febb6a ("ext4: Add support FALLOC_FL_INSERT_RANGE for fallocate") +Cc: stable@kernel.org +Signed-off-by: Baokun Li +Reviewed-by: Jan Kara +Reviewed-by: Ojaswin Mujoo +Tested-by: Ojaswin Mujoo +Link: https://patch.msgid.link/20240822023545.1994557-11-libaokun@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/extents.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -5570,6 +5570,7 @@ static int ext4_insert_range(struct file + path = ext4_find_extent(inode, offset_lblk, NULL, 0); + if (IS_ERR(path)) { + up_write(&EXT4_I(inode)->i_data_sem); ++ ret = PTR_ERR(path); + goto out_stop; + } + diff --git a/queue-6.1/ext4-update-orig_path-in-ext4_find_extent.patch b/queue-6.1/ext4-update-orig_path-in-ext4_find_extent.patch new file mode 100644 index 00000000000..4c0d7c51d81 --- /dev/null +++ b/queue-6.1/ext4-update-orig_path-in-ext4_find_extent.patch @@ -0,0 +1,86 @@ +From 5b4b2dcace35f618fe361a87bae6f0d13af31bc1 Mon Sep 17 00:00:00 2001 +From: Baokun Li +Date: Thu, 22 Aug 2024 10:35:25 +0800 +Subject: ext4: update orig_path in ext4_find_extent() + +From: Baokun Li + +commit 5b4b2dcace35f618fe361a87bae6f0d13af31bc1 upstream. + +In ext4_find_extent(), if the path is not big enough, we free it and set +*orig_path to NULL. But after reallocating and successfully initializing +the path, we don't update *orig_path, in which case the caller gets a +valid path but a NULL ppath, and this may cause a NULL pointer dereference +or a path memory leak. For example: + +ext4_split_extent + path = *ppath = 2000 + ext4_find_extent + if (depth > path[0].p_maxdepth) + kfree(path = 2000); + *orig_path = path = NULL; + path = kcalloc() = 3000 + ext4_split_extent_at(*ppath = NULL) + path = *ppath; + ex = path[depth].p_ext; + // NULL pointer dereference! + +================================================================== +BUG: kernel NULL pointer dereference, address: 0000000000000010 +CPU: 6 UID: 0 PID: 576 Comm: fsstress Not tainted 6.11.0-rc2-dirty #847 +RIP: 0010:ext4_split_extent_at+0x6d/0x560 +Call Trace: + + ext4_split_extent.isra.0+0xcb/0x1b0 + ext4_ext_convert_to_initialized+0x168/0x6c0 + ext4_ext_handle_unwritten_extents+0x325/0x4d0 + ext4_ext_map_blocks+0x520/0xdb0 + ext4_map_blocks+0x2b0/0x690 + ext4_iomap_begin+0x20e/0x2c0 +[...] +================================================================== + +Therefore, *orig_path is updated when the extent lookup succeeds, so that +the caller can safely use path or *ppath. + +Fixes: 10809df84a4d ("ext4: teach ext4_ext_find_extent() to realloc path if necessary") +Cc: stable@kernel.org +Signed-off-by: Baokun Li +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20240822023545.1994557-6-libaokun@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/extents.c | 3 ++- + fs/ext4/move_extent.c | 1 - + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -957,6 +957,8 @@ ext4_find_extent(struct inode *inode, ex + + ext4_ext_show_path(inode, path); + ++ if (orig_path) ++ *orig_path = path; + return path; + + err: +@@ -3251,7 +3253,6 @@ static int ext4_split_extent_at(handle_t + } + depth = ext_depth(inode); + ex = path[depth].p_ext; +- *ppath = path; + + if (EXT4_EXT_MAY_ZEROOUT & split_flag) { + if (split_flag & (EXT4_EXT_DATA_VALID1|EXT4_EXT_DATA_VALID2)) { +--- a/fs/ext4/move_extent.c ++++ b/fs/ext4/move_extent.c +@@ -36,7 +36,6 @@ get_ext_path(struct inode *inode, ext4_l + *ppath = NULL; + return -ENODATA; + } +- *ppath = path; + return 0; + } + diff --git a/queue-6.1/ext4-use-handle-to-mark-fc-as-ineligible-in-__track_dentry_update.patch b/queue-6.1/ext4-use-handle-to-mark-fc-as-ineligible-in-__track_dentry_update.patch new file mode 100644 index 00000000000..e9258c2f958 --- /dev/null +++ b/queue-6.1/ext4-use-handle-to-mark-fc-as-ineligible-in-__track_dentry_update.patch @@ -0,0 +1,102 @@ +From faab35a0370fd6e0821c7a8dd213492946fc776f Mon Sep 17 00:00:00 2001 +From: "Luis Henriques (SUSE)" +Date: Mon, 23 Sep 2024 11:49:08 +0100 +Subject: ext4: use handle to mark fc as ineligible in __track_dentry_update() + +From: Luis Henriques (SUSE) + +commit faab35a0370fd6e0821c7a8dd213492946fc776f upstream. + +Calling ext4_fc_mark_ineligible() with a NULL handle is racy and may result +in a fast-commit being done before the filesystem is effectively marked as +ineligible. This patch fixes the calls to this function in +__track_dentry_update() by adding an extra parameter to the callback used in +ext4_fc_track_template(). + +Suggested-by: Jan Kara +Signed-off-by: Luis Henriques (SUSE) +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20240923104909.18342-2-luis.henriques@linux.dev +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/fast_commit.c | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +--- a/fs/ext4/fast_commit.c ++++ b/fs/ext4/fast_commit.c +@@ -379,7 +379,7 @@ void ext4_fc_mark_ineligible(struct supe + */ + static int ext4_fc_track_template( + handle_t *handle, struct inode *inode, +- int (*__fc_track_fn)(struct inode *, void *, bool), ++ int (*__fc_track_fn)(handle_t *handle, struct inode *, void *, bool), + void *args, int enqueue) + { + bool update = false; +@@ -396,7 +396,7 @@ static int ext4_fc_track_template( + ext4_fc_reset_inode(inode); + ei->i_sync_tid = tid; + } +- ret = __fc_track_fn(inode, args, update); ++ ret = __fc_track_fn(handle, inode, args, update); + mutex_unlock(&ei->i_fc_lock); + + if (!enqueue) +@@ -420,7 +420,8 @@ struct __track_dentry_update_args { + }; + + /* __track_fn for directory entry updates. Called with ei->i_fc_lock. */ +-static int __track_dentry_update(struct inode *inode, void *arg, bool update) ++static int __track_dentry_update(handle_t *handle, struct inode *inode, ++ void *arg, bool update) + { + struct ext4_fc_dentry_update *node; + struct ext4_inode_info *ei = EXT4_I(inode); +@@ -435,14 +436,14 @@ static int __track_dentry_update(struct + + if (IS_ENCRYPTED(dir)) { + ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_ENCRYPTED_FILENAME, +- NULL); ++ handle); + mutex_lock(&ei->i_fc_lock); + return -EOPNOTSUPP; + } + + node = kmem_cache_alloc(ext4_fc_dentry_cachep, GFP_NOFS); + if (!node) { +- ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_NOMEM, NULL); ++ ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_NOMEM, handle); + mutex_lock(&ei->i_fc_lock); + return -ENOMEM; + } +@@ -454,7 +455,7 @@ static int __track_dentry_update(struct + node->fcd_name.name = kmalloc(dentry->d_name.len, GFP_NOFS); + if (!node->fcd_name.name) { + kmem_cache_free(ext4_fc_dentry_cachep, node); +- ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_NOMEM, NULL); ++ ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_NOMEM, handle); + mutex_lock(&ei->i_fc_lock); + return -ENOMEM; + } +@@ -576,7 +577,8 @@ void ext4_fc_track_create(handle_t *hand + } + + /* __track_fn for inode tracking */ +-static int __track_inode(struct inode *inode, void *arg, bool update) ++static int __track_inode(handle_t *handle, struct inode *inode, void *arg, ++ bool update) + { + if (update) + return -EEXIST; +@@ -614,7 +616,8 @@ struct __track_range_args { + }; + + /* __track_fn for tracking data updates */ +-static int __track_range(struct inode *inode, void *arg, bool update) ++static int __track_range(handle_t *handle, struct inode *inode, void *arg, ++ bool update) + { + struct ext4_inode_info *ei = EXT4_I(inode); + ext4_lblk_t oldstart; diff --git a/queue-6.1/series b/queue-6.1/series index 5d59a470fa2..28015bf618a 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -541,3 +541,19 @@ alsa-usb-audio-add-native-dsd-support-for-luxman-d-08u.patch alsa-line6-add-hw-monitor-volume-control-to-pod-hd500x.patch alsa-hda-realtek-add-quirk-for-huawei-matebook-13-klv-wx9.patch alsa-hda-realtek-add-a-quirk-for-hp-pavilion-15z-ec200.patch +ext4-no-need-to-continue-when-the-number-of-entries-is-1.patch +ext4-correct-encrypted-dentry-name-hash-when-not-casefolded.patch +ext4-fix-slab-use-after-free-in-ext4_split_extent_at.patch +ext4-propagate-errors-from-ext4_find_extent-in-ext4_insert_range.patch +ext4-fix-incorrect-tid-assumption-in-ext4_fc_mark_ineligible.patch +ext4-dax-fix-overflowing-extents-beyond-inode-size-when-partially-writing.patch +ext4-fix-incorrect-tid-assumption-in-__jbd2_log_wait_for_space.patch +ext4-drop-ppath-from-ext4_ext_replay_update_ex-to-avoid-double-free.patch +ext4-aovid-use-after-free-in-ext4_ext_insert_extent.patch +ext4-fix-double-brelse-the-buffer-of-the-extents-path.patch +ext4-update-orig_path-in-ext4_find_extent.patch +ext4-fix-incorrect-tid-assumption-in-ext4_wait_for_tail_page_commit.patch +ext4-fix-incorrect-tid-assumption-in-jbd2_journal_shrink_checkpoint_list.patch +ext4-fix-fast-commit-inode-enqueueing-during-a-full-journal-commit.patch +ext4-use-handle-to-mark-fc-as-ineligible-in-__track_dentry_update.patch +ext4-mark-fc-as-ineligible-using-an-handle-in-ext4_xattr_set.patch