VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   32 Branches   54 Tags
b4d0d230ccfb5 (Thomas Gleixner     2019-05-20 19:08:01 +0200   1) // SPDX-License-Identifier: GPL-2.0-or-later
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000   2) /* Filesystem access-by-fd.
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000   3)  *
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000   4)  * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000   5)  * Written by David Howells (dhowells@redhat.com)
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000   6)  */
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000   7) 
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000   8) #include <linux/fs_context.h>
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000   9) #include <linux/fs_parser.h>
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  10) #include <linux/slab.h>
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  11) #include <linux/uaccess.h>
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  12) #include <linux/syscalls.h>
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  13) #include <linux/security.h>
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  14) #include <linux/anon_inodes.h>
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  15) #include <linux/namei.h>
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  16) #include <linux/file.h>
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  17) #include <uapi/linux/mount.h>
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000  18) #include "internal.h"
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  19) #include "mount.h"
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  20) 
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  21) /*
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  22)  * Allow the user to read back any error, warning or informational messages.
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  23)  */
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  24) static ssize_t fscontext_read(struct file *file,
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  25) 			      char __user *_buf, size_t len, loff_t *pos)
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  26) {
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  27) 	struct fs_context *fc = file->private_data;
cc3c0b533ab91 (Al Viro             2019-12-21 00:16:49 -0500  28) 	struct fc_log *log = fc->log.log;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  29) 	unsigned int logsize = ARRAY_SIZE(log->buffer);
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  30) 	ssize_t ret;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  31) 	char *p;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  32) 	bool need_free;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  33) 	int index, n;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  34) 
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  35) 	ret = mutex_lock_interruptible(&fc->uapi_mutex);
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  36) 	if (ret < 0)
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  37) 		return ret;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  38) 
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  39) 	if (log->head == log->tail) {
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  40) 		mutex_unlock(&fc->uapi_mutex);
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  41) 		return -ENODATA;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  42) 	}
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  43) 
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  44) 	index = log->tail & (logsize - 1);
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  45) 	p = log->buffer[index];
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  46) 	need_free = log->need_free & (1 << index);
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  47) 	log->buffer[index] = NULL;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  48) 	log->need_free &= ~(1 << index);
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  49) 	log->tail++;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  50) 	mutex_unlock(&fc->uapi_mutex);
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  51) 
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  52) 	ret = -EMSGSIZE;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  53) 	n = strlen(p);
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  54) 	if (n > len)
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  55) 		goto err_free;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  56) 	ret = -EFAULT;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  57) 	if (copy_to_user(_buf, p, n) != 0)
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  58) 		goto err_free;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  59) 	ret = n;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  60) 
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  61) err_free:
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  62) 	if (need_free)
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  63) 		kfree(p);
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  64) 	return ret;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  65) }
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  66) 
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  67) static int fscontext_release(struct inode *inode, struct file *file)
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  68) {
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  69) 	struct fs_context *fc = file->private_data;
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  70) 
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  71) 	if (fc) {
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  72) 		file->private_data = NULL;
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  73) 		put_fs_context(fc);
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  74) 	}
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  75) 	return 0;
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  76) }
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  77) 
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  78) const struct file_operations fscontext_fops = {
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  79) 	.read		= fscontext_read,
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  80) 	.release	= fscontext_release,
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  81) 	.llseek		= no_llseek,
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  82) };
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  83) 
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  84) /*
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  85)  * Attach a filesystem context to a file and an fd.
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  86)  */
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  87) static int fscontext_create_fd(struct fs_context *fc, unsigned int o_flags)
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  88) {
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  89) 	int fd;
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  90) 
1cdc415f10831 (Christian Brauner   2019-05-16 12:52:20 +0100  91) 	fd = anon_inode_getfd("[fscontext]", &fscontext_fops, fc,
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  92) 			      O_RDWR | o_flags);
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  93) 	if (fd < 0)
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  94) 		put_fs_context(fc);
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  95) 	return fd;
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  96) }
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000  97) 
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  98) static int fscontext_alloc_log(struct fs_context *fc)
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000  99) {
cc3c0b533ab91 (Al Viro             2019-12-21 00:16:49 -0500 100) 	fc->log.log = kzalloc(sizeof(*fc->log.log), GFP_KERNEL);
cc3c0b533ab91 (Al Viro             2019-12-21 00:16:49 -0500 101) 	if (!fc->log.log)
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000 102) 		return -ENOMEM;
cc3c0b533ab91 (Al Viro             2019-12-21 00:16:49 -0500 103) 	refcount_set(&fc->log.log->usage, 1);
cc3c0b533ab91 (Al Viro             2019-12-21 00:16:49 -0500 104) 	fc->log.log->owner = fc->fs_type->owner;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000 105) 	return 0;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000 106) }
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000 107) 
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 108) /*
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 109)  * Open a filesystem by name so that it can be configured for mounting.
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 110)  *
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 111)  * We are allowed to specify a container in which the filesystem will be
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 112)  * opened, thereby indicating which namespaces will be used (notably, which
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 113)  * network namespace will be used for network filesystems).
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 114)  */
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 115) SYSCALL_DEFINE2(fsopen, const char __user *, _fs_name, unsigned int, flags)
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 116) {
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 117) 	struct file_system_type *fs_type;
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 118) 	struct fs_context *fc;
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 119) 	const char *fs_name;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000 120) 	int ret;
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 121) 
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 122) 	if (!ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN))
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 123) 		return -EPERM;
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 124) 
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 125) 	if (flags & ~FSOPEN_CLOEXEC)
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 126) 		return -EINVAL;
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 127) 
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 128) 	fs_name = strndup_user(_fs_name, PAGE_SIZE);
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 129) 	if (IS_ERR(fs_name))
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 130) 		return PTR_ERR(fs_name);
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 131) 
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 132) 	fs_type = get_fs_type(fs_name);
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 133) 	kfree(fs_name);
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 134) 	if (!fs_type)
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 135) 		return -ENODEV;
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 136) 
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 137) 	fc = fs_context_for_mount(fs_type, 0);
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 138) 	put_filesystem(fs_type);
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 139) 	if (IS_ERR(fc))
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 140) 		return PTR_ERR(fc);
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 141) 
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 142) 	fc->phase = FS_CONTEXT_CREATE_PARAMS;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000 143) 
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000 144) 	ret = fscontext_alloc_log(fc);
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000 145) 	if (ret < 0)
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000 146) 		goto err_fc;
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000 147) 
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 148) 	return fscontext_create_fd(fc, flags & FSOPEN_CLOEXEC ? O_CLOEXEC : 0);
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000 149) 
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000 150) err_fc:
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000 151) 	put_fs_context(fc);
007ec26cdc9fe (David Howells       2018-11-01 23:34:29 +0000 152) 	return ret;
24dcb3d90a1f6 (David Howells       2018-11-01 23:33:31 +0000 153) }
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 154) 
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 155) /*
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 156)  * Pick a superblock into a context for reconfiguration.
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 157)  */
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 158) SYSCALL_DEFINE3(fspick, int, dfd, const char __user *, path, unsigned int, flags)
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 159) {
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 160) 	struct fs_context *fc;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 161) 	struct path target;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 162) 	unsigned int lookup_flags;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 163) 	int ret;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 164) 
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 165) 	if (!ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN))
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 166) 		return -EPERM;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 167) 
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 168) 	if ((flags & ~(FSPICK_CLOEXEC |
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 169) 		       FSPICK_SYMLINK_NOFOLLOW |
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 170) 		       FSPICK_NO_AUTOMOUNT |
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 171) 		       FSPICK_EMPTY_PATH)) != 0)
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 172) 		return -EINVAL;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 173) 
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 174) 	lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 175) 	if (flags & FSPICK_SYMLINK_NOFOLLOW)
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 176) 		lookup_flags &= ~LOOKUP_FOLLOW;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 177) 	if (flags & FSPICK_NO_AUTOMOUNT)
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 178) 		lookup_flags &= ~LOOKUP_AUTOMOUNT;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 179) 	if (flags & FSPICK_EMPTY_PATH)
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 180) 		lookup_flags |= LOOKUP_EMPTY;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 181) 	ret = user_path_at(dfd, path, lookup_flags, &target);
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 182) 	if (ret < 0)
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 183) 		goto err;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 184) 
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 185) 	ret = -EINVAL;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 186) 	if (target.mnt->mnt_root != target.dentry)
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 187) 		goto err_path;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 188) 
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 189) 	fc = fs_context_for_reconfigure(target.dentry, 0, 0);
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 190) 	if (IS_ERR(fc)) {
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 191) 		ret = PTR_ERR(fc);
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 192) 		goto err_path;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 193) 	}
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 194) 
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 195) 	fc->phase = FS_CONTEXT_RECONF_PARAMS;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 196) 
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 197) 	ret = fscontext_alloc_log(fc);
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 198) 	if (ret < 0)
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 199) 		goto err_fc;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 200) 
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 201) 	path_put(&target);
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 202) 	return fscontext_create_fd(fc, flags & FSPICK_CLOEXEC ? O_CLOEXEC : 0);
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 203) 
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 204) err_fc:
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 205) 	put_fs_context(fc);
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 206) err_path:
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 207) 	path_put(&target);
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 208) err:
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 209) 	return ret;
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 210) }
cf3cba4a429be (David Howells       2018-11-01 23:36:23 +0000 211) 
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 212) /*
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 213)  * Check the state and apply the configuration.  Note that this function is
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 214)  * allowed to 'steal' the value by setting param->xxx to NULL before returning.
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 215)  */
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 216) static int vfs_fsconfig_locked(struct fs_context *fc, int cmd,
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 217) 			       struct fs_parameter *param)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 218) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 219) 	struct super_block *sb;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 220) 	int ret;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 221) 
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 222) 	ret = finish_clean_context(fc);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 223) 	if (ret)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 224) 		return ret;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 225) 	switch (cmd) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 226) 	case FSCONFIG_CMD_CREATE:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 227) 		if (fc->phase != FS_CONTEXT_CREATE_PARAMS)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 228) 			return -EBUSY;
c3aabf0780a50 (Al Viro             2019-05-13 12:57:22 -0400 229) 		if (!mount_capable(fc))
c3aabf0780a50 (Al Viro             2019-05-13 12:57:22 -0400 230) 			return -EPERM;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 231) 		fc->phase = FS_CONTEXT_CREATING;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 232) 		ret = vfs_get_tree(fc);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 233) 		if (ret)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 234) 			break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 235) 		sb = fc->root->d_sb;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 236) 		ret = security_sb_kern_mount(sb);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 237) 		if (unlikely(ret)) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 238) 			fc_drop_locked(fc);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 239) 			break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 240) 		}
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 241) 		up_write(&sb->s_umount);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 242) 		fc->phase = FS_CONTEXT_AWAITING_MOUNT;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 243) 		return 0;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 244) 	case FSCONFIG_CMD_RECONFIGURE:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 245) 		if (fc->phase != FS_CONTEXT_RECONF_PARAMS)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 246) 			return -EBUSY;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 247) 		fc->phase = FS_CONTEXT_RECONFIGURING;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 248) 		sb = fc->root->d_sb;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 249) 		if (!ns_capable(sb->s_user_ns, CAP_SYS_ADMIN)) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 250) 			ret = -EPERM;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 251) 			break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 252) 		}
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 253) 		down_write(&sb->s_umount);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 254) 		ret = reconfigure_super(fc);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 255) 		up_write(&sb->s_umount);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 256) 		if (ret)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 257) 			break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 258) 		vfs_clean_context(fc);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 259) 		return 0;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 260) 	default:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 261) 		if (fc->phase != FS_CONTEXT_CREATE_PARAMS &&
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 262) 		    fc->phase != FS_CONTEXT_RECONF_PARAMS)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 263) 			return -EBUSY;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 264) 
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 265) 		return vfs_parse_fs_param(fc, param);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 266) 	}
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 267) 	fc->phase = FS_CONTEXT_FAILED;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 268) 	return ret;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 269) }
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 270) 
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 271) /**
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 272)  * sys_fsconfig - Set parameters and trigger actions on a context
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 273)  * @fd: The filesystem context to act upon
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 274)  * @cmd: The action to take
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 275)  * @_key: Where appropriate, the parameter key to set
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 276)  * @_value: Where appropriate, the parameter value to set
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 277)  * @aux: Additional information for the value
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 278)  *
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 279)  * This system call is used to set parameters on a context, including
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 280)  * superblock settings, data source and security labelling.
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 281)  *
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 282)  * Actions include triggering the creation of a superblock and the
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 283)  * reconfiguration of the superblock attached to the specified context.
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 284)  *
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 285)  * When setting a parameter, @cmd indicates the type of value being proposed
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 286)  * and @_key indicates the parameter to be altered.
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 287)  *
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 288)  * @_value and @aux are used to specify the value, should a value be required:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 289)  *
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 290)  * (*) fsconfig_set_flag: No value is specified.  The parameter must be boolean
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 291)  *     in nature.  The key may be prefixed with "no" to invert the
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 292)  *     setting. @_value must be NULL and @aux must be 0.
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 293)  *
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 294)  * (*) fsconfig_set_string: A string value is specified.  The parameter can be
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 295)  *     expecting boolean, integer, string or take a path.  A conversion to an
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 296)  *     appropriate type will be attempted (which may include looking up as a
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 297)  *     path).  @_value points to a NUL-terminated string and @aux must be 0.
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 298)  *
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 299)  * (*) fsconfig_set_binary: A binary blob is specified.  @_value points to the
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 300)  *     blob and @aux indicates its size.  The parameter must be expecting a
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 301)  *     blob.
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 302)  *
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 303)  * (*) fsconfig_set_path: A non-empty path is specified.  The parameter must be
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 304)  *     expecting a path object.  @_value points to a NUL-terminated string that
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 305)  *     is the path and @aux is a file descriptor at which to start a relative
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 306)  *     lookup or AT_FDCWD.
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 307)  *
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 308)  * (*) fsconfig_set_path_empty: As fsconfig_set_path, but with AT_EMPTY_PATH
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 309)  *     implied.
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 310)  *
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 311)  * (*) fsconfig_set_fd: An open file descriptor is specified.  @_value must be
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 312)  *     NULL and @aux indicates the file descriptor.
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 313)  */
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 314) SYSCALL_DEFINE5(fsconfig,
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 315) 		int, fd,
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 316) 		unsigned int, cmd,
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 317) 		const char __user *, _key,
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 318) 		const void __user *, _value,
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 319) 		int, aux)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 320) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 321) 	struct fs_context *fc;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 322) 	struct fd f;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 323) 	int ret;
aa1918f949144 (Al Viro             2019-12-17 20:09:08 -0500 324) 	int lookup_flags = 0;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 325) 
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 326) 	struct fs_parameter param = {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 327) 		.type	= fs_value_is_undefined,
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 328) 	};
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 329) 
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 330) 	if (fd < 0)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 331) 		return -EINVAL;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 332) 
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 333) 	switch (cmd) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 334) 	case FSCONFIG_SET_FLAG:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 335) 		if (!_key || _value || aux)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 336) 			return -EINVAL;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 337) 		break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 338) 	case FSCONFIG_SET_STRING:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 339) 		if (!_key || !_value || aux)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 340) 			return -EINVAL;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 341) 		break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 342) 	case FSCONFIG_SET_BINARY:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 343) 		if (!_key || !_value || aux <= 0 || aux > 1024 * 1024)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 344) 			return -EINVAL;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 345) 		break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 346) 	case FSCONFIG_SET_PATH:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 347) 	case FSCONFIG_SET_PATH_EMPTY:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 348) 		if (!_key || !_value || (aux != AT_FDCWD && aux < 0))
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 349) 			return -EINVAL;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 350) 		break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 351) 	case FSCONFIG_SET_FD:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 352) 		if (!_key || _value || aux < 0)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 353) 			return -EINVAL;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 354) 		break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 355) 	case FSCONFIG_CMD_CREATE:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 356) 	case FSCONFIG_CMD_RECONFIGURE:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 357) 		if (_key || _value || aux)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 358) 			return -EINVAL;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 359) 		break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 360) 	default:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 361) 		return -EOPNOTSUPP;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 362) 	}
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 363) 
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 364) 	f = fdget(fd);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 365) 	if (!f.file)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 366) 		return -EBADF;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 367) 	ret = -EINVAL;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 368) 	if (f.file->f_op != &fscontext_fops)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 369) 		goto out_f;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 370) 
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 371) 	fc = f.file->private_data;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 372) 	if (fc->ops == &legacy_fs_context_ops) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 373) 		switch (cmd) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 374) 		case FSCONFIG_SET_BINARY:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 375) 		case FSCONFIG_SET_PATH:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 376) 		case FSCONFIG_SET_PATH_EMPTY:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 377) 		case FSCONFIG_SET_FD:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 378) 			ret = -EOPNOTSUPP;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 379) 			goto out_f;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 380) 		}
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 381) 	}
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 382) 
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 383) 	if (_key) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 384) 		param.key = strndup_user(_key, 256);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 385) 		if (IS_ERR(param.key)) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 386) 			ret = PTR_ERR(param.key);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 387) 			goto out_f;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 388) 		}
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 389) 	}
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 390) 
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 391) 	switch (cmd) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 392) 	case FSCONFIG_SET_FLAG:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 393) 		param.type = fs_value_is_flag;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 394) 		break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 395) 	case FSCONFIG_SET_STRING:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 396) 		param.type = fs_value_is_string;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 397) 		param.string = strndup_user(_value, 256);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 398) 		if (IS_ERR(param.string)) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 399) 			ret = PTR_ERR(param.string);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 400) 			goto out_key;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 401) 		}
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 402) 		param.size = strlen(param.string);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 403) 		break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 404) 	case FSCONFIG_SET_BINARY:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 405) 		param.type = fs_value_is_blob;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 406) 		param.size = aux;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 407) 		param.blob = memdup_user_nul(_value, aux);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 408) 		if (IS_ERR(param.blob)) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 409) 			ret = PTR_ERR(param.blob);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 410) 			goto out_key;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 411) 		}
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 412) 		break;
aa1918f949144 (Al Viro             2019-12-17 20:09:08 -0500 413) 	case FSCONFIG_SET_PATH_EMPTY:
aa1918f949144 (Al Viro             2019-12-17 20:09:08 -0500 414) 		lookup_flags = LOOKUP_EMPTY;
df561f6688fef (Gustavo A. R. Silva 2020-08-23 17:36:59 -0500 415) 		fallthrough;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 416) 	case FSCONFIG_SET_PATH:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 417) 		param.type = fs_value_is_filename;
aa1918f949144 (Al Viro             2019-12-17 20:09:08 -0500 418) 		param.name = getname_flags(_value, lookup_flags, NULL);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 419) 		if (IS_ERR(param.name)) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 420) 			ret = PTR_ERR(param.name);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 421) 			goto out_key;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 422) 		}
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 423) 		param.dirfd = aux;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 424) 		param.size = strlen(param.name->name);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 425) 		break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 426) 	case FSCONFIG_SET_FD:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 427) 		param.type = fs_value_is_file;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 428) 		ret = -EBADF;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 429) 		param.file = fget(aux);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 430) 		if (!param.file)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 431) 			goto out_key;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 432) 		break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 433) 	default:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 434) 		break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 435) 	}
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 436) 
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 437) 	ret = mutex_lock_interruptible(&fc->uapi_mutex);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 438) 	if (ret == 0) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 439) 		ret = vfs_fsconfig_locked(fc, cmd, &param);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 440) 		mutex_unlock(&fc->uapi_mutex);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 441) 	}
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 442) 
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 443) 	/* Clean up the our record of any value that we obtained from
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 444) 	 * userspace.  Note that the value may have been stolen by the LSM or
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 445) 	 * filesystem, in which case the value pointer will have been cleared.
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 446) 	 */
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 447) 	switch (cmd) {
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 448) 	case FSCONFIG_SET_STRING:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 449) 	case FSCONFIG_SET_BINARY:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 450) 		kfree(param.string);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 451) 		break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 452) 	case FSCONFIG_SET_PATH:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 453) 	case FSCONFIG_SET_PATH_EMPTY:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 454) 		if (param.name)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 455) 			putname(param.name);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 456) 		break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 457) 	case FSCONFIG_SET_FD:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 458) 		if (param.file)
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 459) 			fput(param.file);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 460) 		break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 461) 	default:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 462) 		break;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 463) 	}
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 464) out_key:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 465) 	kfree(param.key);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 466) out_f:
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 467) 	fdput(f);
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 468) 	return ret;
ecdab150fddb4 (David Howells       2018-11-01 23:36:09 +0000 469) }