Skip to content

Commit 35b574a

Browse files
committed
Merge tag 'pull-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull mount fixes from Al Viro: "Various mount-related bugfixes: - split the do_move_mount() checks in subtree-of-our-ns and entire-anon cases and adapt detached mount propagation selftest for mount_setattr - allow clone_private_mount() for a path on real rootfs - fix a race in call of has_locked_children() - fix move_mount propagation graph breakage by MOVE_MOUNT_SET_GROUP - make sure clone_private_mnt() caller has CAP_SYS_ADMIN in the right userns - avoid false negatives in path_overmount() - don't leak MNT_LOCKED from parent to child in finish_automount() - do_change_type(): refuse to operate on unmounted/not ours mounts" * tag 'pull-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: do_change_type(): refuse to operate on unmounted/not ours mounts clone_private_mnt(): make sure that caller has CAP_SYS_ADMIN in the right userns selftests/mount_setattr: adapt detached mount propagation test do_move_mount(): split the checks in subtree-of-our-ns and entire-anon cases fs: allow clone_private_mount() for a path on real rootfs fix propagation graph breakage by MOVE_MOUNT_SET_GROUP move_mount(2) finish_automount(): don't leak MNT_LOCKED from parent to child path_overmount(): avoid false negatives fs/fhandle.c: fix a race in call of has_locked_children()
2 parents 522cd6a + 12f147d commit 35b574a

File tree

3 files changed

+74
-59
lines changed

3 files changed

+74
-59
lines changed

fs/namespace.c

Lines changed: 71 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
34593479
static 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

include/linux/mount.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ enum mount_flags {
6565
MNT_ATIME_MASK = MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME,
6666

6767
MNT_INTERNAL_FLAGS = MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL |
68-
MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED,
68+
MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED |
69+
MNT_LOCKED,
6970
};
7071

7172
struct vfsmount {

tools/testing/selftests/mount_setattr/mount_setattr_test.c

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,24 +2079,9 @@ TEST_F(mount_setattr, detached_tree_propagation)
20792079
* means that the device information will be different for any
20802080
* statx() that was taken from /mnt/A before the mount compared
20812081
* to one after the mount.
2082-
*
2083-
* Since we already now that the device information between the
2084-
* stx1 and stx2 samples are identical we also now that stx2 and
2085-
* stx3 device information will necessarily differ.
20862082
*/
20872083
ASSERT_NE(stx1.stx_dev_minor, stx3.stx_dev_minor);
2088-
2089-
/*
2090-
* If mount propagation worked correctly then the tmpfs mount
2091-
* that was created after the mount namespace was unshared will
2092-
* have propagated onto /mnt/A in the detached mount tree.
2093-
*
2094-
* Verify that the device information for stx3 and stx4 are
2095-
* identical. It is already established that stx3 is different
2096-
* from both stx1 and stx2 sampled before the tmpfs mount was
2097-
* done so if stx3 and stx4 are identical the proof is done.
2098-
*/
2099-
ASSERT_EQ(stx3.stx_dev_minor, stx4.stx_dev_minor);
2084+
ASSERT_EQ(stx1.stx_dev_minor, stx4.stx_dev_minor);
21002085

21012086
EXPECT_EQ(close(fd_tree), 0);
21022087
}

0 commit comments

Comments
 (0)