]> www.infradead.org Git - users/willy/linux.git/commitdiff
vfs: syscall: Add fsopen() to prepare for superblock creation
authorDavid Howells <dhowells@redhat.com>
Fri, 7 Sep 2018 06:41:01 +0000 (07:41 +0100)
committerDavid Howells <dhowells@redhat.com>
Tue, 23 Oct 2018 16:39:00 +0000 (17:39 +0100)
Provide an fsopen() system call that starts the process of preparing to
create a superblock that will then be mountable, using an fd as a context
handle.  fsopen() is given the name of the filesystem that will be used:

int mfd = fsopen(const char *fsname, unsigned int flags);

where flags can be 0 or FSOPEN_CLOEXEC.

For example:

sfd = fsopen("ext4", FSOPEN_CLOEXEC);
fsconfig(sfd, FSCONFIG_SET_PATH, "source", "/dev/sda1", AT_FDCWD);
fsconfig(sfd, FSCONFIG_SET_FLAG, "noatime", NULL, 0);
fsconfig(sfd, FSCONFIG_SET_FLAG, "acl", NULL, 0);
fsconfig(sfd, FSCONFIG_SET_FLAG, "user_xattr", NULL, 0);
fsconfig(sfd, FSCONFIG_SET_STRING, "sb", "1", 0);
fsconfig(sfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
fsinfo(sfd, NULL, ...); // query new superblock attributes
mfd = fsmount(sfd, FSMOUNT_CLOEXEC, MS_RELATIME);
move_mount(mfd, "", sfd, AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH);

sfd = fsopen("afs", -1);
fsconfig(fd, FSCONFIG_SET_STRING, "source",
 "#grand.central.org:root.cell", 0);
fsconfig(fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
mfd = fsmount(sfd, 0, MS_NODEV);
move_mount(mfd, "", sfd, AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH);

If an error is reported at any step, an error message may be available to be
read() back (ENODATA will be reported if there isn't an error available) in
the form:

"e <subsys>:<problem>"
"e SELinux:Mount on mountpoint not permitted"

Once fsmount() has been called, further fsconfig() calls will incur EBUSY,
even if the fsmount() fails.  read() is still possible to retrieve error
information.

The fsopen() syscall creates a mount context and hangs it of the fd that it
returns.

Netlink is not used because it is optional and would make the core VFS
dependent on the networking layer and also potentially add network
namespace issues.

Note that, for the moment, the caller must have SYS_CAP_ADMIN to use
fsopen().

Signed-off-by: David Howells <dhowells@redhat.com>
cc: linux-api@vger.kernel.org

arch/x86/entry/syscalls/syscall_32.tbl
arch/x86/entry/syscalls/syscall_64.tbl
fs/Makefile
fs/fs_context.c
fs/fsopen.c [new file with mode: 0644]
include/linux/fs_context.h
include/linux/syscalls.h
include/uapi/linux/mount.h

index 76d092b7d1b09bb359a783ec9f86ed32dd801c07..1647fefd296914f37410ed4fc03144fa5390b840 100644 (file)
 386    i386    rseq                    sys_rseq                        __ia32_sys_rseq
 387    i386    open_tree               sys_open_tree                   __ia32_sys_open_tree
 388    i386    move_mount              sys_move_mount                  __ia32_sys_move_mount
+389    i386    fsopen                  sys_fsopen                      __ia32_sys_fsopen
index 37ba4e65eee6e4f3be5f37df7d73cf5c73458e9e..235d33dbccb2a99553fede353701d90ace47a61c 100644 (file)
 334    common  rseq                    __x64_sys_rseq
 335    common  open_tree               __x64_sys_open_tree
 336    common  move_mount              __x64_sys_move_mount
+337    common  fsopen                  __x64_sys_fsopen
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
index ae681523b4b1b0f939215d63eb7b37dea9368a3f..e3ea8093b17867514b1acbf7bc69dc709e88179b 100644 (file)
@@ -13,7 +13,7 @@ obj-y :=      open.o read_write.o file_table.o super.o \
                seq_file.o xattr.o libfs.o fs-writeback.o \
                pnode.o splice.o sync.o utimes.o d_path.o \
                stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \
-               fs_context.o fs_parser.o
+               fs_context.o fs_parser.o fsopen.o
 
 ifeq ($(CONFIG_BLOCK),y)
 obj-y +=       buffer.o block_dev.o direct-io.o mpage.o
index 4087ed85a470555b8316959cbadd1d13fcfb87db..f9c59857675618e9590332d084db436ccceea597 100644 (file)
@@ -274,6 +274,8 @@ struct fs_context *vfs_new_fs_context(struct file_system_type *fs_type,
        fc->fs_type     = get_filesystem(fs_type);
        fc->cred        = get_current_cred();
 
+       mutex_init(&fc->uapi_mutex);
+
        switch (purpose) {
        case FS_CONTEXT_FOR_KERNEL_MOUNT:
                fc->sb_flags |= SB_KERNMOUNT;
@@ -341,6 +343,8 @@ struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc,
        if (!fc)
                return ERR_PTR(-ENOMEM);
 
+       mutex_init(&fc->uapi_mutex);
+
        fc->fs_private  = NULL;
        fc->s_fs_info   = NULL;
        fc->source      = NULL;
diff --git a/fs/fsopen.c b/fs/fsopen.c
new file mode 100644 (file)
index 0000000..762101f
--- /dev/null
@@ -0,0 +1,88 @@
+/* Filesystem access-by-fd.
+ *
+ * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/fs_context.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/syscalls.h>
+#include <linux/security.h>
+#include <linux/anon_inodes.h>
+#include <linux/namei.h>
+#include <linux/file.h>
+#include <uapi/linux/mount.h>
+#include "mount.h"
+
+static int fscontext_release(struct inode *inode, struct file *file)
+{
+       struct fs_context *fc = file->private_data;
+
+       if (fc) {
+               file->private_data = NULL;
+               put_fs_context(fc);
+       }
+       return 0;
+}
+
+const struct file_operations fscontext_fops = {
+       .release        = fscontext_release,
+       .llseek         = no_llseek,
+};
+
+/*
+ * Attach a filesystem context to a file and an fd.
+ */
+static int fscontext_create_fd(struct fs_context *fc, unsigned int o_flags)
+{
+       int fd;
+
+       fd = anon_inode_getfd("fscontext", &fscontext_fops, fc,
+                             O_RDWR | o_flags);
+       if (fd < 0)
+               put_fs_context(fc);
+       return fd;
+}
+
+/*
+ * Open a filesystem by name so that it can be configured for mounting.
+ *
+ * We are allowed to specify a container in which the filesystem will be
+ * opened, thereby indicating which namespaces will be used (notably, which
+ * network namespace will be used for network filesystems).
+ */
+SYSCALL_DEFINE2(fsopen, const char __user *, _fs_name, unsigned int, flags)
+{
+       struct file_system_type *fs_type;
+       struct fs_context *fc;
+       const char *fs_name;
+
+       if (!ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (flags & ~FSOPEN_CLOEXEC)
+               return -EINVAL;
+
+       fs_name = strndup_user(_fs_name, PAGE_SIZE);
+       if (IS_ERR(fs_name))
+               return PTR_ERR(fs_name);
+
+       fs_type = get_fs_type(fs_name);
+       kfree(fs_name);
+       if (!fs_type)
+               return -ENODEV;
+
+       fc = vfs_new_fs_context(fs_type, NULL, 0, 0, FS_CONTEXT_FOR_USER_MOUNT);
+       put_filesystem(fs_type);
+       if (IS_ERR(fc))
+               return PTR_ERR(fc);
+
+       fc->phase = FS_CONTEXT_CREATE_PARAMS;
+       return fscontext_create_fd(fc, flags & FSOPEN_CLOEXEC ? O_CLOEXEC : 0);
+}
index 0415510f64edc2bca168335748734bd174c8f110..37f8bafaaec334b2c8bf557f92f401492a430943 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/mutex.h>
 
 struct cred;
 struct dentry;
@@ -37,6 +38,19 @@ enum fs_context_purpose {
        FS_CONTEXT_FOR_EMERGENCY_RO,    /* Emergency reconfiguration to R/O */
 };
 
+/*
+ * Userspace usage phase for fsopen/fspick.
+ */
+enum fs_context_phase {
+       FS_CONTEXT_CREATE_PARAMS,       /* Loading params for sb creation */
+       FS_CONTEXT_CREATING,            /* A superblock is being created */
+       FS_CONTEXT_AWAITING_MOUNT,      /* Superblock created, awaiting fsmount() */
+       FS_CONTEXT_AWAITING_RECONF,     /* Awaiting initialisation for reconfiguration */
+       FS_CONTEXT_RECONF_PARAMS,       /* Loading params for reconfiguration */
+       FS_CONTEXT_RECONFIGURING,       /* Reconfiguring the superblock */
+       FS_CONTEXT_FAILED,              /* Failed to correctly transition a context */
+};
+
 /*
  * Type of parameter value.
  */
@@ -77,6 +91,7 @@ struct fs_parameter {
  */
 struct fs_context {
        const struct fs_context_operations *ops;
+       struct mutex            uapi_mutex;     /* Userspace access mutex */
        struct file_system_type *fs_type;
        void                    *fs_private;    /* The filesystem's context */
        struct dentry           *root;          /* The root and superblock */
@@ -91,6 +106,7 @@ struct fs_context {
        unsigned int            sb_flags_mask;  /* Superblock flags that were changed */
        unsigned int            lsm_flags;      /* Information flags from the fs to the LSM */
        enum fs_context_purpose purpose:8;
+       enum fs_context_phase   phase:8;        /* The phase the context is in */
        bool                    sloppy:1;       /* T if unrecognised options are okay */
        bool                    silent:1;       /* T if "o silent" specified */
        bool                    need_free:1;    /* Need to call ops->free() */
@@ -136,6 +152,8 @@ extern int vfs_get_super(struct fs_context *fc,
                         int (*fill_super)(struct super_block *sb,
                                           struct fs_context *fc));
 
+extern const struct file_operations fscontext_fops;
+
 #define logfc(FC, FMT, ...) pr_notice(FMT, ## __VA_ARGS__)
 
 /**
index 79042396f7e59755a46a0947b67f2953fd45528e..650d99c919871fe202c3de2cb9350e88bdd0c7f7 100644 (file)
@@ -910,6 +910,7 @@ asmlinkage long sys_open_tree(int dfd, const char __user *path, unsigned flags);
 asmlinkage long sys_move_mount(int from_dfd, const char __user *from_path,
                               int to_dfd, const char __user *to_path,
                               unsigned int ms_flags);
+asmlinkage long sys_fsopen(const char __user *fs_name, unsigned int flags);
 
 /*
  * Architecture-specific system calls
index 3634e065836cb99e6c38b029d15d77c4ef10d602..7570df43d08fdfc097a011e9b67f09f48698987d 100644 (file)
@@ -72,4 +72,9 @@
 #define MOVE_MOUNT_T_EMPTY_PATH                0x00000040 /* Empty to path permitted */
 #define MOVE_MOUNT__MASK               0x00000077
 
+/*
+ * fsopen() flags.
+ */
+#define FSOPEN_CLOEXEC         0x00000001
+
 #endif /* _UAPI_LINUX_MOUNT_H */