All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Howells <dhowells@redhat.com>
To: viro@zeniv.linux.org.uk
Cc: linux-fsdevel@vger.kernel.org, dhowells@redhat.com,
	linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org,
	mszeredi@redhat.com
Subject: [PATCH 5/9] Implement fsmount() to effect a pre-configured mount
Date: Wed, 03 May 2017 17:05:15 +0100	[thread overview]
Message-ID: <149382751575.30481.5197100856310494934.stgit@warthog.procyon.org.uk> (raw)
In-Reply-To: <149382747487.30481.15428192741961545429.stgit@warthog.procyon.org.uk>

Provide a system call by which a filesystem opened with fsopen() and
configured by a series of writes can be mounted:

	int ret = fsmount(int fsfd, int dfd, const char *path);

where fsfd is the fd returned by fsopen(), dfd and path describe the
mountpoint.  dfd can be AT_FDCWD or an fd open to a directory.

In the event that fsmount() fails, it may be possible to get an error
message by calling read().  If no message is available, ENODATA will be
reported.

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

 arch/x86/entry/syscalls/syscall_32.tbl |    1 
 arch/x86/entry/syscalls/syscall_64.tbl |    1 
 fs/namespace.c                         |   93 ++++++++++++++++++++++++++++++++
 include/linux/lsm_hooks.h              |    6 ++
 include/linux/security.h               |    6 ++
 include/linux/syscalls.h               |    1 
 kernel/sys_ni.c                        |    1 
 security/security.c                    |    7 ++
 security/selinux/hooks.c               |   13 ++++
 9 files changed, 129 insertions(+)

diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index 9bf8d4c62f85..abe6ea95e0e6 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -392,3 +392,4 @@
 383	i386	statx			sys_statx
 384	i386	arch_prctl		sys_arch_prctl			compat_sys_arch_prctl
 385	i386	fsopen			sys_fsopen
+386	i386	fsmount			sys_fsmount
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 9b198c5fc412..0977c5079831 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -340,6 +340,7 @@
 331	common	pkey_free		sys_pkey_free
 332	common	statx			sys_statx
 333	common	fsopen			sys_fsopen
