Linux EXT4 FS development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Yichong Chen" <chenyichong@uniontech.com>
Cc: tytso@mit.edu, linux-ext4@vger.kernel.org
Subject: Re: [PATCH v2] ext4: fix the logical block counter overflow in indirect migration
Date: Mon, 14 Sep 2026 08:41:11 +0000	[thread overview]
Message-ID: <20260914084112.4F0831F000FF@smtp.kernel.org> (raw)
In-Reply-To: <20260914082516.3442815-1-chenyichong@uniontech.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

Pre-existing issues:
- [Critical] Missing bounds check on extent length during contiguous block aggregation leads to extent corruption and silent data loss.
- [Critical] Erroneous freeing of active extent metadata blocks if `free_ind_block()` fails after the inode data is permanently swapped.
- [High] `ext4_ext_migrate()` silently overwrites error codes, including the newly added `-EOPNOTSUPP`, falsely reporting success to userspace.
--

commit 551790cf82563190f29580d447430a3723ff4943
Author: Yichong Chen <chenyichong@uniontech.com>
Subject: ext4: fix the logical block counter overflow in indirect migration

This commit prevents a logical block counter overflow in the ext4 indirect
migration path by keeping the counter in 64-bit and refusing migration if a
block reaches EXT_MAX_BLOCKS.

> diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
> index c5e3fc998211a..f492935d5e3de 100644
> --- a/fs/ext4/migrate.c
> +++ b/fs/ext4/migrate.c

[ ... ]

> @@ -66,6 +66,10 @@ static int update_extent_range(handle_t *handle, struct inode *inode,
>  			       ext4_fsblk_t pblock, struct migrate_struct *lb)
>  {
>  	int retval;
> +
> +	if (lb->curr_block >= EXT_MAX_BLOCKS)
> +		return -EOPNOTSUPP;
> +
>  	/*
>  	 * See if we can add on to the existing range (if it exists)
>  	 */
>  	if (lb->first_pblock &&
>  		(lb->last_pblock+1 == pblock) &&
>  		(lb->last_block+1 == lb->curr_block)) {
>  		lb->last_pblock = pblock;
>  		lb->last_block = lb->curr_block;
>  		lb->curr_block++;
>  		return 0;
>  	}

[Severity: Critical]
This is a pre-existing issue, but it appears this contiguous block check
blindly accumulates blocks without verifying that the maximum extent length
(EXT_INIT_MAX_LEN) is respected.

If a file has more than 32768 physically contiguous blocks, the resulting
length is later cast to 16 bits in finish_range():

	newext.ee_len   = cpu_to_le16(lb->last_block - lb->first_block + 1);

Could a length greater than 32768 set the 0x8000 (UNWRITTEN) bit or overflow
entirely, causing valid data to read as zeroes and corrupting the file?


[Severity: High]
This isn't a bug introduced by this patch, but the error handling in
ext4_ext_migrate() seems to unconditionally overwrite error codes like the
newly added -EOPNOTSUPP.

Looking at the error path in ext4_ext_migrate():

err_out:
	if (retval)
		/*
		 * Failure case delete the extent information with the
		 * tmp_inode
		 */
		free_ext_block(handle, tmp_inode);
	else {
		retval = ext4_ext_swap_inode_data(handle, inode, tmp_inode);
		if (retval)
			/*
			 * if we fail to swap inode data free the extent
			 * details of the tmp inode
			 */
			free_ext_block(handle, tmp_inode);
	}

	/* We mark the tmp_inode dirty via ext4_ext_tree_init. */
	retval = ext4_journal_ensure_credits(handle, 1, 0);
	if (retval < 0)
		goto out_stop;

If any function within the migration loop (like the new EXT_MAX_BLOCKS check)
fails, it jumps to err_out with a negative error code in retval. However,
retval is then overwritten by ext4_journal_ensure_credits().

Since this function typically returns 0 or 1 on success, might this falsely
report success to userspace and leave the file unmodified or incomplete?


[Severity: Critical]
This is a pre-existing issue, but I am wondering if the rollback logic in
ext4_ext_migrate() erroneously frees active extent metadata when
ext4_ext_swap_inode_data() encounters an error.

In ext4_ext_swap_inode_data(), the original inode is permanently modified to
use extents:

	ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS);
	memcpy(ei->i_data, tmp_ei->i_data, sizeof(ei->i_data));

	/* ... snip ... */

	retval = free_ind_block(handle, inode, i_data);
	retval2 = ext4_mark_inode_dirty(handle, inode);
	if (unlikely(retval2 && !retval))
		retval = retval2;

err_out:
	return retval;

If free_ind_block() fails (for example, due to a lack of journal credits), it
returns an error. This error is caught in ext4_ext_migrate(), which then
attempts to clean up:

	else {
		retval = ext4_ext_swap_inode_data(handle, inode, tmp_inode);
		if (retval)
			/*
			 * if we fail to swap inode data free the extent
			 * details of the tmp inode
			 */
			free_ext_block(handle, tmp_inode);
	}

Since the extent tree root was already copied to the active inode, is it
possible that calling free_ext_block(handle, tmp_inode) blindly frees the
exact metadata blocks that the active inode now relies upon, leading to severe
on-disk data corruption?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260914082516.3442815-1-chenyichong@uniontech.com?part=1

  reply	other threads:[~2026-09-14  8:41 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-14  8:25 [PATCH v2] ext4: fix the logical block counter overflow in indirect migration Yichong Chen
2026-09-14  8:41 ` sashiko-bot [this message]
2026-09-14 10:06 ` Jan Kara

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260914084112.4F0831F000FF@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=chenyichong@uniontech.com \
    --cc=linux-ext4@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=tytso@mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox