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

Commit 57eccb83 authored by Al Viro's avatar Al Viro
Browse files

mount: consolidate permission checks



... and ask for global CAP_SYS_ADMIN only for superblock-level remounts

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 9b40bc90
Loading
Loading
Loading
Loading
+7 −33
Original line number Original line Diff line number Diff line
@@ -1300,24 +1300,6 @@ SYSCALL_DEFINE1(oldumount, char __user *, name)


#endif
#endif


static int mount_is_safe(struct path *path)
{
	if (may_mount())
		return 0;
	return -EPERM;
#ifdef notyet
	if (S_ISLNK(path->dentry->d_inode->i_mode))
		return -EPERM;
	if (path->dentry->d_inode->i_mode & S_ISVTX) {
		if (current_uid() != path->dentry->d_inode->i_uid)
			return -EPERM;
	}
	if (inode_permission(path->dentry->d_inode, MAY_WRITE))
		return -EPERM;
	return 0;
#endif
}

static bool mnt_ns_loop(struct path *path)
static bool mnt_ns_loop(struct path *path)
{
{
	/* Could bind mounting the mount namespace inode cause a
	/* Could bind mounting the mount namespace inode cause a
@@ -1640,9 +1622,6 @@ static int do_change_type(struct path *path, int flag)
	int type;
	int type;
	int err = 0;
	int err = 0;


	if (!may_mount())
		return -EPERM;

	if (path->dentry != path->mnt->mnt_root)
	if (path->dentry != path->mnt->mnt_root)
		return -EINVAL;
		return -EINVAL;


@@ -1676,9 +1655,7 @@ static int do_loopback(struct path *path, const char *old_name,
	LIST_HEAD(umount_list);
	LIST_HEAD(umount_list);
	struct path old_path;
	struct path old_path;
	struct mount *mnt = NULL, *old;
	struct mount *mnt = NULL, *old;
	int err = mount_is_safe(path);
	int err;
	if (err)
		return err;
	if (!old_name || !*old_name)
	if (!old_name || !*old_name)
		return -EINVAL;
		return -EINVAL;
	err = kern_path(old_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
	err = kern_path(old_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
@@ -1755,9 +1732,6 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
	struct super_block *sb = path->mnt->mnt_sb;
	struct super_block *sb = path->mnt->mnt_sb;
	struct mount *mnt = real_mount(path->mnt);
	struct mount *mnt = real_mount(path->mnt);


	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;

	if (!check_mnt(mnt))
	if (!check_mnt(mnt))
		return -EINVAL;
		return -EINVAL;


@@ -1771,6 +1745,8 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
	down_write(&sb->s_umount);
	down_write(&sb->s_umount);
	if (flags & MS_BIND)
	if (flags & MS_BIND)
		err = change_mount_flags(path->mnt, flags);
		err = change_mount_flags(path->mnt, flags);
	else if (!capable(CAP_SYS_ADMIN))
		err = -EPERM;
	else
	else
		err = do_remount_sb(sb, flags, data, 0);
		err = do_remount_sb(sb, flags, data, 0);
	if (!err) {
	if (!err) {
@@ -1803,9 +1779,7 @@ static int do_move_mount(struct path *path, const char *old_name)
	struct path old_path, parent_path;
	struct path old_path, parent_path;
	struct mount *p;
	struct mount *p;
	struct mount *old;
	struct mount *old;
	int err = 0;
	int err;
	if (!may_mount())
		return -EPERM;
	if (!old_name || !*old_name)
	if (!old_name || !*old_name)
		return -EINVAL;
		return -EINVAL;
	err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
	err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
@@ -1947,9 +1921,6 @@ static int do_new_mount(struct path *path, const char *fstype, int flags,
	if (!fstype)
	if (!fstype)
		return -EINVAL;
		return -EINVAL;


	if (!may_mount())
		return -EPERM;

	type = get_fs_type(fstype);
	type = get_fs_type(fstype);
	if (!type)
	if (!type)
		return -ENODEV;
		return -ENODEV;
@@ -2263,6 +2234,9 @@ long do_mount(const char *dev_name, const char *dir_name,
	if (retval)
	if (retval)
		goto dput_out;
		goto dput_out;


	if (!may_mount())
		return -EPERM;

	/* Default to relatime unless overriden */
	/* Default to relatime unless overriden */
	if (!(flags & MS_NOATIME))
	if (!(flags & MS_NOATIME))
		mnt_flags |= MNT_RELATIME;
		mnt_flags |= MNT_RELATIME;