+334	common	fsmount			sys_fsmount
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/fs/namespace.c b/fs/namespace.c
index e0edab9af308..a367b6cb2ac8 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -3259,6 +3259,99 @@ static int do_new_mount_mc(struct mount_context *mc, struct path *mountpoint,
 }
 
 /*
+ * Mount a new, prepared superblock (specified by fs_fd) on the location
+ * specified by dfd and dir_name.  dfd can be AT_FDCWD, a dir fd or a container
+ * fd.  This cannot be used for binding, moving or remounting mounts.
+ *
+ * If fd is a container and dir_name is NULL, then we try to make this the root
+ * filesystem of that container.  This requires CONTAINER_NEW_EMPTY_FS_NS to
+ * have been passed when creating the container.  This operation may only be
+ * done once.
+ */
+SYSCALL_DEFINE3(fsmount, int, fs_fd, int, dfd, const char __user *, dir_name)
+{
+	struct mount_context *mc;
+	struct inode *inode;
+	struct path mountpoint;
+	struct fd f = fdget(fs_fd);
+	unsigned int mnt_flags = 0;
+	long ret;
+
+	if (!f.file)
+		return -EBADF;
+
+	ret = -EINVAL;
+	if (f.file->f_op != &fs_fs_fops)
+		goto err_fsfd;
+
+	mc = f.file->private_data;
+
+	ret = -EPERM;
+	if (!may_mount() ||
+	    ((mc->ms_flags & MS_MANDLOCK) && !may_mandlock()))
+		goto err_fsfd;
+
+	/* Prevent further changes. */
+	inode = file_inode(f.file);
+	ret = inode_lock_killable(inode);
+	if (ret < 0)
+		goto err_fsfd;
+	ret = -EBUSY;
+	if (!mc->mounted) {
+		mc->mounted = true;
+		ret = 0;
+	}
+	inode_unlock(inode);
+	if (ret < 0)
+		goto err_fsfd;
+
+	/* Find the mountpoint.  A container can be specified in dfd. */
+	ret = user_path_at(dfd, dir_name, LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT,
+			   &mountpoint);
+	if (ret < 0) {
+		mc->error = "VFS: Mountpoint lookup failed";
+		goto err_fsfd;
+	}
+
+	ret = security_mount_ctx_mountpoint(mc, &mountpoint);
+	if (ret < 0)
+		goto err_mp;
+
+	/* Default to relatime unless overriden */
+	if (!(mc->ms_flags & MS_NOATIME))
+		mnt_flags |= MNT_RELATIME;
+
+	/* Separate the per-mountpoint flags */
+	if (mc->ms_flags & MS_NOSUID)
+		mnt_flags |= MNT_NOSUID;
+	if (mc->ms_flags & MS_NODEV)
+		mnt_flags |= MNT_NODEV;
+	if (mc->ms_flags & MS_NOEXEC)
+		mnt_flags |= MNT_NOEXEC;
+	if (mc->ms_flags & MS_NOATIME)
+		mnt_flags |= MNT_NOATIME;
+	if (mc->ms_flags & MS_NODIRATIME)
+		mnt_flags |= MNT_NODIRATIME;
+	if (mc->ms_flags & MS_STRICTATIME)
+		mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);
+	if (mc->ms_flags & MS_RDONLY)
+		mnt_flags |= MNT_READONLY;
+	mc->mnt_flags = mnt_flags;
+
+	mc->ms_flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN |
+			  MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
+			  MS_STRICTATIME | MS_NOREMOTELOCK | MS_SUBMOUNT);
+
+	ret = do_new_mount_mc(mc, &mountpoint, mnt_flags);
+
+err_mp:
+	path_put(&mountpoint);
+err_fsfd:
+	fdput(f);
+	return ret;
+}
+
+/*
  * Return true if path is reachable from root
  *
  * namespace_sem or mount_lock is held
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index f6aa68b8e68e..fe2bffd7264d 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -100,6 +100,10 @@
  *	Equivalent of sb_kern_mount, but with a mount_context.
  *	@mc indicates the mount context.
  *	@src_sb indicates the new superblock.
+ * @mount_ctx_mountpoint:
+ *	Equivalent of sb_mount, but with a mount_context.
+ *	@mc indicates the mount context.
+ *	@mountpoint indicates the path on which the mount will take place.
  *
  * Security hooks for filesystem operations.
  *
@@ -1389,6 +1393,7 @@ union security_list_options {
 	void (*mount_ctx_free)(struct mount_context *mc);
 	int (*mount_ctx_option)(struct mount_context *mc, char *opt);
 	int (*mount_ctx_kern_mount)(struct mount_context *mc, struct super_block *sb);
+	int (*mount_ctx_mountpoint)(struct mount_context *mc, struct path *mountpoint);
 
 	int (*sb_alloc_security)(struct super_block *sb);
 	void (*sb_free_security)(struct super_block *sb);
@@ -1703,6 +1708,7 @@ struct security_hook_heads {
 	struct list_head mount_ctx_free;
 	struct list_head mount_ctx_option;
 	struct list_head mount_ctx_kern_mount;
+	struct list_head mount_ctx_mountpoint;
 	struct list_head sb_alloc_security;
 	struct list_head sb_free_security;
 	struct list_head sb_copy_data;
diff --git a/include/linux/security.h b/include/linux/security.h
index 91efe3039bff..b427a554033a 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -226,6 +226,7 @@ int security_mount_ctx_dup(struct mount_context *mc, struct mount_context *src);
 void security_mount_ctx_free(struct mount_context *mc);
 int security_mount_ctx_option(struct mount_context *mc, char *opt);
 int security_mount_ctx_kern_mount(struct mount_context *mc, struct super_block *sb);
+int security_mount_ctx_mountpoint(struct mount_context *mc, struct path *mountpoint);
 int security_sb_alloc(struct super_block *sb);
 void security_sb_free(struct super_block *sb);
 int security_sb_copy_data(char *orig, char *copy);
@@ -541,6 +542,11 @@ static inline int security_mount_ctx_kern_mount(struct mount_context *mc,
 {
 	return 0;
 }
+static inline int security_mount_ctx_mountpoint(struct mount_context *mc,
+						struct path *mountpoint)
+{
+	return 0;
+}
 
 static inline int security_sb_alloc(struct super_block *sb)
 {
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 91ec8802ad5d..9ac7d8ca8c2e 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -906,5 +906,6 @@ asmlinkage long sys_pkey_free(int pkey);
 asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags,
 			  unsigned mask, struct statx __user *buffer);
 asmlinkage long sys_fsopen(const char *fs_name, int containerfd, unsigned int flags);
+asmlinkage long sys_fsmount(int fsfd, int dfd, const char *path);
 
 #endif
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index de1dc63e7e47..a0fe764bd5dd 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -261,3 +261,4 @@ cond_syscall(sys_pkey_free);
 
 /* fd-based mount */
 cond_syscall(sys_fsopen);
