Re: [PATCH] ext4: validate donor file superblock early in EXT4_IOC_MOVE_EXT
From: Andreas Dilger
Date: Mon Jun 08 2026 - 14:21:13 EST
On Jun 8, 2026, at 09:25, Yun Zhou <yun.zhou@xxxxxxxxxxxxx> wrote:
>
> Reject the EXT4_IOC_MOVE_EXT ioctl early if the donor file does not
> belong to the same superblock as the original file. Currently, this
> validation is performed inside ext4_move_extents() by
> mext_check_validity(), but only after lock_two_nondirectories() has
> already acquired the inode locks. When the donor fd refers to a file
> on a different filesystem (e.g., overlayfs), this late validation
> creates a circular lock dependency:
>
> CPU0 (overlayfs write) CPU1 (ext4 ioctl)
> ---- ----
> inode_lock(ovl_inode)
> mnt_want_write_file(filp)
> sb_start_write(ext4_sb) [sb_writers]
> backing_file_write_iter()
> vfs_iter_write(real_file)
> file_start_write(real_file)
> sb_start_write(ext4_sb) [blocked by freeze]
> lock_two_nondirectories()
> inode_lock(ovl_inode) [blocked]
>
> With a concurrent freeze operation holding sb_writers write side, this
> forms a deadlock cycle: CPU0 waits for freeze to complete, freeze waits
> for CPU1's sb_writers reader to exit, CPU1 waits for CPU0's inode lock.
>
> Since EXT4_IOC_MOVE_EXT exchanges physical extents between two files,
> it fundamentally requires both files to reside on the same ext4
> filesystem. Moving the superblock check before any lock acquisition
> is both semantically correct and eliminates the circular dependency
> by ensuring that cross-filesystem donor fds are rejected before
> sb_writers or inode locks are taken.
>
> Fixes: fcf6b1b729bc ("ext4: refactor ext4_move_extents code base")
> Reported-by: syzbot+ad6118a7584b607c67f2@xxxxxxxxxxxxxxxxxxxxxxxxx
> Closes: https://syzkaller.appspot.com/bug?extid=ad6118a7584b607c67f2
> Signed-off-by: Yun Zhou <yun.zhou@xxxxxxxxxxxxx>
Thanks for the patch. Looks good to me.
Reviewed-by: Andreas Dilger <adilger@xxxxxxxxx <mailto:adilger@xxxxxxxxx>>
> ---
> fs/ext4/ioctl.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
> index 1d0c3d4bdf47..f7cd419a3218 100644
> --- a/fs/ext4/ioctl.c
> +++ b/fs/ext4/ioctl.c
> @@ -1650,6 +1650,9 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd,
> if (!(fd_file(donor)->f_mode & FMODE_WRITE))
> return -EBADF;
>
> + if (file_inode(filp)->i_sb != file_inode(fd_file(donor))->i_sb)
> + return -EXDEV;
> +
> err = mnt_want_write_file(filp);
> if (err)
> return err;
> --
> 2.43.0
>
Cheers, Andreas