Skip to content

Commit acbf235

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: "A couple of races around legalize_mnt vs umount (both fairly old and hard to hit) plus two bugs in move_mount(2) - both around 'move detached subtree in place' logics" * tag 'pull-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: fix IS_MNT_PROPAGATING uses do_move_mount(): don't leak MNTNS_PROPAGATING on failures do_umount(): add missing barrier before refcount checks in sync case __legitimize_mnt(): check for MNT_SYNC_UMOUNT should be under mount_lock
2 parents 1a33418 + d1ddc6f commit acbf235

File tree

3 files changed

+17
-19
lines changed

3 files changed

+17
-19
lines changed

fs/namespace.c

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -787,15 +787,11 @@ int __legitimize_mnt(struct vfsmount *bastard, unsigned seq)
787787
return 0;
788788
mnt = real_mount(bastard);
789789
mnt_add_count(mnt, 1);
790-
smp_mb(); // see mntput_no_expire()
790+
smp_mb(); // see mntput_no_expire() and do_umount()
791791
if (likely(!read_seqretry(&mount_lock, seq)))
792792
return 0;
793-
if (bastard->mnt_flags & MNT_SYNC_UMOUNT) {
794-
mnt_add_count(mnt, -1);
795-
return 1;
796-
}
797793
lock_mount_hash();
798-
if (unlikely(bastard->mnt_flags & MNT_DOOMED)) {
794+
if (unlikely(bastard->mnt_flags & (MNT_SYNC_UMOUNT | MNT_DOOMED))) {
799795
mnt_add_count(mnt, -1);
800796
unlock_mount_hash();
801797
return 1;
@@ -2048,6 +2044,7 @@ static int do_umount(struct mount *mnt, int flags)
20482044
umount_tree(mnt, UMOUNT_PROPAGATE);
20492045
retval = 0;
20502046
} else {
2047+
smp_mb(); // paired with __legitimize_mnt()
20512048
shrink_submounts(mnt);
20522049
retval = -EBUSY;
20532050
if (!propagate_mount_busy(mnt, 2)) {
@@ -3560,7 +3557,8 @@ static int can_move_mount_beneath(const struct path *from,
35603557
* @mnt_from itself. This defeats the whole purpose of mounting
35613558
* @mnt_from beneath @mnt_to.
35623559
*/
3563-
if (propagation_would_overmount(parent_mnt_to, mnt_from, mp))
3560+
if (check_mnt(mnt_from) &&
3561+
propagation_would_overmount(parent_mnt_to, mnt_from, mp))
35643562
return -EINVAL;
35653563

35663564
return 0;
@@ -3718,15 +3716,14 @@ static int do_move_mount(struct path *old_path,
37183716
if (err)
37193717
goto out;
37203718

3721-
if (is_anon_ns(ns))
3722-
ns->mntns_flags &= ~MNTNS_PROPAGATING;
3723-
37243719
/* if the mount is moved, it should no longer be expire
37253720
* automatically */
37263721
list_del_init(&old->mnt_expire);
37273722
if (attached)
37283723
put_mountpoint(old_mp);
37293724
out:
3725+
if (is_anon_ns(ns))
3726+
ns->mntns_flags &= ~MNTNS_PROPAGATING;
37303727
unlock_mount(mp);
37313728
if (!err) {
37323729
if (attached) {

fs/pnode.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ static struct mount *propagation_next(struct mount *m,
150150
struct mount *origin)
151151
{
152152
/* are there any slaves of this mount? */
153-
if (!IS_MNT_PROPAGATED(m) && !list_empty(&m->mnt_slave_list))
153+
if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
154154
return first_slave(m);
155155

156156
while (1) {
@@ -174,7 +174,7 @@ static struct mount *skip_propagation_subtree(struct mount *m,
174174
* Advance m such that propagation_next will not return
175175
* the slaves of m.
176176
*/
177-
if (!IS_MNT_PROPAGATED(m) && !list_empty(&m->mnt_slave_list))
177+
if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
178178
m = last_slave(m);
179179

180180
return m;
@@ -185,7 +185,7 @@ static struct mount *next_group(struct mount *m, struct mount *origin)
185185
while (1) {
186186
while (1) {
187187
struct mount *next;
188-
if (!IS_MNT_PROPAGATED(m) && !list_empty(&m->mnt_slave_list))
188+
if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
189189
return first_slave(m);
190190
next = next_peer(m);
191191
if (m->mnt_group_id == origin->mnt_group_id) {
@@ -226,11 +226,15 @@ static int propagate_one(struct mount *m, struct mountpoint *dest_mp)
226226
struct mount *child;
227227
int type;
228228
/* skip ones added by this propagate_mnt() */
229-
if (IS_MNT_PROPAGATED(m))
229+
if (IS_MNT_NEW(m))
230230
return 0;
231-
/* skip if mountpoint isn't covered by it */
231+
/* skip if mountpoint isn't visible in m */
232232
if (!is_subdir(dest_mp->m_dentry, m->mnt.mnt_root))
233233
return 0;
234+
/* skip if m is in the anon_ns we are emptying */
235+
if (m->mnt_ns->mntns_flags & MNTNS_PROPAGATING)
236+
return 0;
237+
234238
if (peers(m, last_dest)) {
235239
type = CL_MAKE_SHARED;
236240
} else {
@@ -380,9 +384,6 @@ bool propagation_would_overmount(const struct mount *from,
380384
if (!IS_MNT_SHARED(from))
381385
return false;
382386

383-
if (IS_MNT_PROPAGATED(to))
384-
return false;
385-
386387
if (to->mnt.mnt_root != mp->m_dentry)
387388
return false;
388389

fs/pnode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
#define IS_MNT_SHARED(m) ((m)->mnt.mnt_flags & MNT_SHARED)
1414
#define IS_MNT_SLAVE(m) ((m)->mnt_master)
15-
#define IS_MNT_PROPAGATED(m) (!(m)->mnt_ns || ((m)->mnt_ns->mntns_flags & MNTNS_PROPAGATING))
15+
#define IS_MNT_NEW(m) (!(m)->mnt_ns)
1616
#define CLEAR_MNT_SHARED(m) ((m)->mnt.mnt_flags &= ~MNT_SHARED)
1717
#define IS_MNT_UNBINDABLE(m) ((m)->mnt.mnt_flags & MNT_UNBINDABLE)
1818
#define IS_MNT_MARKED(m) ((m)->mnt.mnt_flags & MNT_MARKED)

0 commit comments

Comments
 (0)