Don't propagate mounts into detached trees
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 23 May 2025 23:20:36 +0000 (19:20 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 26 May 2025 21:35:32 +0000 (17:35 -0400)
All versions up to 6.14 did not propagate mount events into detached
tree.  Shortly after 6.14 a merge of vfs-6.15-rc1.mount.namespace
(130e696aa68b) has changed that.

Unfortunately, that has caused userland regressions (reported in
https://lore.kernel.org/all/CAOYeF9WQhFDe+BGW=Dp5fK8oRy5AgZ6zokVyTj1Wp4EUiYgt4w@mail.gmail.com/)

Straight revert wouldn't be an option - in particular, the variant in 6.14
had a bug that got fixed in d1ddc6f1d9f0 ("fix IS_MNT_PROPAGATING uses")
and we don't want to bring the bug back.

This is a modification of manual revert posted by Christian, with changes
needed to avoid reintroducing the breakage in scenario described in
d1ddc6f1d9f0.

Cc: stable@vger.kernel.org
Reported-by: Allison Karlitskaya <lis@redhat.com>
Tested-by: Allison Karlitskaya <lis@redhat.com>
Acked-by: Christian Brauner <brauner@kernel.org>
Co-developed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/mount.h
fs/namespace.c
fs/pnode.c

index 7aecf2a6047232557cda2d3d5df69285a63609d6..ad7173037924a86c8302fee2219e02163e5c2c7a 100644 (file)
@@ -7,10 +7,6 @@
 
 extern struct list_head notify_list;
 
-typedef __u32 __bitwise mntns_flags_t;
-
-#define MNTNS_PROPAGATING      ((__force mntns_flags_t)(1 << 0))
-
 struct mnt_namespace {
        struct ns_common        ns;
        struct mount *  root;
@@ -37,7 +33,6 @@ struct mnt_namespace {
        struct rb_node          mnt_ns_tree_node; /* node in the mnt_ns_tree */
        struct list_head        mnt_ns_list; /* entry in the sequential list of mounts namespace */
        refcount_t              passive; /* number references not pinning @mounts */
-       mntns_flags_t           mntns_flags;
 } __randomize_layout;
 
 struct mnt_pcp {
index 1b466c54a357d1216bc44bc8705ff368342b55b5..623cd110076dcd97d5c9e94a2de2c9f6d6faf944 100644 (file)
@@ -3648,7 +3648,7 @@ static int do_move_mount(struct path *old_path,
        if (!(attached ? check_mnt(old) : is_anon_ns(ns)))
                goto out;
 
-       if (is_anon_ns(ns)) {
+       if (is_anon_ns(ns) && ns == p->mnt_ns) {
                /*
                 * Ending up with two files referring to the root of the
                 * same anonymous mount namespace would cause an error
@@ -3656,16 +3656,7 @@ static int do_move_mount(struct path *old_path,
                 * twice into the mount tree which would be rejected
                 * later. But be explicit about it right here.
                 */
-               if ((is_anon_ns(p->mnt_ns) && ns == p->mnt_ns))
-                       goto out;
-
-               /*
-                * If this is an anonymous mount tree ensure that mount
-                * propagation can detect mounts that were just
-                * propagated to the target mount tree so we don't
-                * propagate onto them.
-                */
-               ns->mntns_flags |= MNTNS_PROPAGATING;
+               goto out;
        } else if (is_anon_ns(p->mnt_ns)) {
                /*
                 * Don't allow moving an attached mount tree to an
@@ -3722,8 +3713,6 @@ static int do_move_mount(struct path *old_path,
        if (attached)
                put_mountpoint(old_mp);
 out:
-       if (is_anon_ns(ns))
-               ns->mntns_flags &= ~MNTNS_PROPAGATING;
        unlock_mount(mp);
        if (!err) {
                if (attached) {
index fb77427df39e2eebdc44f0bf4137f1821bdf51a6..ffd429b760d5d422477c524b3ef14d825f131fb1 100644 (file)
@@ -231,8 +231,8 @@ static int propagate_one(struct mount *m, struct mountpoint *dest_mp)
        /* skip if mountpoint isn't visible in m */
        if (!is_subdir(dest_mp->m_dentry, m->mnt.mnt_root))
                return 0;
-       /* skip if m is in the anon_ns we are emptying */
-       if (m->mnt_ns->mntns_flags & MNTNS_PROPAGATING)
+       /* skip if m is in the anon_ns */
+       if (is_anon_ns(m->mnt_ns))
                return 0;
 
        if (peers(m, last_dest)) {