@@ -2410,7 +2410,7 @@ void drop_collected_mounts(struct vfsmount *mnt)
24102410 namespace_unlock ();
24112411}
24122412
2413- bool has_locked_children (struct mount * mnt , struct dentry * dentry )
2413+ static bool __has_locked_children (struct mount * mnt , struct dentry * dentry )
24142414{
24152415 struct mount * child ;
24162416
@@ -2424,6 +2424,16 @@ bool has_locked_children(struct mount *mnt, struct dentry *dentry)
24242424 return false;
24252425}
24262426
2427+ bool has_locked_children (struct mount * mnt , struct dentry * dentry )
2428+ {
2429+ bool res ;
2430+
2431+ read_seqlock_excl (& mount_lock );
2432+ res = __has_locked_children (mnt , dentry );
2433+ read_sequnlock_excl (& mount_lock );
2434+ return res ;
2435+ }
2436+
24272437/*
24282438 * Check that there aren't references to earlier/same mount namespaces in the
24292439 * specified subtree. Such references can act as pins for mount namespaces
@@ -2468,23 +2478,27 @@ struct vfsmount *clone_private_mount(const struct path *path)
24682478 if (IS_MNT_UNBINDABLE (old_mnt ))
24692479 return ERR_PTR (- EINVAL );
24702480
2471- if (mnt_has_parent (old_mnt )) {
2472- if (!check_mnt (old_mnt ))
2473- return ERR_PTR (- EINVAL );
2474- } else {
2475- if (!is_mounted (& old_mnt -> mnt ))
2476- return ERR_PTR (- EINVAL );
2477-
2478- /* Make sure this isn't something purely kernel internal. */
2479- if (!is_anon_ns (old_mnt -> mnt_ns ))
2481+ /*
2482+ * Make sure the source mount is acceptable.
2483+ * Anything mounted in our mount namespace is allowed.
2484+ * Otherwise, it must be the root of an anonymous mount
2485+ * namespace, and we need to make sure no namespace
2486+ * loops get created.
2487+ */
2488+ if (!check_mnt (old_mnt )) {
2489+ if (!is_mounted (& old_mnt -> mnt ) ||
2490+ !is_anon_ns (old_mnt -> mnt_ns ) ||
2491+ mnt_has_parent (old_mnt ))
24802492 return ERR_PTR (- EINVAL );
24812493
2482- /* Make sure we don't create mount namespace loops. */
24832494 if (!check_for_nsfs_mounts (old_mnt ))
24842495 return ERR_PTR (- EINVAL );
24852496 }
24862497
2487- if (has_locked_children (old_mnt , path -> dentry ))
2498+ if (!ns_capable (old_mnt -> mnt_ns -> user_ns , CAP_SYS_ADMIN ))
2499+ return ERR_PTR (- EPERM );
2500+
2501+ if (__has_locked_children (old_mnt , path -> dentry ))
24882502 return ERR_PTR (- EINVAL );
24892503
24902504 new_mnt = clone_mnt (old_mnt , path -> dentry , CL_PRIVATE );
@@ -2930,6 +2944,10 @@ static int do_change_type(struct path *path, int ms_flags)
29302944 return - EINVAL ;
29312945
29322946 namespace_lock ();
2947+ if (!check_mnt (mnt )) {
2948+ err = - EINVAL ;
2949+ goto out_unlock ;
2950+ }
29332951 if (type == MS_SHARED ) {
29342952 err = invent_group_ids (mnt , recurse );
29352953 if (err )
@@ -3021,7 +3039,7 @@ static struct mount *__do_loopback(struct path *old_path, int recurse)
30213039 if (!may_copy_tree (old_path ))
30223040 return mnt ;
30233041
3024- if (!recurse && has_locked_children (old , old_path -> dentry ))
3042+ if (!recurse && __has_locked_children (old , old_path -> dentry ))
30253043 return mnt ;
30263044
30273045 if (recurse )
@@ -3414,7 +3432,7 @@ static int do_set_group(struct path *from_path, struct path *to_path)
34143432 goto out ;
34153433
34163434 /* From mount should not have locked children in place of To's root */
3417- if (has_locked_children (from , to -> mnt .mnt_root ))
3435+ if (__has_locked_children (from , to -> mnt .mnt_root ))
34183436 goto out ;
34193437
34203438 /* Setting sharing groups is only allowed on private mounts */
@@ -3428,7 +3446,7 @@ static int do_set_group(struct path *from_path, struct path *to_path)
34283446 if (IS_MNT_SLAVE (from )) {
34293447 struct mount * m = from -> mnt_master ;
34303448
3431- list_add (& to -> mnt_slave , & m -> mnt_slave_list );
3449+ list_add (& to -> mnt_slave , & from -> mnt_slave );
34323450 to -> mnt_master = m ;
34333451 }
34343452
@@ -3453,18 +3471,25 @@ static int do_set_group(struct path *from_path, struct path *to_path)
34533471 * Check if path is overmounted, i.e., if there's a mount on top of
34543472 * @path->mnt with @path->dentry as mountpoint.
34553473 *
3456- * Context: This function expects namespace_lock() to be held.
3474+ * Context: namespace_sem must be held at least shared.
3475+ * MUST NOT be called under lock_mount_hash() (there one should just
3476+ * call __lookup_mnt() and check if it returns NULL).
34573477 * Return: If path is overmounted true is returned, false if not.
34583478 */
34593479static inline bool path_overmounted (const struct path * path )
34603480{
3481+ unsigned seq = read_seqbegin (& mount_lock );
3482+ bool no_child ;
3483+
34613484 rcu_read_lock ();
3462- if (unlikely (__lookup_mnt (path -> mnt , path -> dentry ))) {
3463- rcu_read_unlock ();
3464- return true;
3465- }
3485+ no_child = !__lookup_mnt (path -> mnt , path -> dentry );
34663486 rcu_read_unlock ();
3467- return false;
3487+ if (need_seqretry (& mount_lock , seq )) {
3488+ read_seqlock_excl (& mount_lock );
3489+ no_child = !__lookup_mnt (path -> mnt , path -> dentry );
3490+ read_sequnlock_excl (& mount_lock );
3491+ }
3492+ return unlikely (!no_child );
34683493}
34693494
34703495/**
@@ -3623,37 +3648,41 @@ static int do_move_mount(struct path *old_path,
36233648 ns = old -> mnt_ns ;
36243649
36253650 err = - EINVAL ;
3626- if (!may_use_mount (p ))
3627- goto out ;
3628-
36293651 /* The thing moved must be mounted... */
36303652 if (!is_mounted (& old -> mnt ))
36313653 goto out ;
36323654
3633- /* ... and either ours or the root of anon namespace */
3634- if (!(attached ? check_mnt (old ) : is_anon_ns (ns )))
3635- goto out ;
3636-
3637- if (is_anon_ns (ns ) && ns == p -> mnt_ns ) {
3655+ if (check_mnt (old )) {
3656+ /* if the source is in our namespace... */
3657+ /* ... it should be detachable from parent */
3658+ if (!mnt_has_parent (old ) || IS_MNT_LOCKED (old ))
3659+ goto out ;
3660+ /* ... and the target should be in our namespace */
3661+ if (!check_mnt (p ))
3662+ goto out ;
3663+ } else {
36383664 /*
3639- * Ending up with two files referring to the root of the
3640- * same anonymous mount namespace would cause an error
3641- * as this would mean trying to move the same mount
3642- * twice into the mount tree which would be rejected
3643- * later. But be explicit about it right here.
3665+ * otherwise the source must be the root of some anon namespace.
3666+ * AV: check for mount being root of an anon namespace is worth
3667+ * an inlined predicate...
36443668 */
3645- goto out ;
3646- } else if ( is_anon_ns ( p -> mnt_ns )) {
3669+ if (! is_anon_ns ( ns ) || mnt_has_parent ( old ))
3670+ goto out ;
36473671 /*
3648- * Don't allow moving an attached mount tree to an
3649- * anonymous mount tree.
3672+ * Bail out early if the target is within the same namespace -
3673+ * subsequent checks would've rejected that, but they lose
3674+ * some corner cases if we check it early.
36503675 */
3651- goto out ;
3676+ if (ns == p -> mnt_ns )
3677+ goto out ;
3678+ /*
3679+ * Target should be either in our namespace or in an acceptable
3680+ * anon namespace, sensu check_anonymous_mnt().
3681+ */
3682+ if (!may_use_mount (p ))
3683+ goto out ;
36523684 }
36533685
3654- if (old -> mnt .mnt_flags & MNT_LOCKED )
3655- goto out ;
3656-
36573686 if (!path_mounted (old_path ))
36583687 goto out ;
36593688
0 commit comments