summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChao Yu <yuchao0@huawei.com>2019-07-17 05:06:11 -0400
committerJaegeuk Kim <jaegeuk@kernel.org>2019-08-23 10:57:15 -0400
commit4507847c86bfc64e9bdce941a0f707560d3df98a (patch)
tree7e76cf839e82f3fdbf71f09943f0feb7e68bb7de
parent899fee36fac07e49bb969e3f214e572eecb14f00 (diff)
f2fs: support FS_IOC_{GET,SET}FSLABEL
Support two generic fs ioctls FS_IOC_{GET,SET}FSLABEL, letting f2fs pass generic/492 testcase. Fixes were made by Eric where: - f2fs: fix buffer overruns in FS_IOC_{GET, SET}FSLABEL utf16s_to_utf8s() and utf8s_to_utf16s() take the number of characters, not the number of bytes. - f2fs: fix copying too many bytes in FS_IOC_SETFSLABEL Userspace provides a null-terminated string, so don't assume that the full FSLABEL_MAX bytes can always be copied. - f2fs: add missing authorization check in FS_IOC_SETFSLABEL FS_IOC_SETFSLABEL modifies the filesystem superblock, so it shouldn't be allowed to regular users. Require CAP_SYS_ADMIN, like xfs and btrfs do. Signed-off-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--fs/f2fs/f2fs.h3
-rw-r--r--fs/f2fs/file.c69
2 files changed, 72 insertions, 0 deletions
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 09ad4116d635..d2b718e33f88 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -418,6 +418,9 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,
418#define F2FS_IOC_PRECACHE_EXTENTS _IO(F2FS_IOCTL_MAGIC, 15) 418#define F2FS_IOC_PRECACHE_EXTENTS _IO(F2FS_IOCTL_MAGIC, 15)
419#define F2FS_IOC_RESIZE_FS _IOW(F2FS_IOCTL_MAGIC, 16, __u64) 419#define F2FS_IOC_RESIZE_FS _IOW(F2FS_IOCTL_MAGIC, 16, __u64)
420 420
421#define F2FS_IOC_GET_VOLUME_NAME FS_IOC_GETFSLABEL
422#define F2FS_IOC_SET_VOLUME_NAME FS_IOC_SETFSLABEL
423
421#define F2FS_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY 424#define F2FS_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY
422#define F2FS_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY 425#define F2FS_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY
423#define F2FS_IOC_GET_ENCRYPTION_PWSALT FS_IOC_GET_ENCRYPTION_PWSALT 426#define F2FS_IOC_GET_ENCRYPTION_PWSALT FS_IOC_GET_ENCRYPTION_PWSALT
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index b1f38f2795bc..344e0bd638e5 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -20,6 +20,7 @@
20#include <linux/uio.h> 20#include <linux/uio.h>
21#include <linux/uuid.h> 21#include <linux/uuid.h>
22#include <linux/file.h> 22#include <linux/file.h>
23#include <linux/nls.h>
23 24
24#include "f2fs.h" 25#include "f2fs.h"
25#include "node.h" 26#include "node.h"
@@ -3081,6 +3082,68 @@ static int f2fs_ioc_resize_fs(struct file *filp, unsigned long arg)
3081 return ret; 3082 return ret;
3082} 3083}
3083 3084
3085static int f2fs_get_volume_name(struct file *filp, unsigned long arg)
3086{
3087 struct inode *inode = file_inode(filp);
3088 struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3089 char *vbuf;
3090 int count;
3091 int err = 0;
3092
3093 vbuf = f2fs_kzalloc(sbi, MAX_VOLUME_NAME, GFP_KERNEL);
3094 if (!vbuf)
3095 return -ENOMEM;
3096
3097 down_read(&sbi->sb_lock);
3098 count = utf16s_to_utf8s(sbi->raw_super->volume_name,
3099 ARRAY_SIZE(sbi->raw_super->volume_name),
3100 UTF16_LITTLE_ENDIAN, vbuf, MAX_VOLUME_NAME);
3101 up_read(&sbi->sb_lock);
3102
3103 if (copy_to_user((char __user *)arg, vbuf,
3104 min(FSLABEL_MAX, count)))
3105 err = -EFAULT;
3106
3107 kvfree(vbuf);
3108 return err;
3109}
3110
3111static int f2fs_set_volume_name(struct file *filp, unsigned long arg)
3112{
3113 struct inode *inode = file_inode(filp);
3114 struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3115 char *vbuf;
3116 int err = 0;
3117
3118 if (!capable(CAP_SYS_ADMIN))
3119 return -EPERM;
3120
3121 vbuf = strndup_user((const char __user *)arg, FSLABEL_MAX);
3122 if (IS_ERR(vbuf))
3123 return PTR_ERR(vbuf);
3124
3125 err = mnt_want_write_file(filp);
3126 if (err)
3127 goto out;
3128
3129 down_write(&sbi->sb_lock);
3130
3131 memset(sbi->raw_super->volume_name, 0,
3132 sizeof(sbi->raw_super->volume_name));
3133 utf8s_to_utf16s(vbuf, strlen(vbuf), UTF16_LITTLE_ENDIAN,
3134 sbi->raw_super->volume_name,
3135 ARRAY_SIZE(sbi->raw_super->volume_name));
3136
3137 err = f2fs_commit_super(sbi, false);
3138
3139 up_write(&sbi->sb_lock);
3140
3141 mnt_drop_write_file(filp);
3142out:
3143 kfree(vbuf);
3144 return err;
3145}
3146
3084long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 3147long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
3085{ 3148{
3086 int ret; 3149 int ret;
@@ -3144,6 +3207,10 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
3144 return f2fs_ioc_precache_extents(filp, arg); 3207 return f2fs_ioc_precache_extents(filp, arg);
3145 case F2FS_IOC_RESIZE_FS: 3208 case F2FS_IOC_RESIZE_FS:
3146 return f2fs_ioc_resize_fs(filp, arg); 3209 return f2fs_ioc_resize_fs(filp, arg);
3210 case F2FS_IOC_GET_VOLUME_NAME:
3211 return f2fs_get_volume_name(filp, arg);
3212 case F2FS_IOC_SET_VOLUME_NAME:
3213 return f2fs_set_volume_name(filp, arg);
3147 default: 3214 default:
3148 return -ENOTTY; 3215 return -ENOTTY;
3149 } 3216 }
@@ -3253,6 +3320,8 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
3253 case F2FS_IOC_SET_PIN_FILE: 3320 case F2FS_IOC_SET_PIN_FILE:
3254 case F2FS_IOC_PRECACHE_EXTENTS: 3321 case F2FS_IOC_PRECACHE_EXTENTS:
3255 case F2FS_IOC_RESIZE_FS: 3322 case F2FS_IOC_RESIZE_FS:
3323 case F2FS_IOC_GET_VOLUME_NAME:
3324 case F2FS_IOC_SET_VOLUME_NAME:
3256 break; 3325 break;
3257 default: 3326 default:
3258 return -ENOIOCTLCMD; 3327 return -ENOIOCTLCMD;