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, ¶m);
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) }