From: Greg Kroah-Hartman Date: Thu, 16 Oct 2025 14:18:59 +0000 (+0200) Subject: 6.17-stable patches X-Git-Tag: v5.15.195~58 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bdebad2c1ec2994c8bd1cfa932ddc26cb5a61a1c;p=thirdparty%2Fkernel%2Fstable-queue.git 6.17-stable patches added patches: ext4-add-ext4_sb_bread_nofail-helper-function-for-ext4_free_branches.patch ext4-avoid-potential-buffer-over-read-in-parse_apply_sb_mount_options.patch ext4-correctly-handle-queries-for-metadata-mappings.patch ext4-fail-unaligned-direct-io-write-with-einval.patch ext4-fix-an-off-by-one-issue-during-moving-extents.patch ext4-guard-against-ea-inode-refcount-underflow-in-xattr-update.patch ext4-increase-i_disksize-to-offset-len-in-ext4_update_disksize_before_punch.patch ext4-validate-ea_ino-and-size-in-check_xattrs.patch ext4-verify-orphan-file-size-is-not-too-big.patch --- diff --git a/queue-6.17/ext4-add-ext4_sb_bread_nofail-helper-function-for-ext4_free_branches.patch b/queue-6.17/ext4-add-ext4_sb_bread_nofail-helper-function-for-ext4_free_branches.patch new file mode 100644 index 0000000000..3438c132d7 --- /dev/null +++ b/queue-6.17/ext4-add-ext4_sb_bread_nofail-helper-function-for-ext4_free_branches.patch @@ -0,0 +1,76 @@ +From d8b90e6387a74bcb1714c8d1e6a782ff709de9a9 Mon Sep 17 00:00:00 2001 +From: Baokun Li +Date: Thu, 21 Aug 2025 21:38:57 +0800 +Subject: ext4: add ext4_sb_bread_nofail() helper function for ext4_free_branches() + +From: Baokun Li + +commit d8b90e6387a74bcb1714c8d1e6a782ff709de9a9 upstream. + +The implicit __GFP_NOFAIL flag in ext4_sb_bread() was removed in commit +8a83ac54940d ("ext4: call bdev_getblk() from sb_getblk_gfp()"), meaning +the function can now fail under memory pressure. + +Most callers of ext4_sb_bread() propagate the error to userspace and do not +remount the filesystem read-only. However, ext4_free_branches() handles +ext4_sb_bread() failure by remounting the filesystem read-only. + +This implies that an ext3 filesystem (mounted via the ext4 driver) could be +forcibly remounted read-only due to a transient page allocation failure, +which is unacceptable. + +To mitigate this, introduce a new helper function, ext4_sb_bread_nofail(), +which explicitly uses __GFP_NOFAIL, and use it in ext4_free_branches(). + +Fixes: 8a83ac54940d ("ext4: call bdev_getblk() from sb_getblk_gfp()") +Cc: stable@kernel.org +Signed-off-by: Baokun Li +Reviewed-by: Jan Kara +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/ext4.h | 2 ++ + fs/ext4/indirect.c | 2 +- + fs/ext4/super.c | 9 +++++++++ + 3 files changed, 12 insertions(+), 1 deletion(-) + +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -3144,6 +3144,8 @@ extern struct buffer_head *ext4_sb_bread + sector_t block, blk_opf_t op_flags); + extern struct buffer_head *ext4_sb_bread_unmovable(struct super_block *sb, + sector_t block); ++extern struct buffer_head *ext4_sb_bread_nofail(struct super_block *sb, ++ sector_t block); + extern void ext4_read_bh_nowait(struct buffer_head *bh, blk_opf_t op_flags, + bh_end_io_t *end_io, bool simu_fail); + extern int ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags, +--- a/fs/ext4/indirect.c ++++ b/fs/ext4/indirect.c +@@ -1025,7 +1025,7 @@ static void ext4_free_branches(handle_t + } + + /* Go read the buffer for the next level down */ +- bh = ext4_sb_bread(inode->i_sb, nr, 0); ++ bh = ext4_sb_bread_nofail(inode->i_sb, nr); + + /* + * A read failure? Report error and clear slot +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -265,6 +265,15 @@ struct buffer_head *ext4_sb_bread_unmova + return __ext4_sb_bread_gfp(sb, block, 0, gfp); + } + ++struct buffer_head *ext4_sb_bread_nofail(struct super_block *sb, ++ sector_t block) ++{ ++ gfp_t gfp = mapping_gfp_constraint(sb->s_bdev->bd_mapping, ++ ~__GFP_FS) | __GFP_MOVABLE | __GFP_NOFAIL; ++ ++ return __ext4_sb_bread_gfp(sb, block, 0, gfp); ++} ++ + void ext4_sb_breadahead_unmovable(struct super_block *sb, sector_t block) + { + struct buffer_head *bh = bdev_getblk(sb->s_bdev, block, diff --git a/queue-6.17/ext4-avoid-potential-buffer-over-read-in-parse_apply_sb_mount_options.patch b/queue-6.17/ext4-avoid-potential-buffer-over-read-in-parse_apply_sb_mount_options.patch new file mode 100644 index 0000000000..5dd63c476b --- /dev/null +++ b/queue-6.17/ext4-avoid-potential-buffer-over-read-in-parse_apply_sb_mount_options.patch @@ -0,0 +1,69 @@ +From 8ecb790ea8c3fc69e77bace57f14cf0d7c177bd8 Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Tue, 16 Sep 2025 23:22:47 -0400 +Subject: ext4: avoid potential buffer over-read in parse_apply_sb_mount_options() + +From: Theodore Ts'o + +commit 8ecb790ea8c3fc69e77bace57f14cf0d7c177bd8 upstream. + +Unlike other strings in the ext4 superblock, we rely on tune2fs to +make sure s_mount_opts is NUL terminated. Harden +parse_apply_sb_mount_options() by treating s_mount_opts as a potential +__nonstring. + +Cc: stable@vger.kernel.org +Fixes: 8b67f04ab9de ("ext4: Add mount options in superblock") +Reviewed-by: Jan Kara +Reviewed-by: Darrick J. Wong +Signed-off-by: Theodore Ts'o +Message-ID: <20250916-tune2fs-v2-1-d594dc7486f0@mit.edu> +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/super.c | 17 +++++------------ + 1 file changed, 5 insertions(+), 12 deletions(-) + +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -2469,7 +2469,7 @@ static int parse_apply_sb_mount_options( + struct ext4_fs_context *m_ctx) + { + struct ext4_sb_info *sbi = EXT4_SB(sb); +- char *s_mount_opts = NULL; ++ char s_mount_opts[65]; + struct ext4_fs_context *s_ctx = NULL; + struct fs_context *fc = NULL; + int ret = -ENOMEM; +@@ -2477,15 +2477,11 @@ static int parse_apply_sb_mount_options( + if (!sbi->s_es->s_mount_opts[0]) + return 0; + +- s_mount_opts = kstrndup(sbi->s_es->s_mount_opts, +- sizeof(sbi->s_es->s_mount_opts), +- GFP_KERNEL); +- if (!s_mount_opts) +- return ret; ++ strscpy_pad(s_mount_opts, sbi->s_es->s_mount_opts); + + fc = kzalloc(sizeof(struct fs_context), GFP_KERNEL); + if (!fc) +- goto out_free; ++ return -ENOMEM; + + s_ctx = kzalloc(sizeof(struct ext4_fs_context), GFP_KERNEL); + if (!s_ctx) +@@ -2517,11 +2513,8 @@ parse_failed: + ret = 0; + + out_free: +- if (fc) { +- ext4_fc_free(fc); +- kfree(fc); +- } +- kfree(s_mount_opts); ++ ext4_fc_free(fc); ++ kfree(fc); + return ret; + } + diff --git a/queue-6.17/ext4-correctly-handle-queries-for-metadata-mappings.patch b/queue-6.17/ext4-correctly-handle-queries-for-metadata-mappings.patch new file mode 100644 index 0000000000..8279eeba2e --- /dev/null +++ b/queue-6.17/ext4-correctly-handle-queries-for-metadata-mappings.patch @@ -0,0 +1,98 @@ +From 46c22a8bb4cb03211da1100d7ee4a2005bf77c70 Mon Sep 17 00:00:00 2001 +From: Ojaswin Mujoo +Date: Fri, 5 Sep 2025 13:44:46 +0530 +Subject: ext4: correctly handle queries for metadata mappings + +From: Ojaswin Mujoo + +commit 46c22a8bb4cb03211da1100d7ee4a2005bf77c70 upstream. + +Currently, our handling of metadata is _ambiguous_ in some scenarios, +that is, we end up returning unknown if the range only covers the +mapping partially. + +For example, in the following case: + +$ xfs_io -c fsmap -d + + 0: 254:16 [0..7]: static fs metadata 8 + 1: 254:16 [8..15]: special 102:1 8 + 2: 254:16 [16..5127]: special 102:2 5112 + 3: 254:16 [5128..5255]: special 102:3 128 + 4: 254:16 [5256..5383]: special 102:4 128 + 5: 254:16 [5384..70919]: inodes 65536 + 6: 254:16 [70920..70967]: unknown 48 + ... + +$ xfs_io -c fsmap -d 24 33 + + 0: 254:16 [24..39]: unknown 16 <--- incomplete reporting + +$ xfs_io -c fsmap -d 24 33 (With patch) + + 0: 254:16 [16..5127]: special 102:2 5112 + +This is because earlier in ext4_getfsmap_meta_helper, we end up ignoring +any extent that starts before our queried range, but overlaps it. While +the man page [1] is a bit ambiguous on this, this fix makes the output +make more sense since we are anyways returning an "unknown" extent. This +is also consistent to how XFS does it: + +$ xfs_io -c fsmap -d + + ... + 6: 254:16 [104..127]: free space 24 + 7: 254:16 [128..191]: inodes 64 + ... + +$ xfs_io -c fsmap -d 137 150 + + 0: 254:16 [128..191]: inodes 64 <-- full extent returned + + [1] https://man7.org/linux/man-pages/man2/ioctl_getfsmap.2.html + +Reported-by: Ritesh Harjani (IBM) +Cc: stable@kernel.org +Signed-off-by: Ojaswin Mujoo +Message-ID: <023f37e35ee280cd9baac0296cbadcbe10995cab.1757058211.git.ojaswin@linux.ibm.com> +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/fsmap.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +--- a/fs/ext4/fsmap.c ++++ b/fs/ext4/fsmap.c +@@ -74,7 +74,8 @@ static int ext4_getfsmap_dev_compare(con + static bool ext4_getfsmap_rec_before_low_key(struct ext4_getfsmap_info *info, + struct ext4_fsmap *rec) + { +- return rec->fmr_physical < info->gfi_low.fmr_physical; ++ return rec->fmr_physical + rec->fmr_length <= ++ info->gfi_low.fmr_physical; + } + + /* +@@ -200,15 +201,18 @@ static int ext4_getfsmap_meta_helper(str + ext4_group_first_block_no(sb, agno)); + fs_end = fs_start + EXT4_C2B(sbi, len); + +- /* Return relevant extents from the meta_list */ ++ /* ++ * Return relevant extents from the meta_list. We emit all extents that ++ * partially/fully overlap with the query range ++ */ + list_for_each_entry_safe(p, tmp, &info->gfi_meta_list, fmr_list) { +- if (p->fmr_physical < info->gfi_next_fsblk) { ++ if (p->fmr_physical + p->fmr_length <= info->gfi_next_fsblk) { + list_del(&p->fmr_list); + kfree(p); + continue; + } +- if (p->fmr_physical <= fs_start || +- p->fmr_physical + p->fmr_length <= fs_end) { ++ if (p->fmr_physical <= fs_end && ++ p->fmr_physical + p->fmr_length > fs_start) { + /* Emit the retained free extent record if present */ + if (info->gfi_lastfree.fmr_owner) { + error = ext4_getfsmap_helper(sb, info, diff --git a/queue-6.17/ext4-fail-unaligned-direct-io-write-with-einval.patch b/queue-6.17/ext4-fail-unaligned-direct-io-write-with-einval.patch new file mode 100644 index 0000000000..64f894f4db --- /dev/null +++ b/queue-6.17/ext4-fail-unaligned-direct-io-write-with-einval.patch @@ -0,0 +1,87 @@ +From 963845748fe67125006859229487b45485564db7 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Mon, 1 Sep 2025 13:27:40 +0200 +Subject: ext4: fail unaligned direct IO write with EINVAL + +From: Jan Kara + +commit 963845748fe67125006859229487b45485564db7 upstream. + +Commit bc264fea0f6f ("iomap: support incremental iomap_iter advances") +changed the error handling logic in iomap_iter(). Previously any error +from iomap_dio_bio_iter() got propagated to userspace, after this commit +if ->iomap_end returns error, it gets propagated to userspace instead of +an error from iomap_dio_bio_iter(). This results in unaligned writes to +ext4 to silently fallback to buffered IO instead of erroring out. + +Now returning ENOTBLK for DIO writes from ext4_iomap_end() seems +unnecessary these days. It is enough to return ENOTBLK from +ext4_iomap_begin() when we don't support DIO write for that particular +file offset (due to hole). + +Fixes: bc264fea0f6f ("iomap: support incremental iomap_iter advances") +Cc: stable@kernel.org +Signed-off-by: Jan Kara +Reviewed-by: Ritesh Harjani (IBM) +Message-ID: <20250901112739.32484-2-jack@suse.cz> +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/inode.c | 35 ----------------------------------- + 1 file changed, 35 deletions(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 5b7a15db4953..c3b23c90fd11 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -3872,47 +3872,12 @@ static int ext4_iomap_overwrite_begin(struct inode *inode, loff_t offset, + return ret; + } + +-static inline bool ext4_want_directio_fallback(unsigned flags, ssize_t written) +-{ +- /* must be a directio to fall back to buffered */ +- if ((flags & (IOMAP_WRITE | IOMAP_DIRECT)) != +- (IOMAP_WRITE | IOMAP_DIRECT)) +- return false; +- +- /* atomic writes are all-or-nothing */ +- if (flags & IOMAP_ATOMIC) +- return false; +- +- /* can only try again if we wrote nothing */ +- return written == 0; +-} +- +-static int ext4_iomap_end(struct inode *inode, loff_t offset, loff_t length, +- ssize_t written, unsigned flags, struct iomap *iomap) +-{ +- /* +- * Check to see whether an error occurred while writing out the data to +- * the allocated blocks. If so, return the magic error code for +- * non-atomic write so that we fallback to buffered I/O and attempt to +- * complete the remainder of the I/O. +- * For non-atomic writes, any blocks that may have been +- * allocated in preparation for the direct I/O will be reused during +- * buffered I/O. For atomic write, we never fallback to buffered-io. +- */ +- if (ext4_want_directio_fallback(flags, written)) +- return -ENOTBLK; +- +- return 0; +-} +- + const struct iomap_ops ext4_iomap_ops = { + .iomap_begin = ext4_iomap_begin, +- .iomap_end = ext4_iomap_end, + }; + + const struct iomap_ops ext4_iomap_overwrite_ops = { + .iomap_begin = ext4_iomap_overwrite_begin, +- .iomap_end = ext4_iomap_end, + }; + + static int ext4_iomap_begin_report(struct inode *inode, loff_t offset, +-- +2.51.0 + diff --git a/queue-6.17/ext4-fix-an-off-by-one-issue-during-moving-extents.patch b/queue-6.17/ext4-fix-an-off-by-one-issue-during-moving-extents.patch new file mode 100644 index 0000000000..181fb24ad3 --- /dev/null +++ b/queue-6.17/ext4-fix-an-off-by-one-issue-during-moving-extents.patch @@ -0,0 +1,47 @@ +From 12e803c8827d049ae8f2c743ef66ab87ae898375 Mon Sep 17 00:00:00 2001 +From: Zhang Yi +Date: Fri, 12 Sep 2025 18:58:41 +0800 +Subject: ext4: fix an off-by-one issue during moving extents + +From: Zhang Yi + +commit 12e803c8827d049ae8f2c743ef66ab87ae898375 upstream. + +During the movement of a written extent, mext_page_mkuptodate() is +called to read data in the range [from, to) into the page cache and to +update the corresponding buffers. Therefore, we should not wait on any +buffer whose start offset is >= 'to'. Otherwise, it will return -EIO and +fail the extents movement. + + $ for i in `seq 3 -1 0`; \ + do xfs_io -fs -c "pwrite -b 1024 $((i * 1024)) 1024" /mnt/foo; \ + done + $ umount /mnt && mount /dev/pmem1s /mnt # drop cache + $ e4defrag /mnt/foo + e4defrag 1.47.0 (5-Feb-2023) + ext4 defragmentation for /mnt/foo + [1/1]/mnt/foo: 0% [ NG ] + Success: [0/1] + +Cc: stable@kernel.org +Fixes: a40759fb16ae ("ext4: remove array of buffer_heads from mext_page_mkuptodate()") +Signed-off-by: Zhang Yi +Reviewed-by: Jan Kara +Message-ID: <20250912105841.1886799-1-yi.zhang@huaweicloud.com> +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/move_extent.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ext4/move_extent.c ++++ b/fs/ext4/move_extent.c +@@ -225,7 +225,7 @@ static int mext_page_mkuptodate(struct f + do { + if (bh_offset(bh) + blocksize <= from) + continue; +- if (bh_offset(bh) > to) ++ if (bh_offset(bh) >= to) + break; + wait_on_buffer(bh); + if (buffer_uptodate(bh)) diff --git a/queue-6.17/ext4-guard-against-ea-inode-refcount-underflow-in-xattr-update.patch b/queue-6.17/ext4-guard-against-ea-inode-refcount-underflow-in-xattr-update.patch new file mode 100644 index 0000000000..a46fb254ba --- /dev/null +++ b/queue-6.17/ext4-guard-against-ea-inode-refcount-underflow-in-xattr-update.patch @@ -0,0 +1,80 @@ +From 57295e835408d8d425bef58da5253465db3d6888 Mon Sep 17 00:00:00 2001 +From: Ahmet Eray Karadag +Date: Sat, 20 Sep 2025 05:13:43 +0300 +Subject: ext4: guard against EA inode refcount underflow in xattr update + +From: Ahmet Eray Karadag + +commit 57295e835408d8d425bef58da5253465db3d6888 upstream. + +syzkaller found a path where ext4_xattr_inode_update_ref() reads an EA +inode refcount that is already <= 0 and then applies ref_change (often +-1). That lets the refcount underflow and we proceed with a bogus value, +triggering errors like: + + EXT4-fs error: EA inode ref underflow: ref_count=-1 ref_change=-1 + EXT4-fs warning: ea_inode dec ref err=-117 + +Make the invariant explicit: if the current refcount is non-positive, +treat this as on-disk corruption, emit ext4_error_inode(), and fail the +operation with -EFSCORRUPTED instead of updating the refcount. Delete the +WARN_ONCE() as negative refcounts are now impossible; keep error reporting +in ext4_error_inode(). + +This prevents the underflow and the follow-on orphan/cleanup churn. + +Reported-by: syzbot+0be4f339a8218d2a5bb1@syzkaller.appspotmail.com +Fixes: https://syzbot.org/bug?extid=0be4f339a8218d2a5bb1 +Cc: stable@kernel.org +Co-developed-by: Albin Babu Varghese +Signed-off-by: Albin Babu Varghese +Signed-off-by: Ahmet Eray Karadag +Message-ID: <20250920021342.45575-1-eraykrdg1@gmail.com> +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/xattr.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -1019,7 +1019,7 @@ static int ext4_xattr_inode_update_ref(h + int ref_change) + { + struct ext4_iloc iloc; +- s64 ref_count; ++ u64 ref_count; + int ret; + + inode_lock_nested(ea_inode, I_MUTEX_XATTR); +@@ -1029,13 +1029,17 @@ static int ext4_xattr_inode_update_ref(h + goto out; + + ref_count = ext4_xattr_inode_get_ref(ea_inode); ++ if ((ref_count == 0 && ref_change < 0) || (ref_count == U64_MAX && ref_change > 0)) { ++ ext4_error_inode(ea_inode, __func__, __LINE__, 0, ++ "EA inode %lu ref wraparound: ref_count=%lld ref_change=%d", ++ ea_inode->i_ino, ref_count, ref_change); ++ ret = -EFSCORRUPTED; ++ goto out; ++ } + ref_count += ref_change; + ext4_xattr_inode_set_ref(ea_inode, ref_count); + + if (ref_change > 0) { +- WARN_ONCE(ref_count <= 0, "EA inode %lu ref_count=%lld", +- ea_inode->i_ino, ref_count); +- + if (ref_count == 1) { + WARN_ONCE(ea_inode->i_nlink, "EA inode %lu i_nlink=%u", + ea_inode->i_ino, ea_inode->i_nlink); +@@ -1044,9 +1048,6 @@ static int ext4_xattr_inode_update_ref(h + ext4_orphan_del(handle, ea_inode); + } + } else { +- WARN_ONCE(ref_count < 0, "EA inode %lu ref_count=%lld", +- ea_inode->i_ino, ref_count); +- + if (ref_count == 0) { + WARN_ONCE(ea_inode->i_nlink != 1, + "EA inode %lu i_nlink=%u", diff --git a/queue-6.17/ext4-increase-i_disksize-to-offset-len-in-ext4_update_disksize_before_punch.patch b/queue-6.17/ext4-increase-i_disksize-to-offset-len-in-ext4_update_disksize_before_punch.patch new file mode 100644 index 0000000000..b73e5a7604 --- /dev/null +++ b/queue-6.17/ext4-increase-i_disksize-to-offset-len-in-ext4_update_disksize_before_punch.patch @@ -0,0 +1,91 @@ +From 9d80eaa1a1d37539224982b76c9ceeee736510b9 Mon Sep 17 00:00:00 2001 +From: Yongjian Sun +Date: Thu, 11 Sep 2025 21:30:24 +0800 +Subject: ext4: increase i_disksize to offset + len in ext4_update_disksize_before_punch() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yongjian Sun + +commit 9d80eaa1a1d37539224982b76c9ceeee736510b9 upstream. + +After running a stress test combined with fault injection, +we performed fsck -a followed by fsck -fn on the filesystem +image. During the second pass, fsck -fn reported: + +Inode 131512, end of extent exceeds allowed value + (logical block 405, physical block 1180540, len 2) + +This inode was not in the orphan list. Analysis revealed the +following call chain that leads to the inconsistency: + + ext4_da_write_end() + //does not update i_disksize + ext4_punch_hole() + //truncate folio, keep size +ext4_page_mkwrite() + ext4_block_page_mkwrite() + ext4_block_write_begin() + ext4_get_block() + //insert written extent without update i_disksize +journal commit +echo 1 > /sys/block/xxx/device/delete + +da-write path updates i_size but does not update i_disksize. Then +ext4_punch_hole truncates the da-folio yet still leaves i_disksize +unchanged(in the ext4_update_disksize_before_punch function, the +condition offset + len < size is met). Then ext4_page_mkwrite sees +ext4_nonda_switch return 1 and takes the nodioread_nolock path, the +folio about to be written has just been punched out, and it’s offset +sits beyond the current i_disksize. This may result in a written +extent being inserted, but again does not update i_disksize. If the +journal gets committed and then the block device is yanked, we might +run into this. It should be noted that replacing ext4_punch_hole with +ext4_zero_range in the call sequence may also trigger this issue, as +neither will update i_disksize under these circumstances. + +To fix this, we can modify ext4_update_disksize_before_punch to +increase i_disksize to min(i_size, offset + len) when both i_size and +(offset + len) are greater than i_disksize. + +Cc: stable@kernel.org +Signed-off-by: Yongjian Sun +Reviewed-by: Zhang Yi +Reviewed-by: Jan Kara +Reviewed-by: Baokun Li +Message-ID: <20250911133024.1841027-1-sunyongjian@huaweicloud.com> +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/inode.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -4252,7 +4252,11 @@ int ext4_can_truncate(struct inode *inod + * We have to make sure i_disksize gets properly updated before we truncate + * page cache due to hole punching or zero range. Otherwise i_disksize update + * can get lost as it may have been postponed to submission of writeback but +- * that will never happen after we truncate page cache. ++ * that will never happen if we remove the folio containing i_size from the ++ * page cache. Also if we punch hole within i_size but above i_disksize, ++ * following ext4_page_mkwrite() may mistakenly allocate written blocks over ++ * the hole and thus introduce allocated blocks beyond i_disksize which is ++ * not allowed (e2fsck would complain in case of crash). + */ + int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset, + loff_t len) +@@ -4263,9 +4267,11 @@ int ext4_update_disksize_before_punch(st + loff_t size = i_size_read(inode); + + WARN_ON(!inode_is_locked(inode)); +- if (offset > size || offset + len < size) ++ if (offset > size) + return 0; + ++ if (offset + len < size) ++ size = offset + len; + if (EXT4_I(inode)->i_disksize >= size) + return 0; + diff --git a/queue-6.17/ext4-validate-ea_ino-and-size-in-check_xattrs.patch b/queue-6.17/ext4-validate-ea_ino-and-size-in-check_xattrs.patch new file mode 100644 index 0000000000..e3249cea6a --- /dev/null +++ b/queue-6.17/ext4-validate-ea_ino-and-size-in-check_xattrs.patch @@ -0,0 +1,44 @@ +From 44d2a72f4d64655f906ba47a5e108733f59e6f28 Mon Sep 17 00:00:00 2001 +From: Deepanshu Kartikey +Date: Tue, 23 Sep 2025 19:02:45 +0530 +Subject: ext4: validate ea_ino and size in check_xattrs + +From: Deepanshu Kartikey + +commit 44d2a72f4d64655f906ba47a5e108733f59e6f28 upstream. + +During xattr block validation, check_xattrs() processes xattr entries +without validating that entries claiming to use EA inodes have non-zero +sizes. Corrupted filesystems may contain xattr entries where e_value_size +is zero but e_value_inum is non-zero, indicating invalid xattr data. + +Add validation in check_xattrs() to detect this corruption pattern early +and return -EFSCORRUPTED, preventing invalid xattr entries from causing +issues throughout the ext4 codebase. + +Cc: stable@kernel.org +Suggested-by: Theodore Ts'o +Reported-by: syzbot+4c9d23743a2409b80293@syzkaller.appspotmail.com +Link: https://syzkaller.appspot.com/bug?extid=4c9d23743a2409b80293 +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Theodore Ts'o +Message-ID: <20250923133245.1091761-1-kartikey406@gmail.com> +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/xattr.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -251,6 +251,10 @@ check_xattrs(struct inode *inode, struct + err_str = "invalid ea_ino"; + goto errout; + } ++ if (ea_ino && !size) { ++ err_str = "invalid size in ea xattr"; ++ goto errout; ++ } + if (size > EXT4_XATTR_SIZE_MAX) { + err_str = "e_value size too large"; + goto errout; diff --git a/queue-6.17/ext4-verify-orphan-file-size-is-not-too-big.patch b/queue-6.17/ext4-verify-orphan-file-size-is-not-too-big.patch new file mode 100644 index 0000000000..41ad548a70 --- /dev/null +++ b/queue-6.17/ext4-verify-orphan-file-size-is-not-too-big.patch @@ -0,0 +1,51 @@ +From 0a6ce20c156442a4ce2a404747bb0fb05d54eeb3 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Tue, 9 Sep 2025 13:22:07 +0200 +Subject: ext4: verify orphan file size is not too big + +From: Jan Kara + +commit 0a6ce20c156442a4ce2a404747bb0fb05d54eeb3 upstream. + +In principle orphan file can be arbitrarily large. However orphan replay +needs to traverse it all and we also pin all its buffers in memory. Thus +filesystems with absurdly large orphan files can lead to big amounts of +memory consumed. Limit orphan file size to a sane value and also use +kvmalloc() for allocating array of block descriptor structures to avoid +large order allocations for sane but large orphan files. + +Reported-by: syzbot+0b92850d68d9b12934f5@syzkaller.appspotmail.com +Fixes: 02f310fcf47f ("ext4: Speedup ext4 orphan inode handling") +Cc: stable@kernel.org +Signed-off-by: Jan Kara +Message-ID: <20250909112206.10459-2-jack@suse.cz> +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/orphan.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +--- a/fs/ext4/orphan.c ++++ b/fs/ext4/orphan.c +@@ -583,9 +583,20 @@ int ext4_init_orphan_info(struct super_b + ext4_msg(sb, KERN_ERR, "get orphan inode failed"); + return PTR_ERR(inode); + } ++ /* ++ * This is just an artificial limit to prevent corrupted fs from ++ * consuming absurd amounts of memory when pinning blocks of orphan ++ * file in memory. ++ */ ++ if (inode->i_size > 8 << 20) { ++ ext4_msg(sb, KERN_ERR, "orphan file too big: %llu", ++ (unsigned long long)inode->i_size); ++ ret = -EFSCORRUPTED; ++ goto out_put; ++ } + oi->of_blocks = inode->i_size >> sb->s_blocksize_bits; + oi->of_csum_seed = EXT4_I(inode)->i_csum_seed; +- oi->of_binfo = kmalloc_array(oi->of_blocks, ++ oi->of_binfo = kvmalloc_array(oi->of_blocks, + sizeof(struct ext4_orphan_block), + GFP_KERNEL); + if (!oi->of_binfo) { diff --git a/queue-6.17/series b/queue-6.17/series index 9bd0610dd6..039a0f0146 100644 --- a/queue-6.17/series +++ b/queue-6.17/series @@ -335,3 +335,12 @@ media-iris-send-dummy-buffer-address-for-all-codecs-during-drain.patch media-iris-fix-missing-last-flag-handling-during-drain.patch media-iris-fix-format-check-for-capture-plane-in-try_fmt.patch media-iris-allow-stop-on-firmware-only-if-start-was-issued.patch +ext4-add-ext4_sb_bread_nofail-helper-function-for-ext4_free_branches.patch +ext4-fail-unaligned-direct-io-write-with-einval.patch +ext4-verify-orphan-file-size-is-not-too-big.patch +ext4-increase-i_disksize-to-offset-len-in-ext4_update_disksize_before_punch.patch +ext4-correctly-handle-queries-for-metadata-mappings.patch +ext4-avoid-potential-buffer-over-read-in-parse_apply_sb_mount_options.patch +ext4-fix-an-off-by-one-issue-during-moving-extents.patch +ext4-guard-against-ea-inode-refcount-underflow-in-xattr-update.patch +ext4-validate-ea_ino-and-size-in-check_xattrs.patch