History

vfs: syscall: Add move_mount(2) to move mounts around

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);

David Howells committed 8 years ago

Commit 2db154b1 parent a07b2008 files · +130 −32Browse files

Unified · Split

8 files
  1. arch/x86/entry/syscalls/syscall_32.tbl +2 −1
  2. arch/x86/entry/syscalls/syscall_64.tbl +1 −0
  3. fs/namespace.c +95 −31
  4. include/linux/lsm_hooks.h +6 −0
  5. include/linux/security.h +7 −0
  6. include/linux/syscalls.h +3 −0
  7. include/uapi/linux/mount.h +11 −0
  8. security/security.c +5 −0
arch/x86/entry/syscalls/syscall_32.tbl+2−1
@@ -399,7 +399,8 @@ · 398 unmodified lines
399385 i386 io_pgetevents sys_io_pgetevents_time32 __ia32_compat_sys_io_pgetevents399385 i386 io_pgetevents sys_io_pgetevents_time32 __ia32_compat_sys_io_pgetevents
400386 i386 rseq sys_rseq __ia32_sys_rseq400386 i386 rseq sys_rseq __ia32_sys_rseq
401387 i386 open_tree sys_open_tree __ia32_sys_open_tree401387 i386 open_tree sys_open_tree __ia32_sys_open_tree
402# don't use numbers 388 through 392, add new calls at the end402388 i386 move_mount sys_move_mount __ia32_sys_move_mount
403# don't use numbers 389 through 392, add new calls at the end
403393 i386 semget sys_semget __ia32_sys_semget404393 i386 semget sys_semget __ia32_sys_semget
404394 i386 semctl sys_semctl __ia32_compat_sys_semctl405394 i386 semctl sys_semctl __ia32_compat_sys_semctl
405395 i386 shmget sys_shmget __ia32_sys_shmget406395 i386 shmget sys_shmget __ia32_sys_shmget
arch/x86/entry/syscalls/syscall_64.tbl+1−0
@@ -344,6 +344,7 @@ · 343 unmodified lines
344333 common io_pgetevents __x64_sys_io_pgetevents344333 common io_pgetevents __x64_sys_io_pgetevents
345334 common rseq __x64_sys_rseq345334 common rseq __x64_sys_rseq
346335 common open_tree __x64_sys_open_tree346335 common open_tree __x64_sys_open_tree
347336 common move_mount __x64_sys_move_mount
347# don't use numbers 387 through 423, add new calls after the last348# don't use numbers 387 through 423, add new calls after the last
348# 'common' entry349# 'common' entry
349424 common pidfd_send_signal __x64_sys_pidfd_send_signal350424 common pidfd_send_signal __x64_sys_pidfd_send_signal
fs/namespace.c+95−31
@@ -2539,72 +2539,81 @@ static inline int tree_contains_unbindable(struct mount *mnt) · 2538 unmodified lines
2539 return 0;2539 return 0;
2540}2540}
2541 2541
2542static int do_move_mount(struct path *path, const char *old_name)2542static int do_move_mount(struct path *old_path, struct path *new_path)
2543{2543{
2544 struct path old_path, parent_path;2544 struct path parent_path = {.mnt = NULL, .dentry = NULL};
2545 struct mount *p;2545 struct mount *p;
2546 struct mount *old;2546 struct mount *old;
2547 struct mountpoint *mp;2547 struct mountpoint *mp;
2548 int err;2548 int err;
2549 if (!old_name || !*old_name)
2550 return -EINVAL;
2551 err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
2552 if (err)
2553 return err;
2554 2549
2555 mp = lock_mount(path);2550 mp = lock_mount(new_path);
2556 err = PTR_ERR(mp);
2557 if (IS_ERR(mp))2551 if (IS_ERR(mp))
2558 goto out;2552 return PTR_ERR(mp);
2559 2553
2560 old = real_mount(old_path.mnt);2554 old = real_mount(old_path->mnt);
2561 p = real_mount(path->mnt);2555 p = real_mount(new_path->mnt);
2562 2556
2563 err = -EINVAL;2557 err = -EINVAL;
2564 if (!check_mnt(p) || !check_mnt(old))2558 if (!check_mnt(p) || !check_mnt(old))
2565 goto out1;2559 goto out;
2566 2560
2567 if (old->mnt.mnt_flags & MNT_LOCKED)2561 if (!mnt_has_parent(old))
2568 goto out1;2562 goto out;
2569 2563
2570 err = -EINVAL;2564 if (old->mnt.mnt_flags & MNT_LOCKED)
2571 if (old_path.dentry != old_path.mnt->mnt_root)2565 goto out;
2572 goto out1;
2573 2566
2574 if (!mnt_has_parent(old))2567 if (old_path->dentry != old_path->mnt->mnt_root)
2575 goto out1;2568 goto out;
2576 2569
2577 if (d_is_dir(path->dentry) !=2570 if (d_is_dir(new_path->dentry) !=
2578 d_is_dir(old_path.dentry))2571 d_is_dir(old_path->dentry))
2579 goto out1;2572 goto out;
2580 /*2573 /*
2581 * Don't move a mount residing in a shared parent.2574 * Don't move a mount residing in a shared parent.
2582 */2575 */
2583 if (IS_MNT_SHARED(old->mnt_parent))2576 if (IS_MNT_SHARED(old->mnt_parent))
2584 goto out1;2577 goto out;
2585 /*2578 /*
2586 * Don't move a mount tree containing unbindable mounts to a destination2579 * Don't move a mount tree containing unbindable mounts to a destination
2587 * mount which is shared.2580 * mount which is shared.
2588 */2581 */
2589 if (IS_MNT_SHARED(p) && tree_contains_unbindable(old))2582 if (IS_MNT_SHARED(p) && tree_contains_unbindable(old))
2590 goto out1;2583 goto out;
2591 err = -ELOOP;2584 err = -ELOOP;
2592 for (; mnt_has_parent(p); p = p->mnt_parent)2585 for (; mnt_has_parent(p); p = p->mnt_parent)
2593 if (p == old)2586 if (p == old)
2594 goto out1;2587 goto out;
2595 2588
2596 err = attach_recursive_mnt(old, real_mount(path->mnt), mp, &parent_path);2589 err = attach_recursive_mnt(old, real_mount(new_path->mnt), mp,
2590 &parent_path);
2597 if (err)2591 if (err)
2598 goto out1;2592 goto out;
2599 2593
2600 /* if the mount is moved, it should no longer be expire2594 /* if the mount is moved, it should no longer be expire
2601 * automatically */2595 * automatically */
2602 list_del_init(&old->mnt_expire);2596 list_del_init(&old->mnt_expire);
2603out1:
2604 unlock_mount(mp);
2605out:2597out:
2598 unlock_mount(mp);
2606 if (!err)2599 if (!err)
2607 path_put(&parent_path);2600 path_put(&parent_path);
2601 return err;
2602}
2603
2604static int do_move_mount_old(struct path *path, const char *old_name)
2605{
2606 struct path old_path;
2607 int err;
2608
2609 if (!old_name || !*old_name)
2610 return -EINVAL;
2611
2612 err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
2613 if (err)
2614 return err;
2615
2616 err = do_move_mount(&old_path, path);
2608 path_put(&old_path);2617 path_put(&old_path);
2609 return err;2618 return err;
2610}2619}
@@ -3050,7 +3059,7 @@ long do_mount(const char *dev_name, const char __user *dir_name, · 439 unmodified lines
3050 else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))3059 else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
3051 retval = do_change_type(&path, flags);3060 retval = do_change_type(&path, flags);
3052 else if (flags & MS_MOVE)3061 else if (flags & MS_MOVE)
3053 retval = do_move_mount(&path, dev_name);3062 retval = do_move_mount_old(&path, dev_name);
3054 else3063 else
3055 retval = do_new_mount(&path, type_page, sb_flags, mnt_flags,3064 retval = do_new_mount(&path, type_page, sb_flags, mnt_flags,
3056 dev_name, data_page);3065 dev_name, data_page);
@@ -3278,6 +3287,61 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, · 221 unmodified lines
3278 return ksys_mount(dev_name, dir_name, type, flags, data);3287 return ksys_mount(dev_name, dir_name, type, flags, data);
3279}3288}
3280 3289
3290/*
3291 * Move a mount from one place to another.
3292 *
3293 * Note the flags value is a combination of MOVE_MOUNT_* flags.
3294 */
3295SYSCALL_DEFINE5(move_mount,
3296 int, from_dfd, const char *, from_pathname,
3297 int, to_dfd, const char *, to_pathname,
3298 unsigned int, flags)
3299{
3300 struct path from_path, to_path;
3301 unsigned int lflags;
3302 int ret = 0;
3303
3304 if (!may_mount())
3305 return -EPERM;
3306
3307 if (flags & ~MOVE_MOUNT__MASK)
3308 return -EINVAL;
3309
3310 /* If someone gives a pathname, they aren't permitted to move
3311 * from an fd that requires unmount as we can't get at the flag
3312 * to clear it afterwards.
3313 */
3314 lflags = 0;
3315 if (flags & MOVE_MOUNT_F_SYMLINKS) lflags |= LOOKUP_FOLLOW;
3316 if (flags & MOVE_MOUNT_F_AUTOMOUNTS) lflags |= LOOKUP_AUTOMOUNT;
3317 if (flags & MOVE_MOUNT_F_EMPTY_PATH) lflags |= LOOKUP_EMPTY;
3318
3319 ret = user_path_at(from_dfd, from_pathname, lflags, &from_path);
3320 if (ret < 0)
3321 return ret;
3322
3323 lflags = 0;
3324 if (flags & MOVE_MOUNT_T_SYMLINKS) lflags |= LOOKUP_FOLLOW;
3325 if (flags & MOVE_MOUNT_T_AUTOMOUNTS) lflags |= LOOKUP_AUTOMOUNT;
3326 if (flags & MOVE_MOUNT_T_EMPTY_PATH) lflags |= LOOKUP_EMPTY;
3327
3328 ret = user_path_at(to_dfd, to_pathname, lflags, &to_path);
3329 if (ret < 0)
3330 goto out_from;
3331
3332 ret = security_move_mount(&from_path, &to_path);
3333 if (ret < 0)
3334 goto out_to;
3335
3336 ret = do_move_mount(&from_path, &to_path);
3337
3338out_to:
3339 path_put(&to_path);
3340out_from:
3341 path_put(&from_path);
3342 return ret;
3343}
3344
3281/*3345/*
3282 * Return true if path is reachable from root3346 * Return true if path is reachable from root
3283 *3347 *
include/linux/lsm_hooks.h+6−0
@@ -160,6 +160,10 @@ · 159 unmodified lines
160 * Parse a string of security data filling in the opts structure160 * Parse a string of security data filling in the opts structure
161 * @options string containing all mount options known by the LSM161 * @options string containing all mount options known by the LSM
162 * @opts binary data structure usable by the LSM162 * @opts binary data structure usable by the LSM
163 * @move_mount:
164 * Check permission before a mount is moved.
165 * @from_path indicates the mount that is going to be moved.
166 * @to_path indicates the mountpoint that will be mounted upon.
163 * @dentry_init_security:167 * @dentry_init_security:
164 * Compute a context for a dentry as the inode is not yet available168 * Compute a context for a dentry as the inode is not yet available
165 * since NFSv4 has no label backed by an EA anyway.169 * since NFSv4 has no label backed by an EA anyway.
@@ -1501,6 +1505,7 @@ union security_list_options { · 1335 unmodified lines
1501 unsigned long *set_kern_flags);1505 unsigned long *set_kern_flags);
1502 int (*sb_add_mnt_opt)(const char *option, const char *val, int len,1506 int (*sb_add_mnt_opt)(const char *option, const char *val, int len,
1503 void **mnt_opts);1507 void **mnt_opts);
1508 int (*move_mount)(const struct path *from_path, const struct path *to_path);
1504 int (*dentry_init_security)(struct dentry *dentry, int mode,1509 int (*dentry_init_security)(struct dentry *dentry, int mode,
1505 const struct qstr *name, void **ctx,1510 const struct qstr *name, void **ctx,
1506 u32 *ctxlen);1511 u32 *ctxlen);
@@ -1835,6 +1840,7 @@ struct security_hook_heads { · 328 unmodified lines
1835 struct hlist_head sb_set_mnt_opts;1840 struct hlist_head sb_set_mnt_opts;
1836 struct hlist_head sb_clone_mnt_opts;1841 struct hlist_head sb_clone_mnt_opts;
1837 struct hlist_head sb_add_mnt_opt;1842 struct hlist_head sb_add_mnt_opt;
1843 struct hlist_head move_mount;
1838 struct hlist_head dentry_init_security;1844 struct hlist_head dentry_init_security;
1839 struct hlist_head dentry_create_files_as;1845 struct hlist_head dentry_create_files_as;
1840#ifdef CONFIG_SECURITY_PATH1846#ifdef CONFIG_SECURITY_PATH
include/linux/security.h+7−0
@@ -250,6 +250,7 @@ int security_sb_clone_mnt_opts(const struct super_block *oldsb, · 249 unmodified lines
250 unsigned long *set_kern_flags);250 unsigned long *set_kern_flags);
251int security_add_mnt_opt(const char *option, const char *val,251int security_add_mnt_opt(const char *option, const char *val,
252 int len, void **mnt_opts);252 int len, void **mnt_opts);
253int security_move_mount(const struct path *from_path, const struct path *to_path);
253int security_dentry_init_security(struct dentry *dentry, int mode,254int security_dentry_init_security(struct dentry *dentry, int mode,
254 const struct qstr *name, void **ctx,255 const struct qstr *name, void **ctx,
255 u32 *ctxlen);256 u32 *ctxlen);
@@ -611,6 +612,12 @@ static inline int security_add_mnt_opt(const char *option, const char *val, · 355 unmodified lines
611 return 0;612 return 0;
612}613}
613 614
615static inline int security_move_mount(const struct path *from_path,
616 const struct path *to_path)
617{
618 return 0;
619}
620
614static inline int security_inode_alloc(struct inode *inode)621static inline int security_inode_alloc(struct inode *inode)
615{622{
616 return 0;623 return 0;
include/linux/syscalls.h+3−0
@@ -986,6 +986,9 @@ asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags, · 985 unmodified lines
986asmlinkage long sys_rseq(struct rseq __user *rseq, uint32_t rseq_len,986asmlinkage long sys_rseq(struct rseq __user *rseq, uint32_t rseq_len,
987 int flags, uint32_t sig);987 int flags, uint32_t sig);
988asmlinkage long sys_open_tree(int dfd, const char __user *path, unsigned flags);988asmlinkage long sys_open_tree(int dfd, const char __user *path, unsigned flags);
989asmlinkage long sys_move_mount(int from_dfd, const char __user *from_path,
990 int to_dfd, const char __user *to_path,
991 unsigned int ms_flags);
989asmlinkage long sys_pidfd_send_signal(int pidfd, int sig,992asmlinkage long sys_pidfd_send_signal(int pidfd, int sig,
990 siginfo_t __user *info,993 siginfo_t __user *info,
991 unsigned int flags);994 unsigned int flags);
include/uapi/linux/mount.h+11−0
@@ -61,4 +61,15 @@ · 60 unmodified lines
61#define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */61#define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */
62#define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */62#define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */
63 63
64/*
65 * move_mount() flags.
66 */
67#define MOVE_MOUNT_F_SYMLINKS 0x00000001 /* Follow symlinks on from path */
68#define MOVE_MOUNT_F_AUTOMOUNTS 0x00000002 /* Follow automounts on from path */
69#define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */
70#define MOVE_MOUNT_T_SYMLINKS 0x00000010 /* Follow symlinks on to path */
71#define MOVE_MOUNT_T_AUTOMOUNTS 0x00000020 /* Follow automounts on to path */
72#define MOVE_MOUNT_T_EMPTY_PATH 0x00000040 /* Empty to path permitted */
73#define MOVE_MOUNT__MASK 0x00000077
74
64#endif /* _UAPI_LINUX_MOUNT_H */75#endif /* _UAPI_LINUX_MOUNT_H */
security/security.c+5−0
@@ -866,6 +866,11 @@ int security_add_mnt_opt(const char *option, const char *val, int len, · 865 unmodified lines
866}866}
867EXPORT_SYMBOL(security_add_mnt_opt);867EXPORT_SYMBOL(security_add_mnt_opt);
868 868
869int security_move_mount(const struct path *from_path, const struct path *to_path)
870{
871 return call_int_hook(move_mount, 0, from_path, to_path);
872}
873
869int security_inode_alloc(struct inode *inode)874int security_inode_alloc(struct inode *inode)
870{875{
871 int rc = lsm_inode_alloc(inode);876 int rc = lsm_inode_alloc(inode);