From: Alan Jenkins <alan.christopher.jenkins@gmail.com>
To: David Howells <dhowells@redhat.com>, viro@zeniv.linux.org.uk
Cc: linux-api@vger.kernel.org, linux-fsdevel@vger.kernel.org,
torvalds@linux-foundation.org, ebiederm@xmission.com,
linux-security-module@vger.kernel.org
Subject: Re: [PATCH 02/10] vfs: syscall: Add move_mount(2) to move mounts around
Date: Wed, 20 Feb 2019 12:41:51 +0000 [thread overview]
Message-ID: <45432256-ceca-41ae-c695-d9788470f1f1@gmail.com> (raw)
In-Reply-To: <57a6b419-1541-6f97-6810-d0d376580def@gmail.com>
On 20/02/2019 12:32, Alan Jenkins wrote:
> On 19/02/2019 17:08, David Howells wrote:
>> Add a move_mount() system call that will move a mount from one place to
>> another and, in the next commit, allow to attach an unattached mount
>> tree.
>>
>> The new system call looks like the following:
>>
>> int move_mount(int from_dfd, const char *from_path,
>> int to_dfd, const char *to_path,
>> unsigned int flags);
>>
>> Signed-off-by: David Howells <dhowells@redhat.com>
>> cc: linux-api@vger.kernel.org
>> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
>> ---
>>
>> arch/x86/entry/syscalls/syscall_32.tbl | 1
>> arch/x86/entry/syscalls/syscall_64.tbl | 1
>> fs/namespace.c | 126
>> ++++++++++++++++++++++++--------
>> include/linux/lsm_hooks.h | 6 ++
>> include/linux/security.h | 7 ++
>> include/linux/syscalls.h | 3 +
>> include/uapi/linux/mount.h | 11 +++
>> security/security.c | 5 +
>> 8 files changed, 129 insertions(+), 31 deletions(-)
>
>> diff --git a/fs/namespace.c b/fs/namespace.c
>> index 112d46f26fc3..f10122028a11 100644
>> --- a/fs/namespace.c
>> +++ b/fs/namespace.c
>> @@ -2537,72 +2537,81 @@ static inline int
>> tree_contains_unbindable(struct mount *mnt)
>> return 0;
>> }
>> -static int do_move_mount(struct path *path, const char *old_name)
>> +static int do_move_mount(struct path *old_path, struct path *new_path)
>> {
>> - struct path old_path, parent_path;
>> + struct path parent_path = {.mnt = NULL, .dentry = NULL};
>> struct mount *p;
>> struct mount *old;
>> struct mountpoint *mp;
>> int err;
>> - if (!old_name || !*old_name)
>> - return -EINVAL;
>> - err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
>> - if (err)
>> - return err;
>> - mp = lock_mount(path);
>> - err = PTR_ERR(mp);
>> + mp = lock_mount(new_path);
>> if (IS_ERR(mp))
>> - goto out;
>> + return PTR_ERR(mp);
>> - old = real_mount(old_path.mnt);
>> - p = real_mount(path->mnt);
>> + old = real_mount(old_path->mnt);
>> + p = real_mount(new_path->mnt);
>> err = -EINVAL;
>> if (!check_mnt(p) || !check_mnt(old))
>> - goto out1;
>> + goto out;
>> - if (old->mnt.mnt_flags & MNT_LOCKED)
>> - goto out1;
>> + if (!mnt_has_parent(old))
>> + goto out;
>> - err = -EINVAL;
>> - if (old_path.dentry != old_path.mnt->mnt_root)
>> - goto out1;
>> + if (old->mnt.mnt_flags & MNT_LOCKED)
>> + goto out;
>> - if (!mnt_has_parent(old))
>> - goto out1;
>> + if (old_path->dentry != old_path->mnt->mnt_root)
>> + goto out;
>> - if (d_is_dir(path->dentry) !=
>> - d_is_dir(old_path.dentry))
>> - goto out1;
>> + if (d_is_dir(new_path->dentry) !=
>> + d_is_dir(old_path->dentry))
>> + goto out;
>> /*
>> * Don't move a mount residing in a shared parent.
>> */
>> if (IS_MNT_SHARED(old->mnt_parent))
>> - goto out1;
>> + goto out;
>> /*
>> * Don't move a mount tree containing unbindable mounts to a
>> destination
>> * mount which is shared.
>> */
>> if (IS_MNT_SHARED(p) && tree_contains_unbindable(old))
>> - goto out1;
>> + goto out;
>> err = -ELOOP;
>> for (; mnt_has_parent(p); p = p->mnt_parent)
>> if (p == old)
>> - goto out1;
>> + goto out;
>> - err = attach_recursive_mnt(old, real_mount(path->mnt), mp,
>> &parent_path);
>> + err = attach_recursive_mnt(old, real_mount(new_path->mnt), mp,
>> + &parent_path);
>> if (err)
>> - goto out1;
>> + goto out;
>> /* if the mount is moved, it should no longer be expire
>> * automatically */
>> list_del_init(&old->mnt_expire);
>> -out1:
>> - unlock_mount(mp);
>> out:
>> + unlock_mount(mp);
>> if (!err)
>> path_put(&parent_path);
>> + return err;
>> +}
>> +
>> +static int do_move_mount_old(struct path *path, const char *old_name)
>> +{
>> + struct path old_path;
>> + int err;
>> +
>> + if (!old_name || !*old_name)
>> + return -EINVAL;
>> +
>> + err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
>> + if (err)
>> + return err;
>> +
>> + err = do_move_mount(&old_path, path);
>> path_put(&old_path);
>> return err;
>> }
>> @@ -3050,7 +3059,7 @@ long do_mount(const char *dev_name, const char
>> __user *dir_name,
>> else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
>> MS_UNBINDABLE))
>> retval = do_change_type(&path, flags);
>> else if (flags & MS_MOVE)
>> - retval = do_move_mount(&path, dev_name);
>> + retval = do_move_mount_old(&path, dev_name);
>> else
>> retval = do_new_mount(&path, type_page, sb_flags, mnt_flags,
>> dev_name, data_page);
>> @@ -3278,6 +3287,61 @@ SYSCALL_DEFINE5(mount, char __user *,
>> dev_name, char __user *, dir_name,
>> return ksys_mount(dev_name, dir_name, type, flags, data);
>> }
>> +/*
>> + * Move a mount from one place to another.
>> + *
>> + * Note the flags value is a combination of MOVE_MOUNT_* flags.
>> + */
>> +SYSCALL_DEFINE5(move_mount,
>> + int, from_dfd, const char *, from_pathname,
>> + int, to_dfd, const char *, to_pathname,
>> + unsigned int, flags)
>> +{
>> + struct path from_path, to_path;
>> + unsigned int lflags;
>> + int ret = 0;
>> +
>> + if (!may_mount())
>> + return -EPERM;
>> +
>> + if (flags & ~MOVE_MOUNT__MASK)
>> + return -EINVAL;
>> +
>> + /* If someone gives a pathname, they aren't permitted to move
>> + * from an fd that requires unmount as we can't get at the flag
>> + * to clear it afterwards.
>> + */
>
> Comment is incorrect.
>
> * FMODE_NEED_UNMOUNT is never cleared.
>
> * Technically I don't see anything preventing them giving a pathname,
> but it needs to be "." or equivalent. Otherwise it will fail the
> "!attached" check in the next patch.
>
> * The only argument I remember for preventing this, was that it might
> confuse users (not the kernel). If you are allowed to move from a
> sub-mount, then in certain programming styles - like my shell script
> test cases - you might accidentally close the original file too
> early. Then you won't be able to do move_mount() from the tree,
> because the tree was unmounted ("dissolved") when you closed it.
>
> I think the description in the previous patch, for open_tree(), makes
> it clear though. "The detached tree will be dissolved on the final
> close of obtained file".
>
> If there is a good reason, I expect we can simply remove the
> "!attached" part of the check. If the constraint is generating more
> confusion than the added flexibility, I think that would be a good
> reason :-).
Sorry, I see it. Although you are not clearing a flag, you have to free
the old value of old->mnt_ns. And that is not being reference-counted,
it has a single owner, the file which has FMODE_NEED_UNMOUNT. So it is
not possible to simply remove the "!attached" check.
I still find the comment confusing, i.e. describing this as clearing a flag.
Alan
next prev parent reply other threads:[~2019-02-20 12:41 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-02-19 17:08 [PATCH 00/10] VFS: Provide new mount UAPI David Howells
2019-02-19 17:08 ` [PATCH 01/10] vfs: syscall: Add open_tree(2) to reference or clone a mount David Howells
2019-02-19 17:08 ` [PATCH 02/10] vfs: syscall: Add move_mount(2) to move mounts around David Howells
2019-02-20 12:32 ` Alan Jenkins
2019-02-20 12:41 ` Alan Jenkins [this message]
2019-02-20 16:23 ` Jann Horn
2019-07-08 12:02 ` Tetsuo Handa
2019-07-08 13:18 ` Al Viro
2019-07-08 17:12 ` Eric W. Biederman
2019-07-08 18:01 ` Al Viro
2019-07-08 18:13 ` Al Viro
2019-07-08 20:21 ` Al Viro
2019-07-09 0:13 ` Eric W. Biederman
2019-07-09 10:51 ` Tetsuo Handa
2019-07-22 10:12 ` Tetsuo Handa
2019-07-23 4:16 ` John Johansen
2019-07-23 13:45 ` Tetsuo Handa
2019-08-06 10:43 ` Tetsuo Handa
2019-08-22 3:51 ` [RFC][PATCH] fix d_absolute_path() interplay with fsmount() Al Viro
2019-08-30 10:11 ` Tetsuo Handa
2019-07-23 21:45 ` [PATCH 02/10] vfs: syscall: Add move_mount(2) to move mounts around James Morris
2019-07-23 23:30 ` Al Viro
2019-02-19 17:08 ` [PATCH 03/10] teach move_mount(2) to work with OPEN_TREE_CLONE David Howells
2019-02-20 18:59 ` Alan Jenkins
2019-02-26 17:45 ` Alan Jenkins
2019-02-19 17:08 ` [PATCH 04/10] Make anon_inodes unconditional David Howells
2019-02-19 17:09 ` [PATCH 05/10] vfs: syscall: Add fsopen() to prepare for superblock creation David Howells
2019-02-19 17:09 ` [PATCH 06/10] vfs: Implement logging through fs_context David Howells
2019-02-19 17:09 ` [PATCH 07/10] vfs: syscall: Add fsconfig() for configuring and managing a context David Howells
2019-02-19 17:09 ` [PATCH 08/10] vfs: syscall: Add fsmount() to create a mount for a superblock David Howells
2019-02-19 17:09 ` [PATCH 09/10] vfs: syscall: Add fspick() to select a superblock for reconfiguration David Howells
2019-02-19 17:09 ` [PATCH 10/10] vfs: Add a sample program for the new mount API David Howells
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=45432256-ceca-41ae-c695-d9788470f1f1@gmail.com \
--to=alan.christopher.jenkins@gmail.com \
--cc=dhowells@redhat.com \
--cc=ebiederm@xmission.com \
--cc=linux-api@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=torvalds@linux-foundation.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).