On Tue, Feb 19, 2019 at 6:08 PM David Howells <dhowells@xxxxxxxxxx> 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@xxxxxxxxxx> > cc: linux-api@xxxxxxxxxxxxxxx > Signed-off-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx> > --- [...] > +/* > + * 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. > + */ > + lflags = 0; > + if (flags & MOVE_MOUNT_F_SYMLINKS) lflags |= LOOKUP_FOLLOW; > + if (flags & MOVE_MOUNT_F_AUTOMOUNTS) lflags |= LOOKUP_AUTOMOUNT; > + if (flags & MOVE_MOUNT_F_EMPTY_PATH) lflags |= LOOKUP_EMPTY; > + > + ret = user_path_at(from_dfd, from_pathname, lflags, &from_path); > + if (ret < 0) > + return ret; > + > + lflags = 0; > + if (flags & MOVE_MOUNT_T_SYMLINKS) lflags |= LOOKUP_FOLLOW; > + if (flags & MOVE_MOUNT_T_AUTOMOUNTS) lflags |= LOOKUP_AUTOMOUNT; > + if (flags & MOVE_MOUNT_T_EMPTY_PATH) lflags |= LOOKUP_EMPTY; > + > + ret = user_path_at(to_dfd, to_pathname, lflags, &to_path); > + if (ret < 0) > + goto out_from; > + > + ret = security_move_mount(&from_path, &to_path); > + if (ret < 0) > + goto out_to; Wouldn't you want to call this from do_move_mount() instead for consistency? If MS_MOVE and this thing perform the same logical operation, they should probably also call the same LSM hook. > + ret = do_move_mount(&from_path, &to_path); > + > +out_to: > + path_put(&to_path); > +out_from: > + path_put(&from_path); > + return ret; > +} [...] > diff --git a/include/uapi/linux/mount.h b/include/uapi/linux/mount.h > index fd7ae2e7eccf..3634e065836c 100644 > --- a/include/uapi/linux/mount.h > +++ b/include/uapi/linux/mount.h > @@ -61,4 +61,15 @@ > #define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */ > #define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */ > > +/* > + * move_mount() flags. > + */ > +#define MOVE_MOUNT_F_SYMLINKS 0x00000001 /* Follow symlinks on from path */ "Follow symlinks" sounds a bit misleading. LOOKUP_NOFOLLOW only applies to the last element of the path; and there is a pending patchset that's going to let userspace ask the kernel to actually not follow *any* symlinks on the path with O_NOSYMLINKS, so this might confuse people. Maybe change the comment to "don't follow trailing symlink", or something like that?