@@ -2539,72 +2539,81 @@ static inline int tree_contains_unbindable(struct mount *mnt)
25392539 return 0 ;
25402540}
25412541
2542- static int do_move_mount (struct path * path , const char * old_name )
2542+ static int do_move_mount (struct path * old_path , struct path * new_path )
25432543{
2544- struct path old_path , parent_path ;
2544+ struct path parent_path = {. mnt = NULL , . dentry = NULL } ;
25452545 struct mount * p ;
25462546 struct mount * old ;
25472547 struct mountpoint * mp ;
25482548 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 ;
25542549
2555- mp = lock_mount (path );
2556- err = PTR_ERR (mp );
2550+ mp = lock_mount (new_path );
25572551 if (IS_ERR (mp ))
2558- goto out ;
2552+ return PTR_ERR ( mp ) ;
25592553
2560- old = real_mount (old_path . mnt );
2561- p = real_mount (path -> mnt );
2554+ old = real_mount (old_path -> mnt );
2555+ p = real_mount (new_path -> mnt );
25622556
25632557 err = - EINVAL ;
25642558 if (!check_mnt (p ) || !check_mnt (old ))
2565- goto out1 ;
2559+ goto out ;
25662560
2567- if (old -> mnt . mnt_flags & MNT_LOCKED )
2568- goto out1 ;
2561+ if (! mnt_has_parent ( old ) )
2562+ goto out ;
25692563
2570- err = - EINVAL ;
2571- if (old_path .dentry != old_path .mnt -> mnt_root )
2572- goto out1 ;
2564+ if (old -> mnt .mnt_flags & MNT_LOCKED )
2565+ goto out ;
25732566
2574- if (! mnt_has_parent ( old ) )
2575- goto out1 ;
2567+ if (old_path -> dentry != old_path -> mnt -> mnt_root )
2568+ goto out ;
25762569
2577- if (d_is_dir (path -> dentry ) !=
2578- d_is_dir (old_path . dentry ))
2579- goto out1 ;
2570+ if (d_is_dir (new_path -> dentry ) !=
2571+ d_is_dir (old_path -> dentry ))
2572+ goto out ;
25802573 /*
25812574 * Don't move a mount residing in a shared parent.
25822575 */
25832576 if (IS_MNT_SHARED (old -> mnt_parent ))
2584- goto out1 ;
2577+ goto out ;
25852578 /*
25862579 * Don't move a mount tree containing unbindable mounts to a destination
25872580 * mount which is shared.
25882581 */
25892582 if (IS_MNT_SHARED (p ) && tree_contains_unbindable (old ))
2590- goto out1 ;
2583+ goto out ;
25912584 err = - ELOOP ;
25922585 for (; mnt_has_parent (p ); p = p -> mnt_parent )
25932586 if (p == old )
2594- goto out1 ;
2587+ goto out ;
25952588
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 );
25972591 if (err )
2598- goto out1 ;
2592+ goto out ;
25992593
26002594 /* if the mount is moved, it should no longer be expire
26012595 * automatically */
26022596 list_del_init (& old -> mnt_expire );
2603- out1 :
2604- unlock_mount (mp );
26052597out :
2598+ unlock_mount (mp );
26062599 if (!err )
26072600 path_put (& parent_path );
2601+ return err ;
2602+ }
2603+
2604+ static 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 );
26082617 path_put (& old_path );
26092618 return err ;
26102619}
@@ -3050,7 +3059,7 @@ long do_mount(const char *dev_name, const char __user *dir_name,
30503059 else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE ))
30513060 retval = do_change_type (& path , flags );
30523061 else if (flags & MS_MOVE )
3053- retval = do_move_mount (& path , dev_name );
3062+ retval = do_move_mount_old (& path , dev_name );
30543063 else
30553064 retval = do_new_mount (& path , type_page , sb_flags , mnt_flags ,
30563065 dev_name , data_page );
@@ -3278,6 +3287,61 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
32783287 return ksys_mount (dev_name , dir_name , type , flags , data );
32793288}
32803289
3290+ /*
3291+ * Move a mount from one place to another.
3292+ *
3293+ * Note the flags value is a combination of MOVE_MOUNT_* flags.
3294+ */
3295+ SYSCALL_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+
3338+ out_to :
3339+ path_put (& to_path );
3340+ out_from :
3341+ path_put (& from_path );
3342+ return ret ;
3343+ }
3344+
32813345/*
32823346 * Return true if path is reachable from root
32833347 *
0 commit comments