diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/ioctl.c | 30 | ||||
-rw-r--r-- | fs/ext4/move_extent.c | 7 |
2 files changed, 25 insertions, 12 deletions
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: | |||
221 | struct file *donor_filp; | 221 | struct file *donor_filp; |
222 | int err; | 222 | int err; |
223 | 223 | ||
224 | if (!(filp->f_mode & FMODE_READ) || | ||
225 | !(filp->f_mode & FMODE_WRITE)) | ||
226 | return -EBADF; | ||
227 | |||
224 | if (copy_from_user(&me, | 228 | if (copy_from_user(&me, |
225 | (struct move_extent __user *)arg, sizeof(me))) | 229 | (struct move_extent __user *)arg, sizeof(me))) |
226 | return -EFAULT; | 230 | return -EFAULT; |
231 | me.moved_len = 0; | ||
227 | 232 | ||
228 | donor_filp = fget(me.donor_fd); | 233 | donor_filp = fget(me.donor_fd); |
229 | if (!donor_filp) | 234 | if (!donor_filp) |
230 | return -EBADF; | 235 | return -EBADF; |
231 | 236 | ||
232 | if (!capable(CAP_DAC_OVERRIDE)) { | 237 | if (!(donor_filp->f_mode & FMODE_WRITE)) { |
233 | if ((current->real_cred->fsuid != inode->i_uid) || | 238 | err = -EBADF; |
234 | !(inode->i_mode & S_IRUSR) || | 239 | goto mext_out; |
235 | !(donor_filp->f_dentry->d_inode->i_mode & | ||
236 | S_IRUSR)) { | ||
237 | fput(donor_filp); | ||
238 | return -EACCES; | ||
239 | } | ||
240 | } | 240 | } |
241 | 241 | ||
242 | me.moved_len = 0; | 242 | err = mnt_want_write(filp->f_path.mnt); |
243 | if (err) | ||
244 | goto mext_out; | ||
245 | |||
243 | err = ext4_move_extents(filp, donor_filp, me.orig_start, | 246 | err = ext4_move_extents(filp, donor_filp, me.orig_start, |
244 | me.donor_start, me.len, &me.moved_len); | 247 | me.donor_start, me.len, &me.moved_len); |
245 | fput(donor_filp); | 248 | mnt_drop_write(filp->f_path.mnt); |
249 | if (me.moved_len > 0) | ||
250 | file_remove_suid(donor_filp); | ||
246 | 251 | ||
247 | if (copy_to_user((struct move_extent *)arg, &me, sizeof(me))) | 252 | if (copy_to_user((struct move_extent *)arg, &me, sizeof(me))) |
248 | return -EFAULT; | 253 | err = -EFAULT; |
249 | 254 | mext_out: | |
255 | fput(donor_filp); | ||
250 | return err; | 256 | return err; |
251 | } | 257 | } |
252 | 258 | ||
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, | |||
957 | return -EINVAL; | 957 | return -EINVAL; |
958 | } | 958 | } |
959 | 959 | ||
960 | if (donor_inode->i_mode & (S_ISUID|S_ISGID)) { | ||
961 | ext4_debug("ext4 move extent: suid or sgid is set" | ||
962 | " to donor file [ino:orig %lu, donor %lu]\n", | ||
963 | orig_inode->i_ino, donor_inode->i_ino); | ||
964 | return -EINVAL; | ||
965 | } | ||
966 | |||
960 | /* Ext4 move extent does not support swapfile */ | 967 | /* Ext4 move extent does not support swapfile */ |
961 | if (IS_SWAPFILE(orig_inode) || IS_SWAPFILE(donor_inode)) { | 968 | if (IS_SWAPFILE(orig_inode) || IS_SWAPFILE(donor_inode)) { |
962 | ext4_debug("ext4 move extent: The argument files should " | 969 | ext4_debug("ext4 move extent: The argument files should " |