[PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

Subsystems: abi/api, filesystems (vfs and infrastructure), the rest, x86 architecture (32-bit and 64-bit), x86 entry code

STALE2489d

64 messages, 11 authors, 2019-10-09 · open the first message on its own page

[PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: David Howells <dhowells@redhat.com>
Date: 2018-07-10 22:44:09

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);
	write(sfd, "s /dev/sdb1"); // note I'm ignoring write's length arg
	write(sfd, "o noatime");
	write(sfd, "o acl");
	write(sfd, "o user_attr");
	write(sfd, "o iversion");
	write(sfd, "o ");
	write(sfd, "r /my/container"); // root inside the fs
	write(sfd, "x create"); // create the superblock
	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);
	write(sfd, "s %grand.central.org:root.cell");
	write(sfd, "o cell=grand.central.org");
	write(sfd, "r /");
	write(sfd, "x create");
	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 write() 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 |    1 
 arch/x86/entry/syscalls/syscall_64.tbl |    1 
 fs/Makefile                            |    2 
 fs/fs_context.c                        |    4 +
 fs/fsopen.c                            |  209 ++++++++++++++++++++++++++++++++
 include/linux/fs_context.h             |    2 
 include/linux/syscalls.h               |    1 
 include/uapi/linux/fs.h                |    5 +
 8 files changed, 224 insertions(+), 1 deletion(-)
 create mode 100644 fs/fsopen.c
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index 76d092b7d1b0..1647fefd2969 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -400,3 +400,4 @@
 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
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 37ba4e65eee6..235d33dbccb2 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -345,6 +345,7 @@
 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
diff --git a/fs/Makefile b/fs/Makefile
index 7e9ca59ac3a7..d3b33798998e 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -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_context.o fsopen.o
 
 ifeq ($(CONFIG_BLOCK),y)
 obj-y +=	buffer.o block_dev.o direct-io.o mpage.o
diff --git a/fs/fs_context.c b/fs/fs_context.c
index b7c84e0aa2f9..a2d745e6d356 100644
--- a/fs/fs_context.c
+++ b/fs/fs_context.c
@@ -251,6 +251,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;
@@ -335,6 +337,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
index 000000000000..28bb72bda163
--- /dev/null
+++ b/fs/fsopen.c
@@ -0,0 +1,209 @@
+/* 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 "mount.h"
+
+/*
+ * Userspace writes configuration data and commands to the fd and we parse it
+ * here.  For the moment, we assume a single option or command per write.  Each
+ * line written is of the form
+ *
+ *	<command_type><space><stuff...>
+ *
+ *	s /dev/sda1				-- Source device
+ *	o noatime				-- Option without value
+ *	o cell=grand.central.org		-- Option with value
+ *	x create				-- Create a superblock
+ *	x reconfigure				-- Reconfigure a superblock
+ */
+static ssize_t fscontext_write(struct file *file,
+			       const char __user *_buf, size_t len, loff_t *pos)
+{
+	struct fs_context *fc = file->private_data;
+	char opt[2], *data;
+	ssize_t ret;
+
+	if (len < 3 || len > 4095)
+		return -EINVAL;
+
+	if (copy_from_user(opt, _buf, 2) != 0)
+		return -EFAULT;
+	switch (opt[0]) {
+	case 's':
+	case 'o':
+	case 'x':
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (opt[1] != ' ')
+		return -EINVAL;
+
+	data = memdup_user_nul(_buf + 2, len - 2);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	/* From this point onwards we need to lock the fd against someone
+	 * trying to mount it.
+	 */
+	ret = mutex_lock_interruptible(&fc->uapi_mutex);
+	if (ret < 0)
+		goto err_free;
+
+	if (fc->phase == FS_CONTEXT_AWAITING_RECONF) {
+		if (fc->fs_type->init_fs_context) {
+			ret = fc->fs_type->init_fs_context(fc, fc->root);
+			if (ret < 0) {
+				fc->phase = FS_CONTEXT_FAILED;
+				goto err_unlock;
+			}
+		} else {
+			/* Leave legacy context ops in place */
+		}
+
+		/* Do the security check last because ->init_fs_context may
+		 * change the namespace subscriptions.
+		 */
+		ret = security_fs_context_alloc(fc, fc->root);
+		if (ret < 0) {
+			fc->phase = FS_CONTEXT_FAILED;
+			goto err_unlock;
+		}
+
+		fc->phase = FS_CONTEXT_RECONF_PARAMS;
+	}
+
+	ret = -EINVAL;
+	switch (opt[0]) {
+	case 's':
+		if (fc->phase != FS_CONTEXT_CREATE_PARAMS &&
+		    fc->phase != FS_CONTEXT_RECONF_PARAMS)
+			goto wrong_phase;
+		ret = vfs_set_fs_source(fc, data, len - 2);
+		if (ret < 0)
+			goto err_unlock;
+		break;
+
+	case 'o':
+		if (fc->phase != FS_CONTEXT_CREATE_PARAMS &&
+		    fc->phase != FS_CONTEXT_RECONF_PARAMS)
+			goto wrong_phase;
+		ret = vfs_parse_fs_option(fc, data, len - 2);
+		if (ret < 0)
+			goto err_unlock;
+		break;
+
+	case 'x':
+		if (strcmp(data, "create") == 0) {
+			if (fc->phase != FS_CONTEXT_CREATE_PARAMS)
+				goto wrong_phase;
+			fc->phase = FS_CONTEXT_CREATING;
+			ret = vfs_get_tree(fc);
+			if (ret == 0)
+				fc->phase = FS_CONTEXT_AWAITING_MOUNT;
+			else
+				fc->phase = FS_CONTEXT_FAILED;
+		} else {
+			ret = -EOPNOTSUPP;
+		}
+		if (ret < 0)
+			goto err_unlock;
+		break;
+
+	default:
+		goto err_unlock;
+	}
+
+	ret = len;
+err_unlock:
+	mutex_unlock(&fc->uapi_mutex);
+err_free:
+	kfree(data);
+	return ret;
+
+wrong_phase:
+	ret = -EBUSY;
+	goto err_unlock;
+}
+
+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_fs_fops = {
+	.write		= fscontext_write,
+	.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_fs_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, 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);
+}
diff --git a/include/linux/fs_context.h b/include/linux/fs_context.h
index f157ff935a1e..387f25d7acc4 100644
--- a/include/linux/fs_context.h
+++ b/include/linux/fs_context.h
@@ -14,6 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/mutex.h>
 
 struct cred;
 struct dentry;
@@ -58,6 +59,7 @@ enum fs_context_phase {
  */
 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 */
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 3c0855d9b105..ad6c7ff33c01 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -904,6 +904,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
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index 1c982eb44ff4..f8818e6cddd6 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -344,4 +344,9 @@ typedef int __bitwise __kernel_rwf_t;
 #define RWF_SUPPORTED	(RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT |\
 			 RWF_APPEND)
 
+/*
+ * Flags for fsopen() and co.
+ */
+#define FSOPEN_CLOEXEC		0x00000001
+
 #endif /* _UAPI_LINUX_FS_H */

[MANPAGE PATCH] Add manpage for fsopen(2), fspick(2) and fsmount(2)

From: David Howells <dhowells@redhat.com>
Date: 2018-07-10 22:54:09

Add a manual page to document the fsopen(), fspick() and fsmount() system
calls.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 man2/fsmount.2 |    1 
 man2/fsopen.2  |  357 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 man2/fspick.2  |    1 
 3 files changed, 359 insertions(+)
 create mode 100644 man2/fsmount.2
 create mode 100644 man2/fsopen.2
 create mode 100644 man2/fspick.2