+cond_syscall(sys_fsmount);
diff --git a/security/security.c b/security/security.c
index 2e522361df66..56780c1852b5 100644
--- a/security/security.c
+++ b/security/security.c
@@ -334,6 +334,11 @@ int security_mount_ctx_kern_mount(struct mount_context *mc, struct super_block *
 	return call_int_hook(mount_ctx_kern_mount, 0, mc, sb);
 }
 
+int security_mount_ctx_mountpoint(struct mount_context *mc, struct path *mountpoint)
+{
+	return call_int_hook(mount_ctx_mountpoint, 0, mc, mountpoint);
+}
+
 int security_sb_alloc(struct super_block *sb)
 {
 	return call_int_hook(sb_alloc_security, 0, sb);
@@ -1691,6 +1696,8 @@ struct security_hook_heads security_hook_heads = {
 		LIST_HEAD_INIT(security_hook_heads.mount_ctx_option),
 	.mount_ctx_kern_mount =
 		LIST_HEAD_INIT(security_hook_heads.mount_ctx_kern_mount),
+	.mount_ctx_mountpoint =
+		LIST_HEAD_INIT(security_hook_heads.mount_ctx_mountpoint),
 	.sb_alloc_security =
 		LIST_HEAD_INIT(security_hook_heads.sb_alloc_security),
 	.sb_free_security =
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index cf38db840f71..2bd8e73eb9c9 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2999,6 +2999,18 @@ static int selinux_mount_ctx_kern_mount(struct mount_context *mc,
 	return rc;
 }
 
+static int selinux_mount_ctx_mountpoint(struct mount_context *mc,
+					struct path *mountpoint)
+{
+	const struct cred *cred = current_cred();
+	int ret;
+
+	ret = path_has_perm(cred, mountpoint, FILE__MOUNTON);
+	if (ret < 0)
+		mc->error = "SELinux: Mount on mountpoint not permitted";
+	return ret;
+}
+
 /* inode security operations */
 
 static int selinux_inode_alloc_security(struct inode *inode)
@@ -6309,6 +6321,7 @@ static struct security_hook_list selinux_hooks[] = {
 	LSM_HOOK_INIT(mount_ctx_free, selinux_mount_ctx_free),
 	LSM_HOOK_INIT(mount_ctx_option, selinux_mount_ctx_option),
 	LSM_HOOK_INIT(mount_ctx_kern_mount, selinux_mount_ctx_kern_mount),
+	LSM_HOOK_INIT(mount_ctx_mountpoint, selinux_mount_ctx_mountpoint),
 
 	LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
 	LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),

  parent reply	other threads:[~2017-05-03 16:05 UTC|newest]

Thread overview: 71+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-03 16:04 [RFC][PATCH 0/9] VFS: Introduce mount context David Howells
2017-05-03 16:04 ` [PATCH 1/9] Provide a function to create a NUL-terminated string from unterminated data David Howells
2017-05-03 16:55   ` Jeff Layton
2017-05-03 19:26   ` Rasmus Villemoes
2017-05-03 20:13   ` David Howells
2017-05-03 16:04 ` [PATCH 2/9] Clean up whitespace in fs/namespace.c David Howells
2017-05-03 16:04 ` [PATCH 3/9] VFS: Introduce a mount context David Howells
2017-05-03 18:13   ` Jeff Layton
2017-05-03 18:26     ` Joe Perches
2017-05-03 20:38       ` Matthew Wilcox
2017-05-03 21:36         ` Joe Perches
2017-05-03 21:36           ` [Cocci] " Joe Perches
2017-05-03 21:36           ` Joe Perches
2017-05-04  6:28           ` Julia Lawall
2017-05-04  6:28             ` [Cocci] " Julia Lawall
2017-05-04  6:28             ` Julia Lawall
2017-05-03 21:17       ` David Howells
2017-05-03 18:37     ` David Howells
2017-05-03 18:43       ` Joe Perches
2017-05-03 20:11       ` David Howells
2017-05-04  9:27     ` David Howells
2017-05-04 14:34       ` Joe Perches
2017-05-03 21:43   ` Rasmus Villemoes
2017-05-04 10:22   ` David Howells
2017-05-08 15:05   ` Miklos Szeredi
2017-05-08 22:57   ` David Howells
2017-05-09  8:03     ` Miklos Szeredi
2017-05-10 12:41       ` Karel Zak
2017-05-09  9:32     ` David Howells
2017-05-09 11:04       ` Miklos Szeredi
2017-05-09  9:41     ` David Howells
2017-05-09 12:02       ` Miklos Szeredi
2017-05-09 18:51         ` Jeff Layton
2017-05-10  7:24           ` Miklos Szeredi
2017-05-10  8:05           ` David Howells
2017-05-10 13:20             ` Jeff Layton
2017-05-10 13:30               ` Miklos Szeredi
2017-05-10 13:33                 ` Miklos Szeredi
2017-05-10 13:48                 ` Jeff Layton
2017-05-12  8:15                   ` Miklos Szeredi
2017-05-10 13:31             ` David Howells
2017-05-10 13:37               ` Jeff Layton
2017-05-09  9:56     ` David Howells
2017-05-09 12:38       ` Miklos Szeredi
2017-05-03 16:05 ` [PATCH 4/9] Implement fsopen() to prepare for a mount David Howells
2017-05-03 18:37   ` Jeff Layton
2017-05-03 18:41   ` David Howells
2017-05-03 20:44   ` Rasmus Villemoes
2017-05-04 10:40   ` Karel Zak
2017-05-04 12:55   ` David Howells
2017-05-04 12:58   ` David Howells
2017-05-04 13:06   ` David Howells
2017-05-04 13:34     ` Karel Zak
2017-05-09 18:40       ` Jeff Layton
2017-05-08 15:10   ` Miklos Szeredi
2017-05-08 23:09   ` David Howells
2017-05-03 16:05 ` David Howells [this message]
2017-05-03 16:05 ` [PATCH 6/9] Sample program for driving fsopen/fsmount David Howells
2017-05-03 16:05 ` [PATCH 7/9] procfs: Move proc_fill_super() to fs/proc/root.c David Howells
2017-05-03 16:05 ` [PATCH 8/9] proc: Support the mount context in procfs David Howells
2017-05-03 16:05 ` [PATCH 9/9] NFS: Support the mount context and fsopen() David Howells
2017-05-03 16:44 ` [RFC][PATCH 0/9] VFS: Introduce mount context Jeff Layton
2017-05-03 16:50 ` David Howells
2017-05-03 17:27   ` Jeff Layton
2017-05-05 14:35 ` Miklos Szeredi
2017-05-05 15:47 ` David Howells
2017-05-08  8:25   ` Miklos Szeredi
2017-05-08  8:35 ` David Howells
2017-05-08  8:43   ` Miklos Szeredi
2017-05-08 17:03 ` Djalal Harouni
2017-05-08 17:03   ` Djalal Harouni

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=149382751575.30481.5197100856310494934.stgit@warthog.procyon.org.uk \
    --to=dhowells@redhat.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=mszeredi@redhat.com \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.