From 446aaa6e7e993b38a6f21c6acfa68f3f1af3dbe3 Mon Sep 17 00:00:00 2001 From: Kazuya Mio Date: Tue, 24 Nov 2009 10:28:48 -0500 Subject: ext4: initialize moved_len before calling ext4_move_extents() The move_extent.moved_len is used to pass back the number of exchanged blocks count to user space. Currently the caller must clear this field; but we spend more code space checking for this requirement than simply zeroing the field ourselves, so let's just make life easier for everyone all around. Signed-off-by: Kazuya Mio Signed-off-by: Akira Fujita Signed-off-by: "Theodore Ts'o" --- fs/ext4/ioctl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/ext4/ioctl.c') diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index c1cdf613e725..31e5ee0c858f 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -239,6 +239,7 @@ setversion_out: } } + me.moved_len = 0; err = ext4_move_extents(filp, donor_filp, me.orig_start, me.donor_start, me.len, &me.moved_len); fput(donor_filp); -- cgit v1.2.3 From 4a58579b9e4e2a35d57e6c9c8483e52f6f1b7fd6 Mon Sep 17 00:00:00 2001 From: Akira Fujita Date: Sun, 6 Dec 2009 23:38:31 -0500 Subject: ext4: Fix insufficient checks in EXT4_IOC_MOVE_EXT This patch fixes three problems in the handling of the EXT4_IOC_MOVE_EXT ioctl: 1. In current EXT4_IOC_MOVE_EXT, there are read access mode checks for original and donor files, but they allow the illegal write access to donor file, since donor file is overwritten by original file data. To fix this problem, change access mode checks of original (r->r/w) and donor (r->w) files. 2. Disallow the use of donor files that have a setuid or setgid bits. 3. Call mnt_want_write() and mnt_drop_write() before and after ext4_move_extents() calling to get write access to a mount. Signed-off-by: Akira Fujita Signed-off-by: "Theodore Ts'o" --- fs/ext4/ioctl.c | 30 ++++++++++++++++++------------ fs/ext4/move_extent.c | 7 +++++++ 2 files changed, 25 insertions(+), 12 deletions(-) (limited to 'fs/ext4/ioctl.c') diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 31e5ee0c858f..b63d193126db 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -221,32 +221,38 @@ setversion_out: struct file *donor_filp; int err; + if (!(filp->f_mode & FMODE_READ) || + !(filp->f_mode & FMODE_WRITE)) + return -EBADF; + if (copy_from_user(&me, (struct move_extent __user *)arg, sizeof(me))) return -EFAULT; + me.moved_len = 0; donor_filp = fget(me.donor_fd); if (!donor_filp) return -EBADF; - if (!capable(CAP_DAC_OVERRIDE)) { - if ((current->real_cred->fsuid != inode->i_uid) || - !(inode->i_mode & S_IRUSR) || - !(donor_filp->f_dentry->d_inode->i_mode & - S_IRUSR)) { - fput(donor_filp); - return -EACCES; - } + if (!(donor_filp->f_mode & FMODE_WRITE)) { + err = -EBADF; + goto mext_out; } - me.moved_len = 0; + err = mnt_want_write(filp->f_path.mnt); + if (err) + goto mext_out; + err = ext4_move_extents(filp, donor_filp, me.orig_start, me.donor_start, me.len, &me.moved_len); - fput(donor_filp); + mnt_drop_write(filp->f_path.mnt); + if (me.moved_len > 0) + file_remove_suid(donor_filp); if (copy_to_user((struct move_extent *)arg, &me, sizeof(me))) - return -EFAULT; - + err = -EFAULT; +mext_out: + fput(donor_filp); return err; } diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index cad1e2edda7e..82c415be87a4 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c @@ -957,6 +957,13 @@ mext_check_arguments(struct inode *orig_inode, return -EINVAL; } + if (donor_inode->i_mode & (S_ISUID|S_ISGID)) { + ext4_debug("ext4 move extent: suid or sgid is set" + " to donor file [ino:orig %lu, donor %lu]\n", + orig_inode->i_ino, donor_inode->i_ino); + return -EINVAL; + } + /* Ext4 move extent does not support swapfile */ if (IS_SWAPFILE(orig_inode) || IS_SWAPFILE(donor_inode)) { ext4_debug("ext4 move extent: The argument files should " -- cgit v1.2.3