diff --git a/man2/fsmount.2 b/man2/fsmount.2
new file mode 100644
index 000000000..2bf59fc3e
--- /dev/null
+++ b/man2/fsmount.2
@@ -0,0 +1 @@
+.so man2/fsopen.2
diff --git a/man2/fsopen.2 b/man2/fsopen.2
new file mode 100644
index 000000000..1bc761ab4
--- /dev/null
+++ b/man2/fsopen.2
@@ -0,0 +1,357 @@
+'\" t
+.\" Copyright (c) 2018 David Howells <dhowells@redhat.com>
+.\"
+.\" %%%LICENSE_START(VERBATIM)
+.\" Permission is granted to make and distribute verbatim copies of this
+.\" manual provided the copyright notice and this permission notice are
+.\" preserved on all copies.
+.\"
+.\" Permission is granted to copy and distribute modified versions of this
+.\" manual under the conditions for verbatim copying, provided that the
+.\" entire resulting derived work is distributed under the terms of a
+.\" permission notice identical to this one.
+.\"
+.\" Since the Linux kernel and libraries are constantly changing, this
+.\" manual page may be incorrect or out-of-date.  The author(s) assume no
+.\" responsibility for errors or omissions, or for damages resulting from
+.\" the use of the information contained herein.  The author(s) may not
+.\" have taken the same level of care in the production of this manual,
+.\" which is licensed free of charge, as they might when working
+.\" professionally.
+.\"
+.\" Formatted or processed versions of this manual, if unaccompanied by
+.\" the source, must acknowledge the copyright and authors of this work.
+.\" %%%LICENSE_END
+.\"
+.TH FSOPEN 2 2018-06-07 "Linux" "Linux Programmer's Manual"
+.SH NAME
+fsopen, fsmount, fspick \- Handle filesystem (re-)configuration and mounting
+.SH SYNOPSIS
+.nf
+.B #include <sys/types.h>
+.br
+.B #include <sys/mount.h>
+.br
+.B #include <unistd.h>
+.br
+.BR "#include <fcntl.h>           " "/* Definition of AT_* constants */"
+.PP
+.BI "int fsopen(const char *" fsname ", unsigned int " flags );
+.PP
+.BI "int fsmount(int " fd ", unsigned int " flags ", unsigned int " ms_flags );
+.PP
+.BI "int fspick(int " dirfd ", const char *" pathname ", unsigned int " flags );
+.fi
+.PP
+.IR Note :
+There are no glibc wrappers for these system calls.
+.SH DESCRIPTION
+.PP
+.BR fsopen ()
+creates a new filesystem configuration context within the kernel for the
+filesystem named in the
+.I fsname
+parameter and attaches it to a file descriptor, which it then returns.  The
+file descriptor can be marked close-on-exec by setting
+.B FSOPEN_CLOEXEC
+in flags.
+.PP
+The
+file descriptor can then be used to configure the desired filesystem parameters
+and security parameters by using
+.BR write (2)
+to pass parameters to it and then writing a command to actually create the
+filesystem representation.
+.PP
+The file descriptor also serves as a channel by which more comprehensive error,
+warning and information messages may be retrieved from the kernel using
+.BR read (2).
+.PP
+Once the kernel's filesystem representation has been created, it can be queried
+by calling
+.BR fsinfo (2)
+on the file descriptor.  fsinfo() will spot that the target is actually a
+creation context and look inside that.
+.PP
+.BR fsmount ()
+can then be called to create a mount object that refers to the newly created
+filesystem representation, with the propagation and mount restrictions to be
+applied specified in
+.IR ms_flags .
+The mount object is then attached to a new file descriptor that looks like one
+created by
+.BR open "(2) with " O_PATH " or " open_tree (2).
+This can be passed to
+.BR move_mount (2)
+to attach the mount object to a mountpoint, thereby completing the process.
+.PP
+The file descriptor returned by fsmount() is marked close-on-exec if
+FSMOUNT_CLOEXEC is specified in
+.IR flags .
+.PP
+After fsmount() has completed, the context created by fsopen() is reset and
+moved to reconfiguration state, allowing the new superblock to be reconfigured.
+.PP
+.BR fspick ()
+creates a new filesystem context within the kernel, attaches the superblock
+specified by
+.IR dfd ", " pathname ", " flags
+and puts it into the reconfiguration state and attached the context to a new
+file descriptor that can then be parameterised with
+.BR write (2)
+exactly the same as for the context created by fsopen() above.
+.PP
+.I flags
+is an OR'd together mask of
+.B FSPICK_CLOEXEC
+which indicates that the returned file descriptor should be marked
+close-on-exec and
+.BR FSPICK_SYMLINK_NOFOLLOW ", " FSPICK_NO_AUTOMOUNT " and " FSPICK_EMPTY_PATH
+which control the pathwalk to the target object (see below).
+
+.\"________________________________________________________
+.SS Writable Command Interface
+Superblock (re-)configuration is achieved by writing command strings to the
+context file descriptor using
+.BR write (2).
+Each string is prefixed with a specifier indicating the class of command
+being specified.  The available commands include:
+.TP
+\fB"o <option>"\fP
+Specify a filesystem or security parameter.
+.I <option>
+is typically a key or key=val format string.  Since the length of the option is
+given to write(), the option may include any sort of character, including
+spaces and commas or even binary data.
+.TP
+\fB"s <name>"\fP
+Specify a device file, network server or other other source specification.
+This may be optional, depending on the filesystem, and it may be possible to
+provide multiple of them to a filesystem.
+.TP
+\fB"x create"\fP
+End the filesystem configuration phase and try and create a representation in
+the kernel with the parameters specified.  After this, the context is shifted
+to the mount-pending state waiting for an fsmount() call to occur.
+.TP
+\fB"x reconfigure"\fP
+End a filesystem reconfiguration phase try to apply the parameters to the
+filesystem representation.  After this, the context gets reset and put back to
+the start of the reconfiguration phase again.
+.PP
+With this interface, option strings are not limited to 4096 bytes, either
+individually or in sum, and they are also not restricted to text-only options.
+Further, errors may be given individually for each option and not aggregated or
+dumped into the kernel log.
+
+.\"________________________________________________________
+.SS Message Retrieval Interface
+The context file descriptor may be queried for message strings at any time by
+calling
+.BR read (2)
+on the file descriptor.  This will return formatted messages that are prefixed
+to indicate their class:
+.TP
+\fB"e <message>"\fP
+An error message string was logged.
+.TP
+\fB"i <message>"\fP
+An informational message string was logged.
+.TP
+\fB"w <message>"\fP
+An warning message string was logged.
+.PP
+Messages are removed from the queue as they're read.
+
+.\"________________________________________________________
+.SH EXAMPLES
+To illustrate the process, here's an example whereby this can be used to mount
+an ext4 filesystem on /dev/sdb1 onto /mnt.  Note that the example ignores the
+fact that
+.BR write (2)
+has a length parameter and that errors might occur.
+.PP
+.in +4n
+.nf
+sfd = fsopen("ext4", FSOPEN_CLOEXEC);
+write(sfd, "s /dev/sdb1");
+write(sfd, "o noatime");
+write(sfd, "o acl");
+write(sfd, "o user_attr");
+write(sfd, "o iversion");
+write(sfd, "x create");
+fsinfo(sfd, NULL, ...);
+mfd = fsmount(sfd, FSMOUNT_CLOEXEC, MS_RELATIME);
+move_mount(mfd, "", sfd, AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH);
+.fi
+.in
+.PP
+Here, an ext4 context is created first and attached to sfd.  This is then told
+where its source will be, given a bunch of options and created.
+.BR fsinfo (2)
+can then be used to query the filesystem.  Then fsmount() is called to create a
+mount object and
+.BR move_mount (2)
+is called to attach it to its intended mountpoint.
+.PP
+And here's an example of mounting from an NFS server:
+.PP
+.in +4n
+.nf
+sfd = fsopen("nfs", 0);
+write(sfd, "s example.com/pub/linux");
+write(sfd, "o nfsvers=3");
+write(sfd, "o rsize=65536");
+write(sfd, "o wsize=65536");
+write(sfd, "o rdma");
+write(sfd, "x create");
+mfd = fsmount(sfd, 0, MS_NODEV);
+move_mount(mfd, "", sfd, AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH);
+.fi
+.in
+.PP
+Reconfiguration can be achieved by:
+.PP
+.in +4n
+.nf
+sfd = fspick(AT_FDCWD, "/mnt", FSPICK_NO_AUTOMOUNT | FSPICK_CLOEXEC);
+write(sfd, "o ro");
+write(sfd, "x reconfigure");
+.fi
+.in
+.PP
+or:
+.PP
+.in +4n
+.nf
+sfd = fsopen(...);
+...
+mfd = fsmount(sfd, ...);
+...
+write(sfd, "o ro");
+write(sfd, "x reconfigure");
+.fi
+.in
+
+
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success, all three functions return a file descriptor.  On error, \-1 is
+returned, and
+.I errno
+is set appropriately.
+.SH ERRORS
+The error values given below result from filesystem type independent
+errors.
+Each filesystem type may have its own special errors and its
+own special behavior.
+See the Linux kernel source code for details.
+.TP
+.B EACCES
+A component of a path was not searchable.
+(See also
+.BR path_resolution (7).)
+.TP
+.B EACCES
+Mounting a read-only filesystem was attempted without giving the
+.B MS_RDONLY
+flag.
+.TP
+.B EACCES
+The block device
+.I source
+is located on a filesystem mounted with the
+.B MS_NODEV
+option.
+.\" mtk: Probably: write permission is required for MS_BIND, with
+.\" the error EPERM if not present; CAP_DAC_OVERRIDE is required.
+.TP
+.B EBUSY
+.I source
+cannot be reconfigured read-only, because it still holds files open for
+writing.
+.TP
+.B EFAULT
+One of the pointer arguments points outside the user address space.
+.TP
+.B EINVAL
+.I source
+had an invalid superblock.
+.TP
+.B EINVAL
+.I ms_flags
+includes more than one of
+.BR MS_SHARED ,
+.BR MS_PRIVATE ,
+.BR MS_SLAVE ,
+or
+.BR MS_UNBINDABLE .
+.TP
+.BR EINVAL
+An attempt was made to bind mount an unbindable mount.
+.TP
+.B ELOOP
+Too many links encountered during pathname resolution.
+.TP
+.B EMFILE
+The system has too many open files to create more.
+.TP
+.B ENFILE
+The process has too many open files to create more.
+.TP
+.B ENAMETOOLONG
+A pathname was longer than
+.BR MAXPATHLEN .
+.TP
+.B ENODEV
+Filesystem
+.I fsname
+not configured in the kernel.
+.TP
+.B ENOENT
+A pathname was empty or had a nonexistent component.
+.TP
+.B ENOMEM
+The kernel could not allocate sufficient memory to complete the call.
+.TP
+.B ENOTBLK
+.I source
+is not a block device (and a device was required).
+.TP
+.B ENOTDIR
+.IR pathname ,
+or a prefix of
+.IR source ,
+is not a directory.
+.TP
+.B ENXIO
+The major number of the block device
+.I source
+is out of range.
+.TP
+.B EPERM
+The caller does not have the required privileges.
+.SH CONFORMING TO
+These functions are Linux-specific and should not be used in programs intended
+to be portable.
+.SH VERSIONS
+.BR fsopen "(), " fsmount "() and " fspick ()
+were added to Linux in kernel 4.18.
+.SH NOTES
+Glibc does not (yet) provide a wrapper for the
+.BR fsopen "() , " fsmount "() or " fspick "()"
+system calls; call them using
+.BR syscall (2).
+.SH SEE ALSO
+.BR mountpoint (1),
+.BR move_mount (2),
+.BR open_tree (2),
+.BR umount (2),
+.BR mount_namespaces (7),
+.BR path_resolution (7),
+.BR findmnt (8),
+.BR lsblk (8),
+.BR mount (8),
+.BR umount (8)
diff --git a/man2/fspick.2 b/man2/fspick.2
new file mode 100644
index 000000000..2bf59fc3e
--- /dev/null
+++ b/man2/fspick.2
@@ -0,0 +1 @@
+.so man2/fsopen.2

Re: [MANPAGE PATCH] Add manpage for fsopen(2), fspick(2) and fsmount(2)

From: Michael Kerrisk (man-pages) <hidden>
Date: 2019-10-09 09:52:16

Hello David,

See my previous mail.

With respect to the patch below, would you be willing to review
the content of this man-pages patch to see if it accurately reflects 
what was merged into the kernel, and then resubmit please?

Thanks,

Michael

On 7/11/18 12:54 AM, David Howells wrote:
quoted hunk
Add a manual page to document the fsopen(), fspick() and fsmount() system
calls.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 man2/fsmount.2 |    1 
 man2/fsopen.2  |  357 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 man2/fspick.2  |    1 
 3 files changed, 359 insertions(+)
 create mode 100644 man2/fsmount.2
 create mode 100644 man2/fsopen.2
 create mode 100644 man2/fspick.2
