aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAkira Fujita <a-fujita@rs.jp.nec.com>2009-12-06 23:38:31 -0500
committerTheodore Ts'o <tytso@mit.edu>2009-12-06 23:38:31 -0500
commit4a58579b9e4e2a35d57e6c9c8483e52f6f1b7fd6 (patch)
treef3a7f898a081d0917f7fe7f051aba687308cbf0a
parentb436b9bef84de6893e86346d8fbf7104bc520645 (diff)
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 <a-fujita@rs.jp.nec.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--fs/ext4/ioctl.c30
-rw-r--r--fs/ext4/move_extent.c7
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 254mext_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 "