cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fsopen.c (11207B)


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