diff options
author | Chao Yu <yuchao0@huawei.com> | 2019-07-17 05:06:11 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2019-08-23 10:57:15 -0400 |
commit | 4507847c86bfc64e9bdce941a0f707560d3df98a (patch) | |
tree | 7e76cf839e82f3fdbf71f09943f0feb7e68bb7de | |
parent | 899fee36fac07e49bb969e3f214e572eecb14f00 (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.h | 3 | ||||
-rw-r--r-- | fs/f2fs/file.c | 69 |
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 | ||
3085 | static 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 | |||
3111 | static 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); | ||
3142 | out: | ||
3143 | kfree(vbuf); | ||
3144 | return err; | ||
3145 | } | ||
3146 | |||
3084 | long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 3147 | long 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; |