aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChao Yu2020-11-09 19:24:37 -0600
committerJaegeuk Kim2020-12-21 15:33:12 -0600
commit7bf39237aa7136dd6f1ace671cdc7b0421b2e914 (patch)
treeb3008778beaf94459fe5eb395bc65fb5dba84921
parent8db62952247d02f6f7abb517de238b25d698e948 (diff)
downloadkernel-7bf39237aa7136dd6f1ace671cdc7b0421b2e914.tar.gz
kernel-7bf39237aa7136dd6f1ace671cdc7b0421b2e914.tar.xz
kernel-7bf39237aa7136dd6f1ace671cdc7b0421b2e914.zip
f2fs: fix compat F2FS_IOC_{MOVE,GARBAGE_COLLECT}_RANGE
Eric reported a ioctl bug in below link: https://lore.kernel.org/linux-f2fs-devel/20201103032234.GB2875@sol.localdomain/ That said, on some 32-bit architectures, u64 has only 32-bit alignment, notably i386 and x86_32, so that size of struct f2fs_gc_range compiled in x86_32 is 20 bytes, however the size in x86_64 is 24 bytes, binary compiled in x86_32 can not call F2FS_IOC_GARBAGE_COLLECT_RANGE successfully due to mismatched value of ioctl command in between binary and f2fs module, similarly, F2FS_IOC_MOVE_RANGE will fail too. In this patch we introduce two ioctls for compatibility of above special 32-bit binary: - F2FS_IOC32_GARBAGE_COLLECT_RANGE - F2FS_IOC32_MOVE_RANGE Reported-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Chao Yu <yuchao0@huawei.com> Reviewed-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--fs/f2fs/file.c137
1 files changed, 104 insertions, 33 deletions
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 861a6697960a..8241b8bdb33c 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -2480,26 +2480,19 @@ out:
2480 return ret; 2480 return ret;
2481} 2481}
2482 2482
2483static int f2fs_ioc_gc_range(struct file *filp, unsigned long arg) 2483static int __f2fs_ioc_gc_range(struct file *filp, struct f2fs_gc_range *range)
2484{ 2484{
2485 struct inode *inode = file_inode(filp); 2485 struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp));
2486 struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
2487 struct f2fs_gc_range range;
2488 u64 end; 2486 u64 end;
2489 int ret; 2487 int ret;
2490 2488
2491 if (!capable(CAP_SYS_ADMIN)) 2489 if (!capable(CAP_SYS_ADMIN))
2492 return -EPERM; 2490 return -EPERM;
2493
2494 if (copy_from_user(&range, (struct f2fs_gc_range __user *)arg,
2495 sizeof(range)))
2496 return -EFAULT;
2497
2498 if (f2fs_readonly(sbi->sb)) 2491 if (f2fs_readonly(sbi->sb))
2499 return -EROFS; 2492 return -EROFS;
2500 2493
2501 end = range.start + range.len; 2494 end = range->start + range->len;
2502 if (end < range.start || range.start < MAIN_BLKADDR(sbi) || 2495 if (end < range->start || range->start < MAIN_BLKADDR(sbi) ||
2503 end >= MAX_BLKADDR(sbi)) 2496 end >= MAX_BLKADDR(sbi))
2504 return -EINVAL; 2497 return -EINVAL;
2505 2498
@@ -2508,7 +2501,7 @@ static int f2fs_ioc_gc_range(struct file *filp, unsigned long arg)
2508 return ret; 2501 return ret;
2509 2502
2510do_more: 2503do_more:
2511 if (!range.sync) { 2504 if (!range->sync) {
2512 if (!down_write_trylock(&sbi->gc_lock)) { 2505 if (!down_write_trylock(&sbi->gc_lock)) {
2513 ret = -EBUSY; 2506 ret = -EBUSY;
2514 goto out; 2507 goto out;
@@ -2517,20 +2510,30 @@ do_more:
2517 down_write(&sbi->gc_lock); 2510 down_write(&sbi->gc_lock);
2518 } 2511 }
2519 2512
2520 ret = f2fs_gc(sbi, range.sync, true, GET_SEGNO(sbi, range.start)); 2513 ret = f2fs_gc(sbi, range->sync, true, GET_SEGNO(sbi, range->start));
2521 if (ret) { 2514 if (ret) {
2522 if (ret == -EBUSY) 2515 if (ret == -EBUSY)
2523 ret = -EAGAIN; 2516 ret = -EAGAIN;
2524 goto out; 2517 goto out;
2525 } 2518 }
2526 range.start += BLKS_PER_SEC(sbi); 2519 range->start += BLKS_PER_SEC(sbi);
2527 if (range.start <= end) 2520 if (range->start <= end)
2528 goto do_more; 2521 goto do_more;
2529out: 2522out:
2530 mnt_drop_write_file(filp); 2523 mnt_drop_write_file(filp);
2531 return ret; 2524 return ret;
2532} 2525}
2533 2526
2527static int f2fs_ioc_gc_range(struct file *filp, unsigned long arg)
2528{
2529 struct f2fs_gc_range range;
2530
2531 if (copy_from_user(&range, (struct f2fs_gc_range __user *)arg,
2532 sizeof(range)))
2533 return -EFAULT;
2534 return __f2fs_ioc_gc_range(filp, &range);
2535}
2536
2534static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg) 2537static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg)
2535{ 2538{
2536 struct inode *inode = file_inode(filp); 2539 struct inode *inode = file_inode(filp);
@@ -2867,9 +2870,9 @@ out:
2867 return ret; 2870 return ret;
2868} 2871}
2869 2872
2870static int f2fs_ioc_move_range(struct file *filp, unsigned long arg) 2873static int __f2fs_ioc_move_range(struct file *filp,
2874 struct f2fs_move_range *range)
2871{ 2875{
2872 struct f2fs_move_range range;
2873 struct fd dst; 2876 struct fd dst;
2874 int err; 2877 int err;
2875 2878
@@ -2877,11 +2880,7 @@ static int f2fs_ioc_move_range(struct file *filp, unsigned long arg)
2877 !(filp->f_mode & FMODE_WRITE)) 2880 !(filp->f_mode & FMODE_WRITE))
2878 return -EBADF; 2881 return -EBADF;
2879 2882
2880 if (copy_from_user(&range, (struct f2fs_move_range __user *)arg, 2883 dst = fdget(range->dst_fd);
2881 sizeof(range)))
2882 return -EFAULT;
2883
2884 dst = fdget(range.dst_fd);
2885 if (!dst.file) 2884 if (!dst.file)
2886 return -EBADF; 2885 return -EBADF;
2887 2886
@@ -2894,8 +2893,8 @@ static int f2fs_ioc_move_range(struct file *filp, unsigned long arg)
2894 if (err) 2893 if (err)
2895 goto err_out; 2894 goto err_out;
2896 2895
2897 err = f2fs_move_file_range(filp, range.pos_in, dst.file, 2896 err = f2fs_move_file_range(filp, range->pos_in, dst.file,
2898 range.pos_out, range.len); 2897 range->pos_out, range->len);
2899 2898
2900 mnt_drop_write_file(filp); 2899 mnt_drop_write_file(filp);
2901err_out: 2900err_out:
@@ -2903,6 +2902,16 @@ err_out:
2903 return err; 2902 return err;
2904} 2903}
2905 2904
2905static int f2fs_ioc_move_range(struct file *filp, unsigned long arg)
2906{
2907 struct f2fs_move_range range;
2908
2909 if (copy_from_user(&range, (struct f2fs_move_range __user *)arg,
2910 sizeof(range)))
2911 return -EFAULT;
2912 return __f2fs_ioc_move_range(filp, &range);
2913}
2914
2906static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg) 2915static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg)
2907{ 2916{
2908 struct inode *inode = file_inode(filp); 2917 struct inode *inode = file_inode(filp);
@@ -4017,13 +4026,8 @@ out:
4017 return ret; 4026 return ret;
4018} 4027}
4019 4028
4020long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 4029static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
4021{ 4030{
4022 if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp)))))
4023 return -EIO;
4024 if (!f2fs_is_checkpoint_ready(F2FS_I_SB(file_inode(filp))))
4025 return -ENOSPC;
4026
4027 switch (cmd) { 4031 switch (cmd) {
4028 case FS_IOC_GETFLAGS: 4032 case FS_IOC_GETFLAGS:
4029 return f2fs_ioc_getflags(filp, arg); 4033 return f2fs_ioc_getflags(filp, arg);
@@ -4114,6 +4118,16 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
4114 } 4118 }
4115} 4119}
4116 4120
4121long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
4122{
4123 if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp)))))
4124 return -EIO;
4125 if (!f2fs_is_checkpoint_ready(F2FS_I_SB(file_inode(filp))))
4126 return -ENOSPC;
4127
4128 return __f2fs_ioctl(filp, cmd, arg);
4129}
4130
4117static ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) 4131static ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
4118{ 4132{
4119 struct file *file = iocb->ki_filp; 4133 struct file *file = iocb->ki_filp;
@@ -4230,8 +4244,63 @@ out:
4230} 4244}
4231 4245
4232#ifdef CONFIG_COMPAT 4246#ifdef CONFIG_COMPAT
4247struct compat_f2fs_gc_range {
4248 u32 sync;
4249 compat_u64 start;
4250 compat_u64 len;
4251};
4252#define F2FS_IOC32_GARBAGE_COLLECT_RANGE _IOW(F2FS_IOCTL_MAGIC, 11,\
4253 struct compat_f2fs_gc_range)
4254
4255static int f2fs_compat_ioc_gc_range(struct file *file, unsigned long arg)
4256{
4257 struct compat_f2fs_gc_range __user *urange;
4258 struct f2fs_gc_range range;
4259 int err;
4260
4261 urange = compat_ptr(arg);
4262 err = get_user(range.sync, &urange->sync);
4263 err |= get_user(range.start, &urange->start);
4264 err |= get_user(range.len, &urange->len);
4265 if (err)
4266 return -EFAULT;
4267
4268 return __f2fs_ioc_gc_range(file, &range);
4269}
4270
4271struct compat_f2fs_move_range {
4272 u32 dst_fd;
4273 compat_u64 pos_in;
4274 compat_u64 pos_out;
4275 compat_u64 len;
4276};
4277#define F2FS_IOC32_MOVE_RANGE _IOWR(F2FS_IOCTL_MAGIC, 9, \
4278 struct compat_f2fs_move_range)
4279
4280static int f2fs_compat_ioc_move_range(struct file *file, unsigned long arg)
4281{
4282 struct compat_f2fs_move_range __user *urange;
4283 struct f2fs_move_range range;
4284 int err;
4285
4286 urange = compat_ptr(arg);
4287 err = get_user(range.dst_fd, &urange->dst_fd);
4288 err |= get_user(range.pos_in, &urange->pos_in);
4289 err |= get_user(range.pos_out, &urange->pos_out);
4290 err |= get_user(range.len, &urange->len);
4291 if (err)
4292 return -EFAULT;
4293
4294 return __f2fs_ioc_move_range(file, &range);
4295}
4296
4233long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 4297long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
4234{ 4298{
4299 if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(file)))))
4300 return -EIO;
4301 if (!f2fs_is_checkpoint_ready(F2FS_I_SB(file_inode(file))))
4302 return -ENOSPC;
4303
4235 switch (cmd) { 4304 switch (cmd) {
4236 case FS_IOC32_GETFLAGS: 4305 case FS_IOC32_GETFLAGS:
4237 cmd = FS_IOC_GETFLAGS; 4306 cmd = FS_IOC_GETFLAGS;
@@ -4242,6 +4311,10 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
4242 case FS_IOC32_GETVERSION: 4311 case FS_IOC32_GETVERSION:
4243 cmd = FS_IOC_GETVERSION; 4312 cmd = FS_IOC_GETVERSION;
4244 break; 4313 break;
4314 case F2FS_IOC32_GARBAGE_COLLECT_RANGE:
4315 return f2fs_compat_ioc_gc_range(file, arg);
4316 case F2FS_IOC32_MOVE_RANGE:
4317 return f2fs_compat_ioc_move_range(file, arg);
4245 case F2FS_IOC_START_ATOMIC_WRITE: 4318 case F2FS_IOC_START_ATOMIC_WRITE:
4246 case F2FS_IOC_COMMIT_ATOMIC_WRITE: 4319 case F2FS_IOC_COMMIT_ATOMIC_WRITE:
4247 case F2FS_IOC_START_VOLATILE_WRITE: 4320 case F2FS_IOC_START_VOLATILE_WRITE:
@@ -4259,10 +4332,8 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
4259 case FS_IOC_GET_ENCRYPTION_KEY_STATUS: 4332 case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
4260 case FS_IOC_GET_ENCRYPTION_NONCE: 4333 case FS_IOC_GET_ENCRYPTION_NONCE:
4261 case F2FS_IOC_GARBAGE_COLLECT: 4334 case F2FS_IOC_GARBAGE_COLLECT:
4262 case F2FS_IOC_GARBAGE_COLLECT_RANGE:
4263 case F2FS_IOC_WRITE_CHECKPOINT: 4335 case F2FS_IOC_WRITE_CHECKPOINT:
4264 case F2FS_IOC_DEFRAGMENT: 4336 case F2FS_IOC_DEFRAGMENT:
4265 case F2FS_IOC_MOVE_RANGE:
4266 case F2FS_IOC_FLUSH_DEVICE: 4337 case F2FS_IOC_FLUSH_DEVICE:
4267 case F2FS_IOC_GET_FEATURES: 4338 case F2FS_IOC_GET_FEATURES:
4268 case FS_IOC_FSGETXATTR: 4339 case FS_IOC_FSGETXATTR:
@@ -4285,7 +4356,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
4285 default: 4356 default:
4286 return -ENOIOCTLCMD; 4357 return -ENOIOCTLCMD;
4287 } 4358 }
4288 return f2fs_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); 4359 return __f2fs_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
4289} 4360}
4290#endif 4361#endif
4291 4362