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>
			
			
This commit is contained in:
		
							parent
							
								
									899fee36fa
								
							
						
					
					
						commit
						4507847c86
					
				| @ -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 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user