| From 1ab8904ae61b076d1242e1f48537698c77074b5c Mon Sep 17 00:00:00 2001 | |
| From: Christian Brauner <brauner@kernel.org> | |
| Date: Wed, 23 Sep 2026 14:27:53 +0200 | |
| Subject: mount: keep a copied mount unbindable | |
| From: Christian Brauner <brauner@kernel.org> | |
| commit 1ab8904ae61b076d1242e1f48537698c77074b5c upstream. | |
| It's groundhog day. | |
| MNT_UNBINDABLE used to be set in in mnt->mnt.mnt_flags and was not part | |
| of MNT_INTERNAL_FLAGS. clone_mnt() copied it with all the other flags to | |
| the new mount. This guaranteed that the copy of an unbindable mount | |
| became unbindable as well. Unbindable copies that ended up as shared | |
| lost the unbindable property. | |
| But then commit 406fea799925 ("mount: separate the flags accessed only | |
| under namespace_sem") moved MNT_UNBINDABLE from mnt->mnt.mnt_flags into | |
| mnt->mnt_t_flags as T_UNBINDABLE. | |
| clone_mnt() doesn't copy from mnt_t_flags and specifically doesn't copy | |
| T_UNBINDABLE. The only place a mount gets marked unbindable is in | |
| change_mnt_propagation() for MS_UNBINDABLE. | |
| This reintroduced an earlier bug we had already fixed. It resurfaces in | |
| copy_mnt_ns() which clones unbindable mounts via CL_COPY_UNBINDABLE. So | |
| since v6.17 a mount namespace created via clone(CLONE_NEWNS) or | |
| unshare(CLONE_NEWNS) contain private and bindable copies of every | |
| unbindable mount. The following snippet: | |
| mount --make-unbindable /mnt | |
| unshare -m --propagation unchanged | |
| mount --bind /mnt /tmp/x | |
| succeeds. This used to fail with EINVAL. This also applies to | |
| recursively binding a tree that contains an unbindable the mount. Such | |
| subtrees used to be pruned when they were moved onto a shared mount. | |
| And Documentation/filesystems/sharedsubtree.rst still says that the copy | |
| of an unbindable mount is unbindable. | |
| So once again let's fix this. Copy T_UNBINDABLE in clone_mnt(). Let | |
| set_mnt_shared() mask it off whenever a mount is made shared. | |
| This restores what the old MNT_INTERNAL_FLAGS mask did. | |
| Link: https://patch.msgid.link/20260923-work-mount-fixes-v1-1-f424cf8d3242@kernel.org | |
| Fixes: 406fea799925 ("mount: separate the flags accessed only under namespace_sem") | |
| Cc: stable@vger.kernel.org # v6.17+ | |
| Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org> | |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
| --- | |
| fs/namespace.c | 1 + | |
| 1 file changed, 1 insertion(+) | |
| --- a/fs/namespace.c | |
| +++ b/fs/namespace.c | |
| @@ -1254,6 +1254,7 @@ static struct mount *clone_mnt(struct mo | |
| mnt->mnt.mnt_flags = READ_ONCE(old->mnt.mnt_flags) & | |
| ~MNT_INTERNAL_FLAGS; | |
| + mnt->mnt_t_flags = old->mnt_t_flags & T_UNBINDABLE; | |
| if (flag & (CL_SLAVE | CL_PRIVATE)) | |
| mnt->mnt_group_id = 0; /* not a peer of original */ |