Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 132e4608 authored by David Howells's avatar David Howells Committed by Al Viro
Browse files

new helper: do_new_mount_fc()



Create an fs_context-aware version of do_new_mount().  This takes an
fs_context with a superblock already attached to it.

Make do_new_mount() use do_new_mount_fc() rather than do_new_mount(); this
allows the consolidation of the mount creation, check and add steps.

To make this work, mount_too_revealing() is changed to take a superblock
rather than a mount (which the fs_context doesn't have available), allowing
this check to be done before the mount object is created.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Co-developed-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent a0c9a8b8
Loading
Loading
Loading
Loading
+39 −26
Original line number Diff line number Diff line
@@ -2523,7 +2523,37 @@ static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags)
	return err;
}

static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags);
static bool mount_too_revealing(const struct super_block *sb, int *new_mnt_flags);

/*
 * Create a new mount using a superblock configuration and request it
 * be added to the namespace tree.
 */
static int do_new_mount_fc(struct fs_context *fc, struct path *mountpoint,
			   unsigned int mnt_flags)
{
	struct vfsmount *mnt;
	struct super_block *sb = fc->root->d_sb;
	int error;

	if (mount_too_revealing(sb, &mnt_flags)) {
		dput(fc->root);
		fc->root = NULL;
		deactivate_locked_super(sb);
		return -EPERM;
	}

	up_write(&sb->s_umount);

	mnt = vfs_create_mount(fc);
	if (IS_ERR(mnt))
		return PTR_ERR(mnt);

	error = do_add_mount(real_mount(mnt), mountpoint, mnt_flags);
	if (error < 0)
		mntput(mnt);
	return error;
}

/*
 * create a new mount for userspace and request it to be added into the
@@ -2533,7 +2563,6 @@ static int do_new_mount(struct path *path, const char *fstype, int sb_flags,
			int mnt_flags, const char *name, void *data)
{
	struct file_system_type *type;
	struct vfsmount *mnt;
	struct fs_context *fc;
	const char *subtype = NULL;
	int err = 0;
@@ -2577,26 +2606,9 @@ static int do_new_mount(struct path *path, const char *fstype, int sb_flags,
		err = parse_monolithic_mount_data(fc, data);
	if (!err)
		err = vfs_get_tree(fc);
	if (err)
		goto out;

	up_write(&fc->root->d_sb->s_umount);
	mnt = vfs_create_mount(fc);
	if (IS_ERR(mnt)) {
		err = PTR_ERR(mnt);
		goto out;
	}

	if (mount_too_revealing(mnt, &mnt_flags)) {
		mntput(mnt);
		err = -EPERM;
		goto out;
	}
	if (!err)
		err = do_new_mount_fc(fc, path, mnt_flags);

	err = do_add_mount(real_mount(mnt), path, mnt_flags);
	if (err)
		mntput(mnt);
out:
	put_fs_context(fc);
	return err;
}
@@ -3421,7 +3433,8 @@ bool current_chrooted(void)
	return chrooted;
}

static bool mnt_already_visible(struct mnt_namespace *ns, struct vfsmount *new,
static bool mnt_already_visible(struct mnt_namespace *ns,
				const struct super_block *sb,
				int *new_mnt_flags)
{
	int new_flags = *new_mnt_flags;
@@ -3433,7 +3446,7 @@ static bool mnt_already_visible(struct mnt_namespace *ns, struct vfsmount *new,
		struct mount *child;
		int mnt_flags;

		if (mnt->mnt.mnt_sb->s_type != new->mnt_sb->s_type)
		if (mnt->mnt.mnt_sb->s_type != sb->s_type)
			continue;

		/* This mount is not fully visible if it's root directory
@@ -3484,7 +3497,7 @@ static bool mnt_already_visible(struct mnt_namespace *ns, struct vfsmount *new,
	return visible;
}

static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags)
static bool mount_too_revealing(const struct super_block *sb, int *new_mnt_flags)
{
	const unsigned long required_iflags = SB_I_NOEXEC | SB_I_NODEV;
	struct mnt_namespace *ns = current->nsproxy->mnt_ns;
@@ -3494,7 +3507,7 @@ static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags)
		return false;

	/* Can this filesystem be too revealing? */
	s_iflags = mnt->mnt_sb->s_iflags;
	s_iflags = sb->s_iflags;
	if (!(s_iflags & SB_I_USERNS_VISIBLE))
		return false;

@@ -3504,7 +3517,7 @@ static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags)
		return true;
	}

	return !mnt_already_visible(ns, mnt, new_mnt_flags);
	return !mnt_already_visible(ns, sb, new_mnt_flags);
}

bool mnt_may_suid(struct vfsmount *mnt)