Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Filesystem access-by-fd.
0003  *
0004  * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  */
0007 
0008 #include <linux/fs_context.h>
0009 #include <linux/fs_parser.h>
0010 #include <linux/slab.h>
0011 #include <linux/uaccess.h>
0012 #include <linux/syscalls.h>
0013 #include <linux/security.h>
0014 #include <linux/anon_inodes.h>
0015 #include <linux/namei.h>
0016 #include <linux/file.h>
0017 #include <uapi/linux/mount.h>
0018 #include "internal.h"
0019 #include "mount.h"
0020 
0021 /*
0022  * Allow the user to read back any error, warning or informational messages.
0023  */
0024 static ssize_t fscontext_read(struct file *file,
0025                   char __user *_buf, size_t len, loff_t *pos)
0026 {
0027     struct fs_context *fc = file->private_data;
0028     struct fc_log *log = fc->log.log;
0029     unsigned int logsize = ARRAY_SIZE(log->buffer);
0030     ssize_t ret;
0031     char *p;
0032     bool need_free;
0033     int index, n;
0034 
0035     ret = mutex_lock_interruptible(&fc->uapi_mutex);
0036     if (ret < 0)
0037         return ret;
0038 
0039     if (log->head == log->tail) {
0040         mutex_unlock(&fc->uapi_mutex);
0041         return -ENODATA;
0042     }
0043 
0044     index = log->tail & (logsize - 1);
0045     p = log->buffer[index];
0046     need_free = log->need_free & (1 << index);
0047     log->buffer[index] = NULL;
0048     log->need_free &= ~(1 << index);
0049     log->tail++;
0050     mutex_unlock(&fc->uapi_mutex);
0051 
0052     ret = -EMSGSIZE;
0053     n = strlen(p);
0054     if (n > len)
0055         goto err_free;
0056     ret = -EFAULT;
0057     if (copy_to_user(_buf, p, n) != 0)
0058         goto err_free;
0059     ret = n;
0060 
0061 err_free:
0062     if (need_free)
0063         kfree(p);
0064     return ret;
0065 }
0066 
0067 static int fscontext_release(struct inode *inode, struct file *file)
0068 {
0069     struct fs_context *fc = file->private_data;
0070 
0071     if (fc) {
0072         file->private_data = NULL;
0073         put_fs_context(fc);
0074     }
0075     return 0;
0076 }
0077 
0078 const struct file_operations fscontext_fops = {
0079     .read       = fscontext_read,
0080     .release    = fscontext_release,
0081     .llseek     = no_llseek,
0082 };
0083 
0084 /*
0085  * Attach a filesystem context to a file and an fd.
0086  */
0087 static int fscontext_create_fd(struct fs_context *fc, unsigned int o_flags)
0088 {
0089     int fd;
0090 
0091     fd = anon_inode_getfd("[fscontext]", &fscontext_fops, fc,
0092                   O_RDWR | o_flags);
0093     if (fd < 0)
0094         put_fs_context(fc);
0095     return fd;
0096 }
0097 
0098 static int fscontext_alloc_log(struct fs_context *fc)
0099 {
0100     fc->log.log = kzalloc(sizeof(*fc->log.log), GFP_KERNEL);
0101     if (!fc->log.log)
0102         return -ENOMEM;
0103     refcount_set(&fc->log.log->usage, 1);
0104     fc->log.log->owner = fc->fs_type->owner;
0105     return 0;
0106 }
0107 
0108 /*
0109  * Open a filesystem by name so that it can be configured for mounting.
0110  *
0111  * We are allowed to specify a container in which the filesystem will be
0112  * opened, thereby indicating which namespaces will be used (notably, which
0113  * network namespace will be used for network filesystems).
0114  */
0115 SYSCALL_DEFINE2(fsopen, const char __user *, _fs_name, unsigned int, flags)
0116 {
0117     struct file_system_type *fs_type;
0118     struct fs_context *fc;
0119     const char *fs_name;
0120     int ret;
0121 
0122     if (!may_mount())
0123         return -EPERM;
0124 
0125     if (flags & ~FSOPEN_CLOEXEC)
0126         return -EINVAL;
0127 
0128     fs_name = strndup_user(_fs_name, PAGE_SIZE);
0129     if (IS_ERR(fs_name))
0130         return PTR_ERR(fs_name);
0131 
0132     fs_type = get_fs_type(fs_name);
0133     kfree(fs_name);
0134     if (!fs_type)
0135         return -ENODEV;
0136 
0137     fc = fs_context_for_mount(fs_type, 0);
0138     put_filesystem(fs_type);
0139     if (IS_ERR(fc))
0140         return PTR_ERR(fc);
0141 
0142     fc->phase = FS_CONTEXT_CREATE_PARAMS;
0143 
0144     ret = fscontext_alloc_log(fc);
0145     if (ret < 0)
0146         goto err_fc;
0147 
0148     return fscontext_create_fd(fc, flags & FSOPEN_CLOEXEC ? O_CLOEXEC : 0);
0149 
0150 err_fc:
0151     put_fs_context(fc);
0152     return ret;
0153 }
0154 
0155 /*
0156  * Pick a superblock into a context for reconfiguration.
0157  */
0158 SYSCALL_DEFINE3(fspick, int, dfd, const char __user *, path, unsigned int, flags)
0159 {
0160     struct fs_context *fc;
0161     struct path target;
0162     unsigned int lookup_flags;
0163     int ret;
0164 
0165     if (!may_mount())
0166         return -EPERM;
0167 
0168     if ((flags & ~(FSPICK_CLOEXEC |
0169                FSPICK_SYMLINK_NOFOLLOW |
0170                FSPICK_NO_AUTOMOUNT |
0171                FSPICK_EMPTY_PATH)) != 0)
0172         return -EINVAL;
0173 
0174     lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT;
0175     if (flags & FSPICK_SYMLINK_NOFOLLOW)
0176         lookup_flags &= ~LOOKUP_FOLLOW;
0177     if (flags & FSPICK_NO_AUTOMOUNT)
0178         lookup_flags &= ~LOOKUP_AUTOMOUNT;
0179     if (flags & FSPICK_EMPTY_PATH)
0180         lookup_flags |= LOOKUP_EMPTY;
0181     ret = user_path_at(dfd, path, lookup_flags, &target);
0182     if (ret < 0)
0183         goto err;
0184 
0185     ret = -EINVAL;
0186     if (target.mnt->mnt_root != target.dentry)
0187         goto err_path;
0188 
0189     fc = fs_context_for_reconfigure(target.dentry, 0, 0);
0190     if (IS_ERR(fc)) {
0191         ret = PTR_ERR(fc);
0192         goto err_path;
0193     }
0194 
0195     fc->phase = FS_CONTEXT_RECONF_PARAMS;
0196 
0197     ret = fscontext_alloc_log(fc);
0198     if (ret < 0)
0199         goto err_fc;
0200 
0201     path_put(&target);
0202     return fscontext_create_fd(fc, flags & FSPICK_CLOEXEC ? O_CLOEXEC : 0);
0203 
0204 err_fc:
0205     put_fs_context(fc);
0206 err_path:
0207     path_put(&target);
0208 err:
0209     return ret;
0210 }
0211 
0212 /*
0213  * Check the state and apply the configuration.  Note that this function is
0214  * allowed to 'steal' the value by setting param->xxx to NULL before returning.
0215  */
0216 static int vfs_fsconfig_locked(struct fs_context *fc, int cmd,
0217                    struct fs_parameter *param)
0218 {
0219     struct super_block *sb;
0220     int ret;
0221 
0222     ret = finish_clean_context(fc);
0223     if (ret)
0224         return ret;
0225     switch (cmd) {
0226     case FSCONFIG_CMD_CREATE:
0227         if (fc->phase != FS_CONTEXT_CREATE_PARAMS)
0228             return -EBUSY;
0229         if (!mount_capable(fc))
0230             return -EPERM;
0231         fc->phase = FS_CONTEXT_CREATING;
0232         ret = vfs_get_tree(fc);
0233         if (ret)
0234             break;
0235         sb = fc->root->d_sb;
0236         ret = security_sb_kern_mount(sb);
0237         if (unlikely(ret)) {
0238             fc_drop_locked(fc);
0239             break;
0240         }
0241         up_write(&sb->s_umount);
0242         fc->phase = FS_CONTEXT_AWAITING_MOUNT;
0243         return 0;
0244     case FSCONFIG_CMD_RECONFIGURE:
0245         if (fc->phase != FS_CONTEXT_RECONF_PARAMS)
0246             return -EBUSY;
0247         fc->phase = FS_CONTEXT_RECONFIGURING;
0248         sb = fc->root->d_sb;
0249         if (!ns_capable(sb->s_user_ns, CAP_SYS_ADMIN)) {
0250             ret = -EPERM;
0251             break;
0252         }
0253         down_write(&sb->s_umount);
0254         ret = reconfigure_super(fc);
0255         up_write(&sb->s_umount);
0256         if (ret)
0257             break;
0258         vfs_clean_context(fc);
0259         return 0;
0260     default:
0261         if (fc->phase != FS_CONTEXT_CREATE_PARAMS &&
0262             fc->phase != FS_CONTEXT_RECONF_PARAMS)
0263             return -EBUSY;
0264 
0265         return vfs_parse_fs_param(fc, param);
0266     }
0267     fc->phase = FS_CONTEXT_FAILED;
0268     return ret;
0269 }
0270 
0271 /**
0272  * sys_fsconfig - Set parameters and trigger actions on a context
0273  * @fd: The filesystem context to act upon
0274  * @cmd: The action to take
0275  * @_key: Where appropriate, the parameter key to set
0276  * @_value: Where appropriate, the parameter value to set
0277  * @aux: Additional information for the value
0278  *
0279  * This system call is used to set parameters on a context, including
0280  * superblock settings, data source and security labelling.
0281  *
0282  * Actions include triggering the creation of a superblock and the
0283  * reconfiguration of the superblock attached to the specified context.
0284  *
0285  * When setting a parameter, @cmd indicates the type of value being proposed
0286  * and @_key indicates the parameter to be altered.
0287  *
0288  * @_value and @aux are used to specify the value, should a value be required:
0289  *
0290  * (*) fsconfig_set_flag: No value is specified.  The parameter must be boolean
0291  *     in nature.  The key may be prefixed with "no" to invert the
0292  *     setting. @_value must be NULL and @aux must be 0.
0293  *
0294  * (*) fsconfig_set_string: A string value is specified.  The parameter can be
0295  *     expecting boolean, integer, string or take a path.  A conversion to an
0296  *     appropriate type will be attempted (which may include looking up as a
0297  *     path).  @_value points to a NUL-terminated string and @aux must be 0.
0298  *
0299  * (*) fsconfig_set_binary: A binary blob is specified.  @_value points to the
0300  *     blob and @aux indicates its size.  The parameter must be expecting a
0301  *     blob.
0302  *
0303  * (*) fsconfig_set_path: A non-empty path is specified.  The parameter must be
0304  *     expecting a path object.  @_value points to a NUL-terminated string that
0305  *     is the path and @aux is a file descriptor at which to start a relative
0306  *     lookup or AT_FDCWD.
0307  *
0308  * (*) fsconfig_set_path_empty: As fsconfig_set_path, but with AT_EMPTY_PATH
0309  *     implied.
0310  *
0311  * (*) fsconfig_set_fd: An open file descriptor is specified.  @_value must be
0312  *     NULL and @aux indicates the file descriptor.
0313  */
0314 SYSCALL_DEFINE5(fsconfig,
0315         int, fd,
0316         unsigned int, cmd,
0317         const char __user *, _key,
0318         const void __user *, _value,
0319         int, aux)
0320 {
0321     struct fs_context *fc;
0322     struct fd f;
0323     int ret;
0324     int lookup_flags = 0;
0325 
0326     struct fs_parameter param = {
0327         .type   = fs_value_is_undefined,
0328     };
0329 
0330     if (fd < 0)
0331         return -EINVAL;
0332 
0333     switch (cmd) {
0334     case FSCONFIG_SET_FLAG:
0335         if (!_key || _value || aux)
0336             return -EINVAL;
0337         break;
0338     case FSCONFIG_SET_STRING:
0339         if (!_key || !_value || aux)
0340             return -EINVAL;
0341         break;
0342     case FSCONFIG_SET_BINARY:
0343         if (!_key || !_value || aux <= 0 || aux > 1024 * 1024)
0344             return -EINVAL;
0345         break;
0346     case FSCONFIG_SET_PATH:
0347     case FSCONFIG_SET_PATH_EMPTY:
0348         if (!_key || !_value || (aux != AT_FDCWD && aux < 0))
0349             return -EINVAL;
0350         break;
0351     case FSCONFIG_SET_FD:
0352         if (!_key || _value || aux < 0)
0353             return -EINVAL;
0354         break;
0355     case FSCONFIG_CMD_CREATE:
0356     case FSCONFIG_CMD_RECONFIGURE:
0357         if (_key || _value || aux)
0358             return -EINVAL;
0359         break;
0360     default:
0361         return -EOPNOTSUPP;
0362     }
0363 
0364     f = fdget(fd);
0365     if (!f.file)
0366         return -EBADF;
0367     ret = -EINVAL;
0368     if (f.file->f_op != &fscontext_fops)
0369         goto out_f;
0370 
0371     fc = f.file->private_data;
0372     if (fc->ops == &legacy_fs_context_ops) {
0373         switch (cmd) {
0374         case FSCONFIG_SET_BINARY:
0375         case FSCONFIG_SET_PATH:
0376         case FSCONFIG_SET_PATH_EMPTY:
0377         case FSCONFIG_SET_FD:
0378             ret = -EOPNOTSUPP;
0379             goto out_f;
0380         }
0381     }
0382 
0383     if (_key) {
0384         param.key = strndup_user(_key, 256);
0385         if (IS_ERR(param.key)) {
0386             ret = PTR_ERR(param.key);
0387             goto out_f;
0388         }
0389     }
0390 
0391     switch (cmd) {
0392     case FSCONFIG_SET_FLAG:
0393         param.type = fs_value_is_flag;
0394         break;
0395     case FSCONFIG_SET_STRING:
0396         param.type = fs_value_is_string;
0397         param.string = strndup_user(_value, 256);
0398         if (IS_ERR(param.string)) {
0399             ret = PTR_ERR(param.string);
0400             goto out_key;
0401         }
0402         param.size = strlen(param.string);
0403         break;
0404     case FSCONFIG_SET_BINARY:
0405         param.type = fs_value_is_blob;
0406         param.size = aux;
0407         param.blob = memdup_user_nul(_value, aux);
0408         if (IS_ERR(param.blob)) {
0409             ret = PTR_ERR(param.blob);
0410             goto out_key;
0411         }
0412         break;
0413     case FSCONFIG_SET_PATH_EMPTY:
0414         lookup_flags = LOOKUP_EMPTY;
0415         fallthrough;
0416     case FSCONFIG_SET_PATH:
0417         param.type = fs_value_is_filename;
0418         param.name = getname_flags(_value, lookup_flags, NULL);
0419         if (IS_ERR(param.name)) {
0420             ret = PTR_ERR(param.name);
0421             goto out_key;
0422         }
0423         param.dirfd = aux;
0424         param.size = strlen(param.name->name);
0425         break;
0426     case FSCONFIG_SET_FD:
0427         param.type = fs_value_is_file;
0428         ret = -EBADF;
0429         param.file = fget(aux);
0430         if (!param.file)
0431             goto out_key;
0432         break;
0433     default:
0434         break;
0435     }
0436 
0437     ret = mutex_lock_interruptible(&fc->uapi_mutex);
0438     if (ret == 0) {
0439         ret = vfs_fsconfig_locked(fc, cmd, &param);
0440         mutex_unlock(&fc->uapi_mutex);
0441     }
0442 
0443     /* Clean up the our record of any value that we obtained from
0444      * userspace.  Note that the value may have been stolen by the LSM or
0445      * filesystem, in which case the value pointer will have been cleared.
0446      */
0447     switch (cmd) {
0448     case FSCONFIG_SET_STRING:
0449     case FSCONFIG_SET_BINARY:
0450         kfree(param.string);
0451         break;
0452     case FSCONFIG_SET_PATH:
0453     case FSCONFIG_SET_PATH_EMPTY:
0454         if (param.name)
0455             putname(param.name);
0456         break;
0457     case FSCONFIG_SET_FD:
0458         if (param.file)
0459             fput(param.file);
0460         break;
0461     default:
0462         break;
0463     }
0464 out_key:
0465     kfree(param.key);
0466 out_f:
0467     fdput(f);
0468     return ret;
0469 }