diff options
| author | 2019-07-17 17:06:11 +0800 | |
|---|---|---|
| committer | 2019-08-23 07:57:15 -0700 | |
| commit | 4507847c86bfc64e9bdce941a0f707560d3df98a (patch) | |
| tree | 7e76cf839e82f3fdbf71f09943f0feb7e68bb7de | |
| parent | f2fs: fix to avoid data corruption by forbidding SSR overwrite (diff) | |
| download | wireguard-linux-4507847c86bfc64e9bdce941a0f707560d3df98a.tar.xz wireguard-linux-4507847c86bfc64e9bdce941a0f707560d3df98a.zip  | |
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>
Diffstat (limited to '')
| -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,  #define F2FS_IOC_PRECACHE_EXTENTS	_IO(F2FS_IOCTL_MAGIC, 15)  #define F2FS_IOC_RESIZE_FS		_IOW(F2FS_IOCTL_MAGIC, 16, __u64) +#define F2FS_IOC_GET_VOLUME_NAME	FS_IOC_GETFSLABEL +#define F2FS_IOC_SET_VOLUME_NAME	FS_IOC_SETFSLABEL +  #define F2FS_IOC_SET_ENCRYPTION_POLICY	FS_IOC_SET_ENCRYPTION_POLICY  #define F2FS_IOC_GET_ENCRYPTION_POLICY	FS_IOC_GET_ENCRYPTION_POLICY  #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 @@  #include <linux/uio.h>  #include <linux/uuid.h>  #include <linux/file.h> +#include <linux/nls.h>  #include "f2fs.h"  #include "node.h" @@ -3081,6 +3082,68 @@ static int f2fs_ioc_resize_fs(struct file *filp, unsigned long arg)  	return ret;  } +static int f2fs_get_volume_name(struct file *filp, unsigned long arg) +{ +	struct inode *inode = file_inode(filp); +	struct f2fs_sb_info *sbi = F2FS_I_SB(inode); +	char *vbuf; +	int count; +	int err = 0; + +	vbuf = f2fs_kzalloc(sbi, MAX_VOLUME_NAME, GFP_KERNEL); +	if (!vbuf) +		return -ENOMEM; + +	down_read(&sbi->sb_lock); +	count = utf16s_to_utf8s(sbi->raw_super->volume_name, +			ARRAY_SIZE(sbi->raw_super->volume_name), +			UTF16_LITTLE_ENDIAN, vbuf, MAX_VOLUME_NAME); +	up_read(&sbi->sb_lock); + +	if (copy_to_user((char __user *)arg, vbuf, +				min(FSLABEL_MAX, count))) +		err = -EFAULT; + +	kvfree(vbuf); +	return err; +} + +static int f2fs_set_volume_name(struct file *filp, unsigned long arg) +{ +	struct inode *inode = file_inode(filp); +	struct f2fs_sb_info *sbi = F2FS_I_SB(inode); +	char *vbuf; +	int err = 0; + +	if (!capable(CAP_SYS_ADMIN)) +		return -EPERM; + +	vbuf = strndup_user((const char __user *)arg, FSLABEL_MAX); +	if (IS_ERR(vbuf)) +		return PTR_ERR(vbuf); + +	err = mnt_want_write_file(filp); +	if (err) +		goto out; + +	down_write(&sbi->sb_lock); + +	memset(sbi->raw_super->volume_name, 0, +			sizeof(sbi->raw_super->volume_name)); +	utf8s_to_utf16s(vbuf, strlen(vbuf), UTF16_LITTLE_ENDIAN, +			sbi->raw_super->volume_name, +			ARRAY_SIZE(sbi->raw_super->volume_name)); + +	err = f2fs_commit_super(sbi, false); + +	up_write(&sbi->sb_lock); + +	mnt_drop_write_file(filp); +out: +	kfree(vbuf); +	return err; +} +  long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  {  	int ret; @@ -3144,6 +3207,10 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  		return f2fs_ioc_precache_extents(filp, arg);  	case F2FS_IOC_RESIZE_FS:  		return f2fs_ioc_resize_fs(filp, arg); +	case F2FS_IOC_GET_VOLUME_NAME: +		return f2fs_get_volume_name(filp, arg); +	case F2FS_IOC_SET_VOLUME_NAME: +		return f2fs_set_volume_name(filp, arg);  	default:  		return -ENOTTY;  	} @@ -3253,6 +3320,8 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  	case F2FS_IOC_SET_PIN_FILE:  	case F2FS_IOC_PRECACHE_EXTENTS:  	case F2FS_IOC_RESIZE_FS: +	case F2FS_IOC_GET_VOLUME_NAME: +	case F2FS_IOC_SET_VOLUME_NAME:  		break;  	default:  		return -ENOIOCTLCMD;  | 