diff --git a/man2/fsmount.2 b/man2/fsmount.2
new file mode 100644
index 000000000..2bf59fc3e
--- /dev/null
+++ b/man2/fsmount.2
@@ -0,0 +1 @@
+.so man2/fsopen.2
diff --git a/man2/fsopen.2 b/man2/fsopen.2
new file mode 100644
index 000000000..1bc761ab4
--- /dev/null
+++ b/man2/fsopen.2
@@ -0,0 +1,357 @@
+'\" t
+.\" Copyright (c) 2018 David Howells <dhowells@redhat.com>
+.\"
+.\" %%%LICENSE_START(VERBATIM)
+.\" Permission is granted to make and distribute verbatim copies of this
+.\" manual provided the copyright notice and this permission notice are
+.\" preserved on all copies.
+.\"
+.\" Permission is granted to copy and distribute modified versions of this
+.\" manual under the conditions for verbatim copying, provided that the
+.\" entire resulting derived work is distributed under the terms of a
+.\" permission notice identical to this one.
+.\"
+.\" Since the Linux kernel and libraries are constantly changing, this
+.\" manual page may be incorrect or out-of-date.  The author(s) assume no
+.\" responsibility for errors or omissions, or for damages resulting from
+.\" the use of the information contained herein.  The author(s) may not
+.\" have taken the same level of care in the production of this manual,
+.\" which is licensed free of charge, as they might when working
+.\" professionally.
+.\"
+.\" Formatted or processed versions of this manual, if unaccompanied by
+.\" the source, must acknowledge the copyright and authors of this work.
+.\" %%%LICENSE_END
+.\"
+.TH FSOPEN 2 2018-06-07 "Linux" "Linux Programmer's Manual"
+.SH NAME
+fsopen, fsmount, fspick \- Handle filesystem (re-)configuration and mounting
+.SH SYNOPSIS
+.nf
+.B #include <sys/types.h>
+.br
+.B #include <sys/mount.h>
+.br
+.B #include <unistd.h>
+.br
+.BR "#include <fcntl.h>           " "/* Definition of AT_* constants */"
+.PP
+.BI "int fsopen(const char *" fsname ", unsigned int " flags );
+.PP
+.BI "int fsmount(int " fd ", unsigned int " flags ", unsigned int " ms_flags );
+.PP
+.BI "int fspick(int " dirfd ", const char *" pathname ", unsigned int " flags );
+.fi
+.PP
+.IR Note :
+There are no glibc wrappers for these system calls.
+.SH DESCRIPTION
+.PP
+.BR fsopen ()
+creates a new filesystem configuration context within the kernel for the
+filesystem named in the
+.I fsname
+parameter and attaches it to a file descriptor, which it then returns.  The
+file descriptor can be marked close-on-exec by setting
+.B FSOPEN_CLOEXEC
+in flags.
+.PP
+The
+file descriptor can then be used to configure the desired filesystem parameters
+and security parameters by using
+.BR write (2)
+to pass parameters to it and then writing a command to actually create the
+filesystem representation.
+.PP
+The file descriptor also serves as a channel by which more comprehensive error,
+warning and information messages may be retrieved from the kernel using
+.BR read (2).
+.PP
+Once the kernel's filesystem representation has been created, it can be queried
+by calling
+.BR fsinfo (2)
+on the file descriptor.  fsinfo() will spot that the target is actually a
+creation context and look inside that.
+.PP
+.BR fsmount ()
+can then be called to create a mount object that refers to the newly created
+filesystem representation, with the propagation and mount restrictions to be
+applied specified in
+.IR ms_flags .
+The mount object is then attached to a new file descriptor that looks like one
+created by
+.BR open "(2) with " O_PATH " or " open_tree (2).
+This can be passed to
+.BR move_mount (2)
+to attach the mount object to a mountpoint, thereby completing the process.
+.PP
+The file descriptor returned by fsmount() is marked close-on-exec if
+FSMOUNT_CLOEXEC is specified in
+.IR flags .
+.PP
+After fsmount() has completed, the context created by fsopen() is reset and
+moved to reconfiguration state, allowing the new superblock to be reconfigured.
+.PP
+.BR fspick ()
+creates a new filesystem context within the kernel, attaches the superblock
+specified by
+.IR dfd ", " pathname ", " flags
+and puts it into the reconfiguration state and attached the context to a new
+file descriptor that can then be parameterised with
+.BR write (2)
+exactly the same as for the context created by fsopen() above.
+.PP
+.I flags
+is an OR'd together mask of
+.B FSPICK_CLOEXEC
+which indicates that the returned file descriptor should be marked
+close-on-exec and
+.BR FSPICK_SYMLINK_NOFOLLOW ", " FSPICK_NO_AUTOMOUNT " and " FSPICK_EMPTY_PATH
+which control the pathwalk to the target object (see below).
+
+.\"________________________________________________________
+.SS Writable Command Interface
+Superblock (re-)configuration is achieved by writing command strings to the
+context file descriptor using
+.BR write (2).
+Each string is prefixed with a specifier indicating the class of command
+being specified.  The available commands include:
+.TP
+\fB"o <option>"\fP
+Specify a filesystem or security parameter.
+.I <option>
+is typically a key or key=val format string.  Since the length of the option is
+given to write(), the option may include any sort of character, including
+spaces and commas or even binary data.
+.TP
+\fB"s <name>"\fP
+Specify a device file, network server or other other source specification.
+This may be optional, depending on the filesystem, and it may be possible to
+provide multiple of them to a filesystem.
+.TP
+\fB"x create"\fP
+End the filesystem configuration phase and try and create a representation in
+the kernel with the parameters specified.  After this, the context is shifted
+to the mount-pending state waiting for an fsmount() call to occur.
+.TP
+\fB"x reconfigure"\fP
+End a filesystem reconfiguration phase try to apply the parameters to the
+filesystem representation.  After this, the context gets reset and put back to
+the start of the reconfiguration phase again.
+.PP
+With this interface, option strings are not limited to 4096 bytes, either
+individually or in sum, and they are also not restricted to text-only options.
+Further, errors may be given individually for each option and not aggregated or
+dumped into the kernel log.
+
+.\"________________________________________________________
+.SS Message Retrieval Interface
+The context file descriptor may be queried for message strings at any time by
+calling
+.BR read (2)
+on the file descriptor.  This will return formatted messages that are prefixed
+to indicate their class:
+.TP
+\fB"e <message>"\fP
+An error message string was logged.
+.TP
+\fB"i <message>"\fP
+An informational message string was logged.
+.TP
+\fB"w <message>"\fP
+An warning message string was logged.
+.PP
+Messages are removed from the queue as they're read.
+
+.\"________________________________________________________
+.SH EXAMPLES
+To illustrate the process, here's an example whereby this can be used to mount
+an ext4 filesystem on /dev/sdb1 onto /mnt.  Note that the example ignores the
+fact that
+.BR write (2)
+has a length parameter and that errors might occur.
+.PP
+.in +4n
+.nf
+sfd = fsopen("ext4", FSOPEN_CLOEXEC);
+write(sfd, "s /dev/sdb1");
+write(sfd, "o noatime");
+write(sfd, "o acl");
+write(sfd, "o user_attr");
+write(sfd, "o iversion");
+write(sfd, "x create");
+fsinfo(sfd, NULL, ...);
+mfd = fsmount(sfd, FSMOUNT_CLOEXEC, MS_RELATIME);
+move_mount(mfd, "", sfd, AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH);
+.fi
+.in
+.PP
+Here, an ext4 context is created first and attached to sfd.  This is then told
+where its source will be, given a bunch of options and created.
+.BR fsinfo (2)
+can then be used to query the filesystem.  Then fsmount() is called to create a
+mount object and
+.BR move_mount (2)
+is called to attach it to its intended mountpoint.
+.PP
+And here's an example of mounting from an NFS server:
+.PP
+.in +4n
+.nf
+sfd = fsopen("nfs", 0);
+write(sfd, "s example.com/pub/linux");
+write(sfd, "o nfsvers=3");
+write(sfd, "o rsize=65536");
+write(sfd, "o wsize=65536");
+write(sfd, "o rdma");
+write(sfd, "x create");
+mfd = fsmount(sfd, 0, MS_NODEV);
+move_mount(mfd, "", sfd, AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH);
+.fi
+.in
+.PP
+Reconfiguration can be achieved by:
+.PP
+.in +4n
+.nf
+sfd = fspick(AT_FDCWD, "/mnt", FSPICK_NO_AUTOMOUNT | FSPICK_CLOEXEC);
+write(sfd, "o ro");
+write(sfd, "x reconfigure");
+.fi
+.in
+.PP
+or:
+.PP
+.in +4n
+.nf
+sfd = fsopen(...);
+...
+mfd = fsmount(sfd, ...);
+...
+write(sfd, "o ro");
+write(sfd, "x reconfigure");
+.fi
+.in
+
+
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success, all three functions return a file descriptor.  On error, \-1 is
+returned, and
+.I errno
+is set appropriately.
+.SH ERRORS
+The error values given below result from filesystem type independent
+errors.
+Each filesystem type may have its own special errors and its
+own special behavior.
+See the Linux kernel source code for details.
+.TP
+.B EACCES
+A component of a path was not searchable.
+(See also
+.BR path_resolution (7).)
+.TP
+.B EACCES
+Mounting a read-only filesystem was attempted without giving the
+.B MS_RDONLY
+flag.
+.TP
+.B EACCES
+The block device
+.I source
+is located on a filesystem mounted with the
+.B MS_NODEV
+option.
+.\" mtk: Probably: write permission is required for MS_BIND, with
+.\" the error EPERM if not present; CAP_DAC_OVERRIDE is required.
+.TP
+.B EBUSY
+.I source
+cannot be reconfigured read-only, because it still holds files open for
+writing.
+.TP
+.B EFAULT
+One of the pointer arguments points outside the user address space.
+.TP
+.B EINVAL
+.I source
+had an invalid superblock.
+.TP
+.B EINVAL
+.I ms_flags
+includes more than one of
+.BR MS_SHARED ,
+.BR MS_PRIVATE ,
+.BR MS_SLAVE ,
+or
+.BR MS_UNBINDABLE .
+.TP
+.BR EINVAL
+An attempt was made to bind mount an unbindable mount.
+.TP
+.B ELOOP
+Too many links encountered during pathname resolution.
+.TP
+.B EMFILE
+The system has too many open files to create more.
+.TP
+.B ENFILE
+The process has too many open files to create more.
+.TP
+.B ENAMETOOLONG
+A pathname was longer than
+.BR MAXPATHLEN .
+.TP
+.B ENODEV
+Filesystem
+.I fsname
+not configured in the kernel.
+.TP
+.B ENOENT
+A pathname was empty or had a nonexistent component.
+.TP
+.B ENOMEM
+The kernel could not allocate sufficient memory to complete the call.
+.TP
+.B ENOTBLK
+.I source
+is not a block device (and a device was required).
+.TP
+.B ENOTDIR
+.IR pathname ,
+or a prefix of
+.IR source ,
+is not a directory.
+.TP
+.B ENXIO
+The major number of the block device
+.I source
+is out of range.
+.TP
+.B EPERM
+The caller does not have the required privileges.
+.SH CONFORMING TO
+These functions are Linux-specific and should not be used in programs intended
+to be portable.
+.SH VERSIONS
+.BR fsopen "(), " fsmount "() and " fspick ()
+were added to Linux in kernel 4.18.
+.SH NOTES
+Glibc does not (yet) provide a wrapper for the
+.BR fsopen "() , " fsmount "() or " fspick "()"
+system calls; call them using
+.BR syscall (2).
+.SH SEE ALSO
+.BR mountpoint (1),
+.BR move_mount (2),
+.BR open_tree (2),
+.BR umount (2),
+.BR mount_namespaces (7),
+.BR path_resolution (7),
+.BR findmnt (8),
+.BR lsblk (8),
+.BR mount (8),
+.BR umount (8)
diff --git a/man2/fspick.2 b/man2/fspick.2
new file mode 100644
index 000000000..2bf59fc3e
--- /dev/null
+++ b/man2/fspick.2
@@ -0,0 +1 @@
+.so man2/fsopen.2

