Skip to content

Commit 064fe6e

Browse files
committed
mount: handle mount propagation for detached mount trees
In commit ee2e3f5 ("mount: fix mounting of detached mounts onto targets that reside on shared mounts") I fixed a bug where propagating the source mount tree of an anonymous mount namespace into a target mount tree of a non-anonymous mount namespace could be used to trigger an integer overflow in the non-anonymous mount namespace causing any new mounts to fail. The cause of this was that the propagation algorithm was unable to recognize mounts from the source mount tree that were already propagated into the target mount tree and then reappeared as propagation targets when walking the destination propagation mount tree. When fixing this I disabled mount propagation into anonymous mount namespaces. Make it possible for anonymous mount namespace to receive mount propagation events correctly. This is no also a correctness issue now that we allow mounting detached mount trees onto detached mount trees. Mark the source anonymous mount namespace with MNTNS_PROPAGATING indicating that all mounts belonging to this mount namespace are currently in the process of being propagated and make the propagation algorithm discard those if they appear as propagation targets. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Christian Brauner <[email protected]>
1 parent 99b6a1d commit 064fe6e

File tree

4 files changed

+40
-21
lines changed

4 files changed

+40
-21
lines changed

fs/mount.h

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
#include <linux/ns_common.h>
66
#include <linux/fs_pin.h>
77

8+
extern struct list_head notify_list;
9+
10+
typedef __u32 __bitwise mntns_flags_t;
11+
12+
#define MNTNS_PROPAGATING ((__force mntns_flags_t)(1 << 0))
13+
814
struct mnt_namespace {
915
struct ns_common ns;
1016
struct mount * root;
@@ -27,6 +33,7 @@ struct mnt_namespace {
2733
struct rb_node mnt_ns_tree_node; /* node in the mnt_ns_tree */
2834
struct list_head mnt_ns_list; /* entry in the sequential list of mounts namespace */
2935
refcount_t passive; /* number references not pinning @mounts */
36+
mntns_flags_t mntns_flags;
3037
} __randomize_layout;
3138

3239
struct mnt_pcp {

fs/namespace.c

+27-15
Original file line numberDiff line numberDiff line change
@@ -3536,13 +3536,6 @@ static int do_move_mount(struct path *old_path,
35363536
if (!may_use_mount(p))
35373537
goto out;
35383538

3539-
/*
3540-
* Don't allow moving an attached mount tree to an anonymous
3541-
* mount tree.
3542-
*/
3543-
if (!is_anon_ns(ns) && is_anon_ns(p->mnt_ns))
3544-
goto out;
3545-
35463539
/* The thing moved must be mounted... */
35473540
if (!is_mounted(&old->mnt))
35483541
goto out;
@@ -3551,15 +3544,31 @@ static int do_move_mount(struct path *old_path,
35513544
if (!(attached ? check_mnt(old) : is_anon_ns(ns)))
35523545
goto out;
35533546

3554-
/*
3555-
* Ending up with two files referring to the root of the same
3556-
* anonymous mount namespace would cause an error as this would
3557-
* mean trying to move the same mount twice into the mount tree
3558-
* which would be rejected later. But be explicit about it right
3559-
* here.
3560-
*/
3561-
if (is_anon_ns(ns) && is_anon_ns(p->mnt_ns) && ns == p->mnt_ns)
3547+
if (is_anon_ns(ns)) {
3548+
/*
3549+
* Ending up with two files referring to the root of the
3550+
* same anonymous mount namespace would cause an error
3551+
* as this would mean trying to move the same mount
3552+
* twice into the mount tree which would be rejected
3553+
* later. But be explicit about it right here.
3554+
*/
3555+
if ((is_anon_ns(p->mnt_ns) && ns == p->mnt_ns))
3556+
goto out;
3557+
3558+
/*
3559+
* If this is an anonymous mount tree ensure that mount
3560+
* propagation can detect mounts that were just
3561+
* propagated to the target mount tree so we don't
3562+
* propagate onto them.
3563+
*/
3564+
ns->mntns_flags |= MNTNS_PROPAGATING;
3565+
} else if (is_anon_ns(p->mnt_ns)) {
3566+
/*
3567+
* Don't allow moving an attached mount tree to an
3568+
* anonymous mount tree.
3569+
*/
35623570
goto out;
3571+
}
35633572

35643573
if (old->mnt.mnt_flags & MNT_LOCKED)
35653574
goto out;
@@ -3603,6 +3612,9 @@ static int do_move_mount(struct path *old_path,
36033612
if (err)
36043613
goto out;
36053614

3615+
if (is_anon_ns(ns))
3616+
ns->mntns_flags &= ~MNTNS_PROPAGATING;
3617+
36063618
/* if the mount is moved, it should no longer be expire
36073619
* automatically */
36083620
list_del_init(&old->mnt_expire);

fs/pnode.c

+5-5
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_NEW(m) && !list_empty(&m->mnt_slave_list))
153+
if (!IS_MNT_PROPAGATED(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_NEW(m) && !list_empty(&m->mnt_slave_list))
177+
if (!IS_MNT_PROPAGATED(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_NEW(m) && !list_empty(&m->mnt_slave_list))
188+
if (!IS_MNT_PROPAGATED(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,7 +226,7 @@ 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_NEW(m))
229+
if (IS_MNT_PROPAGATED(m))
230230
return 0;
231231
/* skip if mountpoint isn't covered by it */
232232
if (!is_subdir(dest_mp->m_dentry, m->mnt.mnt_root))
@@ -380,7 +380,7 @@ bool propagation_would_overmount(const struct mount *from,
380380
if (!IS_MNT_SHARED(from))
381381
return false;
382382

383-
if (IS_MNT_NEW(to))
383+
if (IS_MNT_PROPAGATED(to))
384384
return false;
385385

386386
if (to->mnt.mnt_root != mp->m_dentry)

fs/pnode.h

+1-1
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_NEW(m) (!(m)->mnt_ns || is_anon_ns((m)->mnt_ns))
15+
#define IS_MNT_PROPAGATED(m) (!(m)->mnt_ns || ((m)->mnt_ns->mntns_flags & MNTNS_PROPAGATING))
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)