-- 
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Andy Lutomirski <luto@amacapital.net>
Date: 2018-07-11 00:01:07

[cc Jann - you love this stuff]
On Jul 10, 2018, at 3:44 PM, David Howells [off-list ref] wrote:

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);
This is great in principle, but I think you’re seriously playing with fire with the API. 
where flags can be 0 or FSOPEN_CLOEXEC.

For example:

   sfd = fsopen("ext4", FSOPEN_CLOEXEC);
   write(sfd, "s /dev/sdb1"); // note I'm ignoring write's length arg
Imagine some malicious program passes sfd as stdout to a setuid program. That program gets persuaded to write “s /etc/shadow”.  What happens?  You’re okay as long as *every single fs* gets it right, but that’s asking a lot.
   write(sfd, "o noatime");
   write(sfd, "o acl");
   write(sfd, "o user_attr");
   write(sfd, "o iversion");
   write(sfd, "o ");
   write(sfd, "r /my/container"); // root inside the fs
   write(sfd, "x create"); // create the superblock
From cursory inspection of a bunch of the code, I think the expectation is that the actual device access happens in the “x” action. This is not okay. You can’t do this kind of thing in a write() handler, unless you somehow make every single access using f_cred, which is a real pain.

I think the right solution is one of:

(a) Pass a netlink-formatted blob to fsopen() and do the whole thing in one syscall. I don’t mean using netlink sockets — just the nlattr format.  Or you could use a different format. The part that matters is using just one syscall to do the whole thing.

(b) Keep the current structure but use a new syscall instead of write().

(c) Keep using write() but literally just buffer the data. Then have a new syscall to commit it.  In other words, replace “x” with a syscall and call all the fs_context_operations helpers in that context instead of from write().

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2018-07-11 01:07:41

Yeah, Andy is right that we should *not* make "write()" have side effects.

Use it to queue things by all means, but not "do" things. Not unless
there's a very sane security model.

On Tue, Jul 10, 2018 at 4:59 PM Andy Lutomirski [off-list ref] wrote:
I think the right solution is one of:

(a) Pass a netlink-formatted blob to fsopen() and do the whole thing in one syscall. I don’t mean using netlink sockets — just the nlattr format.  Or you could use a different format. The part that matters is using just one syscall to do the whole thing.
Please no. Not another nasty marshalling thing.
(b) Keep the current structure but use a new syscall instead of write().

(c) Keep using write() but literally just buffer the data. Then have a new syscall to commit it.  In other words, replace “x” with a syscall and call all the fs_context_operations helpers in that context instead of from write().
But yeah, b-or-c sounds fine.

               Linus

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Al Viro <viro@ZenIV.linux.org.uk>
Date: 2018-07-11 01:17:08

On Tue, Jul 10, 2018 at 06:05:49PM -0700, Linus Torvalds wrote:
Yeah, Andy is right that we should *not* make "write()" have side effects.

Use it to queue things by all means, but not "do" things. Not unless
there's a very sane security model.

On Tue, Jul 10, 2018 at 4:59 PM Andy Lutomirski [off-list ref] wrote:
quoted
I think the right solution is one of:

(a) Pass a netlink-formatted blob to fsopen() and do the whole thing in one syscall. I don’t mean using netlink sockets — just the nlattr format.  Or you could use a different format. The part that matters is using just one syscall to do the whole thing.
Please no. Not another nasty marshalling thing.
quoted
(b) Keep the current structure but use a new syscall instead of write().

(c) Keep using write() but literally just buffer the data. Then have a new syscall to commit it.  In other words, replace “x” with a syscall and call all the fs_context_operations helpers in that context instead of from write().
But yeah, b-or-c sounds fine.
Umm...  How about "use credentials of opener for everything"?

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Andy Lutomirski <luto@kernel.org>
Date: 2018-07-11 01:35:25

On Tue, Jul 10, 2018 at 6:15 PM, Al Viro [off-list ref] wrote:
On Tue, Jul 10, 2018 at 06:05:49PM -0700, Linus Torvalds wrote:
quoted
Yeah, Andy is right that we should *not* make "write()" have side effects.

Use it to queue things by all means, but not "do" things. Not unless
there's a very sane security model.

On Tue, Jul 10, 2018 at 4:59 PM Andy Lutomirski [off-list ref] wrote:
quoted
I think the right solution is one of:

(a) Pass a netlink-formatted blob to fsopen() and do the whole thing in one syscall. I don’t mean using netlink sockets — just the nlattr format.  Or you could use a different format. The part that matters is using just one syscall to do the whole thing.
Please no. Not another nasty marshalling thing.
quoted
(b) Keep the current structure but use a new syscall instead of write().

(c) Keep using write() but literally just buffer the data. Then have a new syscall to commit it.  In other words, replace “x” with a syscall and call all the fs_context_operations helpers in that context instead of from write().
But yeah, b-or-c sounds fine.
Umm...  How about "use credentials of opener for everything"?
If you want to audit every single filesystem for any code that uses
credentials for anything and add all the right kernel APIs and make
sure the filesystem uses them and somehow keep screwups from getting
added down the line, then okay I guess.  As far as I know, we don't
even *have* an API for "open this device node using this struct cred
*".

I kind of want to add a hack to set some poison bit in current->cred
in sys_write() and clear it on the way out.  Sigh.

--Andy

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: David Howells <dhowells@redhat.com>
Date: 2018-07-11 08:46:34

Andy Lutomirski [off-list ref] wrote:
quoted
Umm...  How about "use credentials of opener for everything"?
If you want to audit every single filesystem for any code that uses
credentials for anything and add all the right kernel APIs and make
sure the filesystem uses them and somehow keep screwups from getting
added down the line, then okay I guess.  As far as I know, we don't
even *have* an API for "open this device node using this struct cred
*".
You can use override_creds() too.

David

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2018-07-11 01:50:32

On Tue, Jul 10, 2018 at 6:15 PM Al Viro [off-list ref] wrote:
Umm...  How about "use credentials of opener for everything"?
yeah, we have that for writes in general.

Nobody ever actually follows that rule. They may *think* they do, and
then they call to some helper that does "capability(CAP_SYS_WHATEVAH)"
without even realizing it.

But I'm certainly ok with writes, if it's just filling a buffer.
Preferably a standard buffer we already have, like a seqfile or pipe
(hey, splice!) or whatever.

And then you have that final op to actually "commit" the state. Which
shouldn't be a write (and not the close).

           Linus

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: David Howells <dhowells@redhat.com>
Date: 2018-07-11 08:45:48

Linus Torvalds [off-list ref] wrote:
Yeah, Andy is right that we should *not* make "write()" have side effects.
Note that write() has side effects all over the place: procfs, sysfs, debugfs,
tracefs, ...  Though for the most part they're single-shot jobs and not
cumulative (I'm not sure this is always true for debugfs - there's a lot of
weird stuff in there).
quoted
(b) Keep the current structure but use a new syscall instead of write().

(c) Keep using write() but literally just buffer the data. Then have a new
syscall to commit it.  In other words, replace “x” with a syscall and call
all the fs_context_operations helpers in that context instead of from
write().
But yeah, b-or-c sounds fine.
I would prefer to avoid the "let's buffer everything" but rather parse the
data as we go along.  What I currently do is store the parsed data in the
context and only actually *apply* it when someone sends the 'x' command.

There are two reasons for this:

 (1) mount()'s error handling is slight: it can only return an error code, but
     creating and mounting something has so many different and interesting
     ways of going wrong and I want to be able to give better error reporting.

     This gets more interesting if it happens inside a container where you
     can't see dmesg.

 (2) Parsing the data means you only need to store the result of the parse and
     can reject anything that's unknown or contradictory.

     Buffering till the end means you have to buffer *everything* - and,
     unless you limit your buffer, you risk running out of RAM.

Now, I can replace the 'x' command with an ioctl() so that just writing random
rubbish to the fd won't cause anything to actually happen.

	fd = fsopen("ext4");
	write(fd, "s /dev/sda1");
	write(fd, "o user_xattr");
	ioctl(fd, FSOPEN_IOC_CREATE_SB, 0);

or I could make a special syscall for it:

	fscommit(fd, FSCOMMIT_CREATE);

or:

	fscommit(fd, FSCOMMIT_RECONFIGURE);

and require that you have CAP_SYS_ADMIN to enact it.

David

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2018-07-11 16:08:22

On Wed, Jul 11, 2018 at 1:42 AM David Howells [off-list ref] wrote:
     Buffering till the end means you have to buffer *everything* - and,
     unless you limit your buffer, you risk running out of RAM
Do we really care?

Can't we limit the buffer size to something small?

Right now, the mount options can't be bigger than a page anyway. Why
would we want to extend on that?

Btw, the magic word here is "why". I really really want to see a
fairly exhaustive explanation of why this all is such a big deal, and
exactly what limitations (including perhaps the mount option buffer
size) are such a pain right now and need changing.
Now, I can replace the 'x' command with an ioctl() so that just writing random
rubbish to the fd won't cause anything to actually happen.

        fd = fsopen("ext4");
        write(fd, "s /dev/sda1");
        write(fd, "o user_xattr");
        ioctl(fd, FSOPEN_IOC_CREATE_SB, 0);

or I could make a special syscall for it:

        fscommit(fd, FSCOMMIT_CREATE);

or:

        fscommit(fd, FSCOMMIT_RECONFIGURE);

and require that you have CAP_SYS_ADMIN to enact it.
I think any of them sound fairly ok, with that whole "we need reasons" caveat.

               Linus

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Jann Horn <jannh@google.com>
Date: 2018-07-11 01:16:20

On Tue, Jul 10, 2018 at 4:59 PM Andy Lutomirski [off-list ref] wrote:
[cc Jann - you love this stuff]
quoted
On Jul 10, 2018, at 3:44 PM, David Howells [off-list ref] wrote:

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);
This is great in principle, but I think you’re seriously playing with fire with the API.
quoted
where flags can be 0 or FSOPEN_CLOEXEC.

For example:

   sfd = fsopen("ext4", FSOPEN_CLOEXEC);
   write(sfd, "s /dev/sdb1"); // note I'm ignoring write's length arg
Imagine some malicious program passes sfd as stdout to a setuid program. That program gets persuaded to write “s /etc/shadow”.  What happens?  You’re okay as long as *every single fs* gets it right, but that’s asking a lot.
quoted
   write(sfd, "o noatime");
   write(sfd, "o acl");
   write(sfd, "o user_attr");
   write(sfd, "o iversion");
   write(sfd, "o ");
   write(sfd, "r /my/container"); // root inside the fs
   write(sfd, "x create"); // create the superblock
From cursory inspection of a bunch of the code, I think the expectation is that the actual device access happens in the “x” action. This is not okay. You can’t do this kind of thing in a write() handler, unless you somehow make every single access using f_cred, which is a real pain.

I think the right solution is one of:

(a) Pass a netlink-formatted blob to fsopen() and do the whole thing in one syscall. I don’t mean using netlink sockets — just the nlattr format.  Or you could use a different format. The part that matters is using just one syscall to do the whole thing.

(b) Keep the current structure but use a new syscall instead of write().

(c) Keep using write() but literally just buffer the data. Then have a new syscall to commit it.  In other words, replace “x” with a syscall and call all the fs_context_operations helpers in that context instead of from write().
I also love ioctls, so I think you could also use an ioctl to do the
commit? You can do anything (well, almost anything) that you can do in
syscall context in ioctl context, too; and when you already have a
file descriptor of a specific type that you want to perform an
operation on, an ioctl works just fine.

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Al Viro <viro@ZenIV.linux.org.uk>
Date: 2018-07-11 01:17:56

On Tue, Jul 10, 2018 at 06:14:10PM -0700, Jann Horn wrote:
I also love ioctls, so I think you could also use an ioctl to do the
commit? You can do anything (well, almost anything) that you can do in
syscall context in ioctl context, too; and when you already have a
file descriptor of a specific type that you want to perform an
operation on, an ioctl works just fine.
Poe's Law in action...

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: David Howells <dhowells@redhat.com>
Date: 2018-07-11 07:25:35

Andy Lutomirski [off-list ref] wrote:
quoted
   sfd = fsopen("ext4", FSOPEN_CLOEXEC);
   write(sfd, "s /dev/sdb1"); // note I'm ignoring write's length arg
Imagine some malicious program passes sfd as stdout to a setuid
program. That program gets persuaded to write "s /etc/shadow".  What
happens?  You’re okay as long as *every single fs* gets it right, but that’s
asking a lot.
Do note that you must already have CAP_SYS_ADMIN to be able to call fsopen().

David

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Eric Biggers <hidden>
Date: 2018-07-11 16:38:35

On Wed, Jul 11, 2018 at 08:22:41AM +0100, David Howells wrote:
Andy Lutomirski [off-list ref] wrote:
quoted
quoted
   sfd = fsopen("ext4", FSOPEN_CLOEXEC);
   write(sfd, "s /dev/sdb1"); // note I'm ignoring write's length arg
Imagine some malicious program passes sfd as stdout to a setuid
program. That program gets persuaded to write "s /etc/shadow".  What
happens?  You’re okay as long as *every single fs* gets it right, but that’s
asking a lot.
Do note that you must already have CAP_SYS_ADMIN to be able to call fsopen().

David
Not really, by default an unprivileged user can still do:

	unshare(CLONE_NEWUSER|CLONE_NEWNS);
	syscall(__NR_fsopen, "ext4", 0);

- Eric

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Andy Lutomirski <luto@kernel.org>
Date: 2018-07-11 17:12:17

On Jul 11, 2018, at 12:22 AM, David Howells [off-list ref] wrote:

Andy Lutomirski [off-list ref] wrote:
quoted
quoted
  sfd = fsopen("ext4", FSOPEN_CLOEXEC);
  write(sfd, "s /dev/sdb1"); // note I'm ignoring write's length arg
Imagine some malicious program passes sfd as stdout to a setuid
program. That program gets persuaded to write "s /etc/shadow".  What
happens?  You’re okay as long as *every single fs* gets it right, but that’s
asking a lot.
Do note that you must already have CAP_SYS_ADMIN to be able to call fsopen().
If you’re not allowing it already, someone will want user namespace
root to be able to use this very, very soon.

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: David Howells <dhowells@redhat.com>
Date: 2018-07-12 15:04:01

Andy Lutomirski [off-list ref] wrote:
quoted
On Jul 11, 2018, at 12:22 AM, David Howells [off-list ref] wrote:

Andy Lutomirski [off-list ref] wrote:
quoted
quoted
  sfd = fsopen("ext4", FSOPEN_CLOEXEC);
  write(sfd, "s /dev/sdb1"); // note I'm ignoring write's length arg
Imagine some malicious program passes sfd as stdout to a setuid
program. That program gets persuaded to write "s /etc/shadow".  What
happens?  You’re okay as long as *every single fs* gets it right, but
that’s asking a lot.
Do note that you must already have CAP_SYS_ADMIN to be able to call
fsopen().
If you're not allowing it already, someone will want user namespace
root to be able to use this very, very soon.
Yeah, I'm sure.  And I've been thinking on how to deal with it.

I think we *have* to open the source files/devices with the creds of whoever
called fsopen() or fspick() - that way you can't upgrade your privs by passing
your context fd to a suid program.  To enforce this, I think it's simplest for
fscontext_write() to call override_creds() right after taking the uapi_mutex
and then call revert_creds() right before dropping the mutex.

Another thing we might want to look at is to allow a supervisory process to
examine the context before permitting the create/reconfigure action to
proceed.  It might also be possible to do this through the LSM.

David

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2018-07-12 15:50:46

On Thu, Jul 12, 2018 at 7:54 AM David Howells [off-list ref] wrote:
I think we *have* to open the source files/devices with the creds of whoever
called fsopen() or fspick() - that way you can't upgrade your privs by passing
your context fd to a suid program.  To enforce this, I think it's simplest for
fscontext_write() to call override_creds() right after taking the uapi_mutex
and then call revert_creds() right before dropping the mutex.
No.

Don't play games with override_creds. It's wrong.

You have to use file->f_creds - no games, no garbage.

But "write()" simply is *NOT* a good "command" interface. If you want
to send a command, use an ioctl or a system call.

Because it's not just about credentials. It's not just about fooling a
suid app into writing an error message to a descriptor you wrote. It's
also about things like "splice()", which can write to your target
using a kernel buffer, and thus trick you into doing a command while
we have the context set to kernel addresses.

Are we trying to get away from that issue? Yes. But it's just another
example of why "write()" IS NOT TO BE USED FOR COMMANDS.

Only use write() for data.

That's final. We're not adding yet another clueless fuck-up of an
interface just because people cannot understand this very simple rule:
"write()" is for data, not for commands.

No more excuses.

                 Linus

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Al Viro <viro@ZenIV.linux.org.uk>
Date: 2018-07-12 16:00:31

On Thu, Jul 12, 2018 at 08:50:46AM -0700, Linus Torvalds wrote:
But "write()" simply is *NOT* a good "command" interface. If you want
to send a command, use an ioctl or a system call.

Because it's not just about credentials. It's not just about fooling a
suid app into writing an error message to a descriptor you wrote. It's
also about things like "splice()", which can write to your target
using a kernel buffer, and thus trick you into doing a command while
we have the context set to kernel addresses.
Wait a sec - that's only a problem if your command contains pointer-chasing
et.al.  Which is why e.g. /dev/sg is fucked in head.  But for something that
is plain text, what's the problem with splice/write/sendmsg/whatever?

I'm not talking about this particular interface, but "write is bad for
commands" as general policy looks missing the point.  If anything, it's
pointer-chasing crap that should be banned everywhere.  Just look at SG_IO -
it's a ioctl, and it's absolute garbage...

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2018-07-12 16:17:59

On Thu, Jul 12, 2018 at 9:00 AM Al Viro [off-list ref] wrote:
Wait a sec - that's only a problem if your command contains pointer-chasing
et.al.
No.

It's a problem if anybody ever does something like "let's have a
helper splice thread that uses splice to move data automatically from
one buffer to another".

And yes, it's something people have wanted.

Seriously. I'm putting my foot down. NO COMMANDS IN WRITE DATA!

We have made that mistake in the past. Having done stupid things in
the past is not an excuse for doing so again. Quite the reverse.
Making the same mistake and not learning from your mistakes is the
sign of stupidity.

So I repeat: write is for data. If you want an action, you do it with
ioctl, or you do it with a system call.

              Linus

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Al Viro <viro@ZenIV.linux.org.uk>
Date: 2018-07-12 16:41:28

On Thu, Jul 12, 2018 at 09:07:36AM -0700, Linus Torvalds wrote:
On Thu, Jul 12, 2018 at 9:00 AM Al Viro [off-list ref] wrote:
quoted
Wait a sec - that's only a problem if your command contains pointer-chasing
et.al.
No.

It's a problem if anybody ever does something like "let's have a
helper splice thread that uses splice to move data automatically from
one buffer to another".

And yes, it's something people have wanted.

Seriously. I'm putting my foot down. NO COMMANDS IN WRITE DATA!

We have made that mistake in the past. Having done stupid things in
the past is not an excuse for doing so again. Quite the reverse.
Making the same mistake and not learning from your mistakes is the
sign of stupidity.

So I repeat: write is for data. If you want an action, you do it with
ioctl, or you do it with a system call.
*shrug*

I think you are wrong[1], but it's your decision.  And seriously, ioctl?
_That_ has a great track record...

[1] one man's data is another man's commands, for starters.  All networking
protocols would fit your description.  So would ANSI escape sequences ("move
cursor to line 12 column 45" does sound like a command), so would writing
postscript to printer, etc.

IME it's more about data structures that are not marshalled cleanly - that
tends to go badly wrong.  Again, see SG_IO for recent example...

Anyway, your tree, your policy.

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2018-07-12 16:50:01

On Thu, Jul 12, 2018 at 9:31 AM Al Viro [off-list ref] wrote:
And seriously, ioctl? _That_ has a great track record...
I agree that a system call is likely saner. Especially since we'd have
one to _start_ this (ie "fsopen()") it would make sense to have the
one to finalize it.
[1] one man's data is another man's commands, for starters.  All networking
protocols would fit your description.  So would ANSI escape sequences ("move
cursor to line 12 column 45" does sound like a command), so would writing
postscript to printer, etc.
.. and all of that is just data to the kernel.

Yes, vt100 escape sequences etc _are_ commands, and boy have we had
bugs in that area. But there the excuse is "that's how the world is".

The thing is, "reality" is the ultimate argument. You can't argue with
cold hard facts.

But when designing a new interface that doesn't have that kind of
constraints, do it right.
IME it's more about data structures that are not marshalled cleanly - that
tends to go badly wrong.  Again, see SG_IO for recent example...
SG_IO actually gets it right. It doesn't do async, but that's part of
the design (and a big part of why it's a lot simpler - the read-write
thing is actually broken too and just forces user space to basically
know SCSI).

              Linus

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2018-07-12 17:14:05

On Thu, Jul 12, 2018 at 9:39 AM Linus Torvalds
[off-list ref] wrote:
I agree that a system call is likely saner. Especially since we'd have
one to _start_ this (ie "fsopen()") it would make sense to have the
one to finalize it.
Side note: if we can make do with just a buffer, then we wouldn't need
"fsopen()". You could literally just open a pipe, and write to it.
It's got 16 pages worth of buffers by default, and you can increase it
(within reason) as root.

Of course, depending on IO patterns, not all the buffer pages are
necessarily fully used, so it's not like you get a buffer of size
PAGE_SIZE*16, but we do merge buffers so you should be fairly close.

Then you really could do without a fsopen(). Just fill a pipe with
data, and do "fsmount()" on the pipe contents.

Added upside? You can use "iov_iter_pipe()" to iterate over all that data.

I'm only half joking.

            Linus

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Al Viro <viro@ZenIV.linux.org.uk>
Date: 2018-07-12 17:54:42

On Thu, Jul 12, 2018 at 10:14:05AM -0700, Linus Torvalds wrote:
On Thu, Jul 12, 2018 at 9:39 AM Linus Torvalds
[off-list ref] wrote:
quoted
I agree that a system call is likely saner. Especially since we'd have
one to _start_ this (ie "fsopen()") it would make sense to have the
one to finalize it.
Side note: if we can make do with just a buffer, then we wouldn't need
"fsopen()". You could literally just open a pipe, and write to it.
It's got 16 pages worth of buffers by default, and you can increase it
(within reason) as root.

Of course, depending on IO patterns, not all the buffer pages are
necessarily fully used, so it's not like you get a buffer of size
PAGE_SIZE*16, but we do merge buffers so you should be fairly close.

Then you really could do without a fsopen(). Just fill a pipe with
data, and do "fsmount()" on the pipe contents.

Added upside? You can use "iov_iter_pipe()" to iterate over all that data.

I'm only half joking.
One semi-historical note here.

Originally, mount(2) (and it had been there since v1) had only one filesystem
type to deal with.  So it was really just "mount <block device pathname> on
<mountpoint pathname>, read-only or read-write".  3 arguments, two strings and
one flag (flag, BTW, was a later addition).

It didn't last.  I can dig out the archaeological notes and cut'n'paste the
whole horror story here, but that'll be way too long and scary.

By 4.2BSD times there had been essentially an enum encoding the filesystem
type and type-tagged union of structs with type-dependent options.  Plus
some options taking more bits in what used to be "is it r/w?" flag.

Leaving aside the whole "mount new/bind/remount/etc." overloading we have
in mount(2) today, we have a bunch of named filesystems, each with its
own set of options.  Device name has ceased to be something special for
many decades; the type name is what's universally present and that's what
decides how the rest (including "device name") is to be interpreted.

Fundamentally, we start with selecting (by name) a filesystem driver we'll
be talking to.  The rest (device name + string options + flags like noexec
that are not handled on VFS level) is given to that driver, which either
tells us to take a hike or gives us a dentry tree that can be attached.

Separating type name from everything else makes a lot of sense, simply
because it's what determines the parsing and interpretation of the rest.
Speaking of half-joking, I suggested AF_FSTYPE at some point.  Then
fsopen(2) would be connect(2)...

I think that having that (connection used to talk to fs driver, with or
without an already set up fs instance we are talking about) as first-class
object makes sense.  That's completely unrelated to the question of buffering,
of course.

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2018-07-12 18:04:51

On Thu, Jul 12, 2018 at 10:44 AM Al Viro [off-list ref] wrote:
Separating type name from everything else makes a lot of sense
I do not dispute that at all.

But you can specify the type name in the "commit" phase, it doesn't
have to be at "fsopen" time.

In fact, doing so would _force_ a certain cleanliness to the
interfaces - it would force the rest to be filesystem-agnostic, rather
than possibly have semantic hacks for some part.

            Linus

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Al Viro <viro@ZenIV.linux.org.uk>
Date: 2018-07-12 18:02:45

On Thu, Jul 12, 2018 at 09:39:31AM -0700, Linus Torvalds wrote:
quoted
[1] one man's data is another man's commands, for starters.  All networking
protocols would fit your description.  So would ANSI escape sequences ("move
cursor to line 12 column 45" does sound like a command), so would writing
postscript to printer, etc.
.. and all of that is just data to the kernel.

Yes, vt100 escape sequences etc _are_ commands, and boy have we had
bugs in that area. But there the excuse is "that's how the world is".
... along with "something similar to ncurses-based programs usable over
ssh is a good thing to have, without having said ssh somehow intercept
and marshal ioctls" ;-)  I can just imagine something e.g. RDMA people
would've designed instead... OTOH, I'm eating right now, so better
not go there...

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: David Howells <dhowells@redhat.com>
Date: 2018-07-12 20:34:23

Linus Torvalds [off-list ref] wrote:
Don't play games with override_creds. It's wrong.

You have to use file->f_creds - no games, no garbage.
You missed the point.

It's all very well to say "use file->f_creds".  The problem is this has to be
handed down all the way through the filesystem and down into the block layer
as appropriate to anywhere there's an LSM call, a CAP_* check or a pathwalk -
but there's not currently any way to do that.

mount_bdev() and blkdev_get_by_path() are examples of this.  At the moment
there is no cred parameter there.  We'd also have to pass the creds down into
path_init() to store in struct nameidata and make sure that every permissions
call that might be invoked during pathwalk in every filesystem uses that, not
current_cred().

I made an attempt to do this a while ago and the patch got rather large before
I gave up.  In many ways, it's what we *should* do, but so many things need an
extra parameter...  If you really want, I can try that again.  It's possible I
can automate it with some perl scripting to parse the error messages from the
compiler.

My suggestion was to use override_creds() to impose the appropriate creds at
the top, be that file->f_creds or fs_context->creds (they would be the same in
any case).

If we want to go down the pass-the-creds-down route, then we can temporarily
do override_creds() until we've made the changes and then remove it later.
But "write()" simply is *NOT* a good "command" interface. If you want
to send a command, use an ioctl or a system call.
Okay.
Because it's not just about credentials. It's not just about fooling a
suid app into writing an error message to a descriptor you wrote. It's
also about things like "splice()", which can write to your target
using a kernel buffer, and thus trick you into doing a command while
we have the context set to kernel addresses.

Are we trying to get away from that issue? Yes. But it's just another
example of why "write()" IS NOT TO BE USED FOR COMMANDS.
Btw, do we protect sysfs, debugfs, tracefs, procfs, etc. writes against
splice?  Some of the things in debugfs are really icky, allowing you to muck
directly with hardware.

David

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Andy Lutomirski <luto@amacapital.net>
Date: 2018-07-12 20:25:58

On Jul 12, 2018, at 1:23 PM, David Howells [off-list ref] wrote:

Linus Torvalds [off-list ref] wrote:
quoted
Don't play games with override_creds. It's wrong.

You have to use file->f_creds - no games, no garbage.
You missed the point.
My suggestion was to use override_creds() to impose the appropriate creds at
the top, be that file->f_creds or fs_context->creds (they would be the same in
any case).
I think it should be a new syscall and use current’s creds. No override needed.

Btw, do we protect sysfs, debugfs, tracefs, procfs, etc. writes against
splice?  Some of the things in debugfs are really icky, allowing you to muck
directly with hardware.
We try. It has been a perennial source of severe bugs.

This is part of why I’d like to see splice() be an opt in. Also, it’s a major step toward getting rid of set_fs().

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2018-07-12 20:46:06

On Thu, Jul 12, 2018 at 1:23 PM David Howells [off-list ref] wrote:
It's all very well to say "use file->f_creds".  The problem is this has to be
handed down all the way through the filesystem and down into the block layer
as appropriate to anywhere there's an LSM call, a CAP_* check or a pathwalk -
but there's not currently any way to do that.
.. and the reason is simple: you damn well shouldn't do that.

The unix semantics are that credentials are checked at open time.

If your interface involves checking credentials at write() time, your
interface is garbage shit.

Really.

This is the whole "write() is only for data". If you ever have
credentials mattering at write time, you're doing something wrong.

Really really.

Don't do it.

             Linus

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2018-07-12 20:47:47

On Thu, Jul 12, 2018 at 1:34 PM Linus Torvalds
[off-list ref] wrote:
This is the whole "write() is only for data". If you ever have
credentials mattering at write time, you're doing something wrong.

Really really.

Don't do it.
.. and I'd like to repeat: we *have* done things wrong. But that's
simply not an excuse. We've done it wrong in SCSI, we've done it wrong
in various /proc files, we've done it wrong in many places.

But let's not do it wrong AGAIN.

                Linus

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: David Howells <dhowells@redhat.com>
Date: 2018-07-12 21:26:37

Linus Torvalds [off-list ref] wrote:
The unix semantics are that credentials are checked at open time.
Sigh.

The problem is that there's more than one actual "open" involved.

	fd = fsopen("ext4");				<--- #1
	whatever_interface(fd, "s /dev/sda1");
	whatever_interface(fd, "o journal_path=/dev/sda2");
	do_the_create_thing(fd);			<--- #2 and #3

The initial check to see whether you can mount or not is done at #1.

But later there are two nested file opens.  Internally, deep down inside the
block layer, /dev/sda1 and /dev/sda2 are opened and further permissions checks
are done, whether you like it or not.  But these have no access to the creds
attached to fd as things currently stand.

So we have three choices:

 (1) Pass the creds from ->get_tree() all the way down into pathwalk and make
     sure *every* check that pathwalk does uses it.

 (2) When do_the_create_thing() is invoked, it wraps the call to ->get_tree()
     with override_creds(file->f_cred).

 (3) Forget using an fd to refer to the context.  fsopen() takes absolutely
     everything, perhaps as a kv array and spits out an O_PATH fd.  You don't
     get improved error reporting, you don't get a chance for interaction -
     say with the server, to construct an ID mapping table - and you don't get
     the chance to query the superblock before creating a mount.

     So, something like:

	struct fsopen_param {
		unsigned int type,
		const char *key;
		const void *val;
		unsigned int val_len;
	};

	mfd = fsopen(const char *fs_type,
		     unsigned int flags, /* CLOEXEC */
		     const struct fsopen_param *params,
		     unsigned int param_count,
		     unsigned int ms_flags /* eg. MNT_NOEXEC */);

     For example:

	struct fsopen_param params[] = {
		{ fsopen_source, "dev.fs", "/dev/sda1" }
		{ fsopen_source, "dev.journal", "/dev/sda2" }
		{ fsopen_option, "user_xattr" }
		{ fsopen_option, "data", "journal" }
		{ fsopen_option, "jqfmt", "vfsv1" }
		{ fsopen_security, "selinux.context", "unconfined_u..." }
	};

	mfd = fsopen("ext4", FSOPEN_CLOEXEC, params, ARRAY_SIZE(params),
		     MNT_NOEXEC);

     There would need to be an fsreconfig() also in a similar vein.

David

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2018-07-12 21:52:27

On Thu, Jul 12, 2018 at 2:26 PM David Howells [off-list ref] wrote:
The problem is that there's more than one actual "open" involved.
No. The problem is "write()".

This is not about open, about fsopen, or about anything at all.

This is about the fact that "write()" by definition can happen in a
different - and unexpected - context. Whether that be due to suid or
due to splice, or due to any other random issue is entirely
immaterial.

(The same is true of "read()" too, but very few people try to make
"read()" have side effects, so it's less of an issue. It does happen,
though).

But once you have another interface than "read/write()", the issues go
away. Those other interfaces are synchronous, and now you can decide
"ok, I'll just use current creds".
 (1) Pass the creds from ->get_tree() all the way down into pathwalk and make
     sure *every* check that pathwalk does uses it.
No. See above.

If your write() does anything but buffering data, it's not getting merged.
 (2) When do_the_create_thing() is invoked, it wraps the call to ->get_tree()
     with override_creds(file->f_cred).
No.

We do not wrap creds in any case. It's just asking for *another* kind
of security issue, where you fool some higher-security thing into
giving you access because it wrapped the higher-security case instead.
 (3) Forget using an fd to refer to the context.  fsopen() takes absolutely
     everything, perhaps as a kv array and spits out an O_PATH fd.
That works.

Or you know - do what I told you to do ALL THE TIME, which was to not
use write(), or to only buffer things with write().

But yes, any option that simply avoids read and write is fine.

You can even have a file descriptor. We already have file descriptors
that cannot be read from or written to. It's quite common for special
devices, the whole "open /dev/floppy with O_NONBLOCK only to be able
to do control operations with it" goes back to pretty much day #1.

More recently, we have the whole "FMODE_PATH" kind of file descriptor,
which works as a directory entry, but not for read and write.

So file descriptors can have very useful properties.

But no. We do not use "write()" to implement actions. If you think you
need to check permissions and think you need a "cred", then you're not
using write(). It really is that simple.

Not using write just avouds *all* the problems. If you can fool a suid
application to do arbitrary system calls for you, then it's not the
system call that is the security problem.

                Linus

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: "Theodore Y. Ts'o" <tytso@mit.edu>
Date: 2018-07-12 22:44:06

On Thu, Jul 12, 2018 at 10:26:37PM +0100, David Howells wrote:
The problem is that there's more than one actual "open" involved.

	fd = fsopen("ext4");				<--- #1
	whatever_interface(fd, "s /dev/sda1");
	whatever_interface(fd, "o journal_path=/dev/sda2");
	do_the_create_thing(fd);			<--- #2 and #3

The initial check to see whether you can mount or not is done at #1.

But later there are two nested file opens.  Internally, deep down inside the
block layer, /dev/sda1 and /dev/sda2 are opened and further permissions checks
are done, whether you like it or not.  But these have no access to the creds
attached to fd as things currently stand.
So maybe the answer is that you open /dev/sda1 and /dev/sda2 and then
pass the file descriptors to the fsopen object?  We can require that
the fd's be opened with O_RDWR and O_EXCL, which has the benefit where
if you have multiple block devices, you know *which* block device had
a problem with being grabbed for an exclusive open.

Just a thought.

						- Ted

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: David Howells <dhowells@redhat.com>
Date: 2018-07-12 23:06:26

Theodore Y. Ts'o [off-list ref] wrote:
So maybe the answer is that you open /dev/sda1 and /dev/sda2 and then
pass the file descriptors to the fsopen object?  We can require that
the fd's be opened with O_RDWR and O_EXCL, which has the benefit where
if you have multiple block devices, you know *which* block device had
a problem with being grabbed for an exclusive open.
Would that mean then that doing:

	mount /dev/sda3 /a
	mount /dev/sda3 /b

would then fail on the second command because /dev/sda3 is already open
exclusively?

David

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Andy Lutomirski <luto@amacapital.net>
Date: 2018-07-12 23:21:35

On Jul 12, 2018, at 3:54 PM, David Howells [off-list ref] wrote:

Theodore Y. Ts'o [off-list ref] wrote:
quoted
So maybe the answer is that you open /dev/sda1 and /dev/sda2 and then
pass the file descriptors to the fsopen object?  We can require that
the fd's be opened with O_RDWR and O_EXCL, which has the benefit where
if you have multiple block devices, you know *which* block device had
a problem with being grabbed for an exclusive open.
Would that mean then that doing:

   mount /dev/sda3 /a
   mount /dev/sda3 /b

would then fail on the second command because /dev/sda3 is already open
exclusively?
I tend to think that this *should* fail using the new API.  The semantics of the second mount request are bizarre at best.

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: David Howells <dhowells@redhat.com>
Date: 2018-07-12 23:47:51

Andy Lutomirski [off-list ref] wrote:
I tend to think that this *should* fail using the new API.  The semantics of
the second mount request are bizarre at best.
You still have to support existing behaviour lest you break userspace.

David

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Andy Lutomirski <luto@amacapital.net>
Date: 2018-07-12 23:50:13

On Jul 12, 2018, at 4:35 PM, David Howells [off-list ref] wrote:

Andy Lutomirski [off-list ref] wrote:
quoted
I tend to think that this *should* fail using the new API.  The semantics of
the second mount request are bizarre at best.
You still have to support existing behaviour lest you break userspace.
I assume the existing behavior is that a bind mount is created?  If so, the new mount(8) tool could do it in user code.

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: David Howells <dhowells@redhat.com>
Date: 2018-07-13 00:15:08

Andy Lutomirski [off-list ref] wrote:
quoted
quoted
I tend to think that this *should* fail using the new API.  The semantics
of the second mount request are bizarre at best.
You still have to support existing behaviour lest you break userspace.
I assume the existing behavior is that a bind mount is created?  If so, the
new mount(8) tool could do it in user code.
You have a race there.

Also you can't currently directly create a bind mount from userspace as you
can only bind from another path point - which you may not be able to access
(either by permission failure or because it's not in your mount namespace).

David

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Andy Lutomirski <luto@amacapital.net>
Date: 2018-07-13 00:36:40

On Jul 12, 2018, at 5:03 PM, David Howells [off-list ref] wrote:

Andy Lutomirski [off-list ref] wrote:
quoted
quoted
quoted
I tend to think that this *should* fail using the new API.  The semantics
of the second mount request are bizarre at best.
You still have to support existing behaviour lest you break userspace.
I assume the existing behavior is that a bind mount is created?  If so, the
new mount(8) tool could do it in user code.
You have a race there.

Also you can't currently directly create a bind mount from userspace as you
can only bind from another path point - which you may not be able to access
(either by permission failure or because it's not in your mount namespace).
Are you trying to preserve the magic bind semantics with the new API?  If you are, I think it should be by explicit opt in only. Otherwise you risk having your shiny new way to specify fs options get ignored when the magic bind mount happens. 

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: David Howells <dhowells@redhat.com>
Date: 2018-07-13 07:43:49

Andy Lutomirski [off-list ref] wrote:
quoted
Also you can't currently directly create a bind mount from userspace as you
can only bind from another path point - which you may not be able to access
(either by permission failure or because it's not in your mount namespace).
Are you trying to preserve the magic bind semantics with the new API?
No, I'm pointing out that you can't emulate this by doing a bind mount from
userspace if you can't access the thing you're binding from.

Now, we could create a syscall that just picks up an extant superblock using a
device and attaches it to a mount for you, but that would have to be at least
partially parameterised - which would be very fs-dependent - so that it can
know whether or not you're allowed to create another mount to that sb.

What you're talking about is emulating sget() in userspace - when we have to
do it in the kernel anyway if we still offer mount(2).

David

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Jann Horn <jannh@google.com>
Date: 2018-07-12 23:36:10

On Thu, Jul 12, 2018 at 3:54 PM David Howells [off-list ref] wrote:
Theodore Y. Ts'o [off-list ref] wrote:
quoted
So maybe the answer is that you open /dev/sda1 and /dev/sda2 and then
pass the file descriptors to the fsopen object?  We can require that
the fd's be opened with O_RDWR and O_EXCL, which has the benefit where
if you have multiple block devices, you know *which* block device had
a problem with being grabbed for an exclusive open.
Would that mean then that doing:

        mount /dev/sda3 /a
        mount /dev/sda3 /b

would then fail on the second command because /dev/sda3 is already open
exclusively?
Not exactly. mount_bdev() uses FMODE_EXCL, which locks out parallel
usage *with a different filesystem type*. This is the effect:

# strace -e trace=mount mount -t vfat /dev/loop0 mount
mount("/dev/loop0", "/home/jannh/tmp/x/mount", "vfat", MS_MGC_VAL, NULL) = 0
+++ exited with 0 +++
# strace -e trace=mount mount -t ext4 /dev/loop0 mount
mount("/dev/loop0", "/home/jannh/tmp/x/mount", "ext4", MS_MGC_VAL,
NULL) = -1 EBUSY (Device or resource busy)
mount: /home/jannh/tmp/x/mount: /dev/loop0 already mounted on
/home/jannh/tmp/x/mount.
+++ exited with 32 +++
I don't really understand why it's not more strict though...

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Jann Horn <jannh@google.com>
Date: 2018-07-12 23:45:55

On Thu, Jul 12, 2018 at 4:23 PM Jann Horn [off-list ref] wrote:
quoted hunk
On Thu, Jul 12, 2018 at 3:54 PM David Howells [off-list ref] wrote:
quoted
Theodore Y. Ts'o [off-list ref] wrote:
quoted
So maybe the answer is that you open /dev/sda1 and /dev/sda2 and then
pass the file descriptors to the fsopen object?  We can require that
the fd's be opened with O_RDWR and O_EXCL, which has the benefit where
if you have multiple block devices, you know *which* block device had
a problem with being grabbed for an exclusive open.
Would that mean then that doing:

        mount /dev/sda3 /a
        mount /dev/sda3 /b

would then fail on the second command because /dev/sda3 is already open
exclusively?
Not exactly. mount_bdev() uses FMODE_EXCL, which locks out parallel
usage *with a different filesystem type*. This is the effect:

# strace -e trace=mount mount -t vfat /dev/loop0 mount
mount("/dev/loop0", "/home/jannh/tmp/x/mount", "vfat", MS_MGC_VAL, NULL) = 0
+++ exited with 0 +++
# strace -e trace=mount mount -t ext4 /dev/loop0 mount
mount("/dev/loop0", "/home/jannh/tmp/x/mount", "ext4", MS_MGC_VAL,
NULL) = -1 EBUSY (Device or resource busy)
mount: /home/jannh/tmp/x/mount: /dev/loop0 already mounted on
/home/jannh/tmp/x/mount.
+++ exited with 32 +++
I don't really understand why it's not more strict though...
Er, sorry, of course that's the current behavior, not the behavior of
the suggested API.

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: "Theodore Y. Ts'o" <tytso@mit.edu>
Date: 2018-07-13 02:48:26

On Thu, Jul 12, 2018 at 11:54:41PM +0100, David Howells wrote:
Would that mean then that doing:

	mount /dev/sda3 /a
	mount /dev/sda3 /b

would then fail on the second command because /dev/sda3 is already open
exclusively?
Good point.  One workaround would be to require an open with O_PATH instead.

     	     	 	    	     	- Ted

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Andy Lutomirski <luto@amacapital.net>
Date: 2018-07-12 16:33:40

On Jul 12, 2018, at 7:54 AM, David Howells [off-list ref] wrote:

Andy Lutomirski [off-list ref] wrote:
quoted
quoted
On Jul 11, 2018, at 12:22 AM, David Howells [off-list ref] wrote:

Andy Lutomirski [off-list ref] wrote:
quoted
quoted
 sfd = fsopen("ext4", FSOPEN_CLOEXEC);
 write(sfd, "s /dev/sdb1"); // note I'm ignoring write's length arg
Imagine some malicious program passes sfd as stdout to a setuid
program. That program gets persuaded to write "s /etc/shadow".  What
happens?  You’re okay as long as *every single fs* gets it right, but
that’s asking a lot.
Do note that you must already have CAP_SYS_ADMIN to be able to call
fsopen().
If you're not allowing it already, someone will want user namespace
root to be able to use this very, very soon.
Yeah, I'm sure.  And I've been thinking on how to deal with it.

I think we *have* to open the source files/devices with the creds of whoever
called fsopen() or fspick() - that way you can't upgrade your privs by passing
your context fd to a suid program.  To enforce this, I think it's simplest for
fscontext_write() to call override_creds() right after taking the uapi_mutex
and then call revert_creds() right before dropping the mutex.
If you make a syscall that attaches a block device to an fscontext, you don’t need any of this.  Heck, someone might actually *want* to grab a block device from a different namespace.

All this override_creds() stuff is maybe okay if we were fixing an old broken thing. But this is brand new.  And having write() call override_creds() and do nontrivial things is a fascinating attack surface.

Just imagine what blows up if I abuse fscontext to open a block device on a path that traverses an AFS mount or /proc/.../fd or similar.  Or if I splice() from a network filesystem into fscontext.

(Al- can’t we just stop allowing splice() at all on things that don’t use iov_iter?)
Another thing we might want to look at is to allow a supervisory process to
examine the context before permitting the create/reconfigure action to
proceed.  It might also be possible to do this through the LSM.
Cc Tycho. He’s working on this exact idea using seccomp. And he’d probably much, much prefer if configuration of an fscontext didn’t use a performance-critical syscall like write().

As a straw man, I suggest:

fsconfigure(contextfd, ADD_BLOCKDEV, dfd, path, flags);

fsconfigure(contextfd, ADD_OPTION, 0, “foo=bar”, flags);

Etc.  

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2018-07-12 16:31:52

On Thu, Jul 12, 2018 at 9:23 AM Andy Lutomirski [off-list ref] wrote:
(Al- can’t we just stop allowing splice() at all on things that don’t use iov_iter?)
We could add a FMODE_SPLICE_READ/WRITE bit, and let people opt in to
splice. We probably should have.

But again, that really doesn't change the fundamentals.  Using write()
for commands is stupid.

It also means that you have to _parse_ all the damn input at that
level, which is a mistake too. It easily leads to insane decisions
like "you have to use 'write()' calls without buffering", because
re-buffering the stream is a f*cking pain.

Just say no. Seriously. Stop this idiotic discussion.

I'm just happy this came up early, because that way I know to look out
for it and not merge it.

                 Linus

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Al Viro <viro@ZenIV.linux.org.uk>
Date: 2018-07-12 16:51:34

On Thu, Jul 12, 2018 at 09:23:22AM -0700, Andy Lutomirski wrote:
If you make a syscall that attaches a block device to an fscontext, you don’t need any of this.  Heck, someone might actually *want* to grab a block device from a different namespace.
Fuck, NO.  The whole notion of "block device of filesystem" is fucking
garbage.  It's up to filesystem driver whether it uses any block
devices.  For backing store or otherwise.  Single or multiple.  Moreover,
it's up to filesystem driver whether it cares if backing store is
a block device, or mtd device, or...

Repeat after me: syscall that attaches a block device to an fscontext
makes as much sense as a syscall that attaches a charset name to the
same.  With a special syscall for attaching a timestamp granularity,
and another for selecting GID semantics on subdirectory creation.

Commit vs. write separation is one thing; fuckloads of special syscalls
for passing vaguely defined classes of mount options (which device
name *is*) is quite different.

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Al Viro <viro@ZenIV.linux.org.uk>
Date: 2018-07-12 16:58:21

On Thu, Jul 12, 2018 at 09:23:22AM -0700, Andy Lutomirski wrote:
 
As a straw man, I suggest:

fsconfigure(contextfd, ADD_BLOCKDEV, dfd, path, flags);

fsconfigure(contextfd, ADD_OPTION, 0, “foo=bar”, flags);
Bollocks.  First of all, block device *IS* a fucking option.
Always had been.  It's not even that it's passed as a separate
argument for historical reasons - just look at NFS.  That argument
is a detached part of options, parsed (yes, *parsed*) by filesystem
in question in whatever way it prefers.

Look at the things like e.g. cramfs.  That argument is interpreted
as pathname of block device.  Or that of mtd device.  Or the magic
string "mtd" followed by mtd number.

What's more, filesystems can and do live on more than one device.
Like e.g. btrfs.  Or like something journalled with the journal
on separate device.  So you do *NOT* get away from the need to
open stuff while doing mount - not unless you introduce arseloads
of ADD_... shite in your scheme.  And create a huge centralized
pile of code dealing with it.  ADD_NFS_IPV4_SERVER_AND_PATH, etc.?

You can't avoid parsing stuff.  It's one thing to argue at which
*point* you prefer doing that, but it has to be done kernel-side.
Format of filesystem options is fundamentally up to filesystem,
whichever syscall you use.

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Andy Lutomirski <luto@amacapital.net>
Date: 2018-07-12 17:54:36

On Jul 12, 2018, at 9:58 AM, Al Viro [off-list ref] wrote:
quoted
On Thu, Jul 12, 2018 at 09:23:22AM -0700, Andy Lutomirski wrote:

As a straw man, I suggest:

fsconfigure(contextfd, ADD_BLOCKDEV, dfd, path, flags);

fsconfigure(contextfd, ADD_OPTION, 0, “foo=bar”, flags);
Bollocks.  First of all, block device *IS* a fucking option.
Always had been.  It's not even that it's passed as a separate
argument for historical reasons - just look at NFS.  That argument
is a detached part of options, parsed (yes, *parsed*) by filesystem
in question in whatever way it prefers.
Fine, then generalize it. fsconfigure(context, ADD_FD, “some fs-specific string explaining what’s going on”, fd);  The point being that there are tons of cases where the filesystem wants to identify some backing store by some device node, and it seems like we should support something along the lines of a modern *at interface.

If I’m writing a daemon that deals with filesystems, I don’t want an API that looks like do_god_knows_what(context, “filesystem specific string that may contain a path to a device node or a network address”). That API will be a pain to use, since that opaque string may come from some random config file and I have no clue what it does. If I want to pass a device node or other object to a filesystem, I want to pass an fd (so I can use openat, SCM_CREDS, etc), and I want it to be crystal clear that I’m passing some object in. And if I tell a filesystem to access the network, I want it to be entirely clear which network namespace is in use.

I realize that doing this right is tricky when there are lots of legacy filesystems that parse opaque strings. That’s fine. We can convert things slowly.

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: David Howells <dhowells@redhat.com>
Date: 2018-07-12 21:11:39

Andy Lutomirski [off-list ref] wrote:
fsconfigure(contextfd, ADD_BLOCKDEV, dfd, path, flags);

fsconfigure(contextfd, ADD_OPTION, 0, “foo=bar”, flags);
That seems okayish.  I'm not sure we need the flags, but I do want to allow
for binary data in an option.  So perhaps something like:

	int fsconfig(int fd, unsigned int type,
		     const char *key, const void *val, size_t val_len);

for example:

	fd = fsopen("ext4", FSOPEN_CLOEXEC);
	fsconfig(fd, fsconfig_blockdev, "dev.data", "/dev/sda1", ...);
	fsconfig(fd, fsconfig_blockdev, "dev.journal", "/dev/sda2", ...);
	fsconfig(fd, fsconfig_option, "user_xattr", NULL, ...);
	fsconfig(fd, fsconfig_option, "errors", "continue", ...);
	fsconfig(fd, fsconfig_option, "data", "journal", ...);
	fsconfig(fd, fsconfig_security, "selinux.context", "unconfined_u:...");
	fsconfig(fd, fsconfig_create, NULL, NULL, 0);
	mfd = fsmount(fd, FSMOUNT_CLOEXEC, MS_NOEXEC);

or:

	fd = fsopen("nfs", FSOPEN_CLOEXEC);
	fsconfig(fd, fsconfig_namespace, "user", "<usernsfd>", ...);
	fsconfig(fd, fsconfig_namespace, "net", "<netnsfd>", ...);
	fsconfig(fd, fsconfig_option, "server", "foo.com", ...);
	fsconfig(fd, fsconfig_option, "root", "/bar", ...);
	fsconfig(fd, fsconfig_option, "soft", NULL, ...);
	fsconfig(fd, fsconfig_option, "retry", "3", ...);
	fsconfig(fd, fsconfig_option, "wsize", "4096", ...);
	fsconfig(fd, fsconfig_uidmap, "dhowells", "1234", ...);
	fsconfig(fd, fsconfig_security, "selinux.context", "unconfined_u:...");
	fsconfig(fd, fsconfig_create, NULL, NULL, 0);
	mfd = fsmount(fd, FSMOUNT_CLOEXEC, MS_NOEXEC);

This does mean that userspace has to work harder, though, but it would
simplify the LSM interface internally.

Al Viro [off-list ref]
First of all, block device *IS* a fucking option.
Whilst that is true, I still need to be able to separate it out for
unconverted filesystems.

David

Re: [PATCH 24/32] vfs: syscall: Add fsopen() to prepare for superblock creation [ver #9]

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2018-07-12 21:40:58

On Thu, Jul 12, 2018 at 2:00 PM David Howells [off-list ref] wrote:

for example:

        fd = fsopen("ext4", FSOPEN_CLOEXEC);
        fsconfig(fd, fsconfig_blockdev, "dev.data", "/dev/sda1", ...);
        fsconfig(fd, fsconfig_blockdev, "dev.journal", "/dev/sda2", ...);
Ok, that looks good to me. It also avoids the parsing issue with using
an interface like "write()", where the expectation is that you can
append things etc.

              Linus

14 further messages

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help