FAILED: patch "[PATCH] namespace: never expire a locked mount" failed to apply to 6.12-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x f78ddcc872248c7aa1d7e904928441a0be4c6d5d
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026101225-upon-doorknob-a385@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From f78ddcc872248c7aa1d7e904928441a0be4c6d5d Mon Sep 17 00:00:00 2001
From: Christian Brauner <[email protected]>
Date: Fri, 2 Oct 2026 15:52:39 +0200
Subject: [PATCH] namespace: never expire a locked mount
Locked mounts are special. They protect the underlying files and directories from being revealed. do_umount() refuses to unmount locked mounts but shrink_submounts() doesn't.
A shrinkable mount can become locked once the owner of a user namespace puts it beneath a locked mount with MOVE_MOUNT_BENEATH. The locked property now moves to the mount at the bottom making it possible to unmount the top mount.
So umount() of an unlocked ancestor now expires the bottom mount first and the covered directory is revealed:
move_mount(c -> x/hidden, MOVE_MOUNT_BENEATH) = 0
the cover after the lock moved: umount2(x/hidden) = 0 the holder of the lock: umount2(x/hidden) = EINVAL the root of the copy, busy: umount2(x) = EBUSY
reads x/hidden/secret: "covered-by-root"
So leave a locked mount alone as it dies together with its parent. A plain umount() of an unlocked mount with a locked one below it is EBUSY from now on. It's the same for any other locked child. A lazy umount still takes the whole tree.
mark_mounts_for_expiry() never sees a locked mount. lock_mnt_tree() leaves a mount on an expiry list alone and nothing else puts a locked one on such a list. Add an assert for this.
fs/namespace.c +4 -1
@@ -4032,6 +4032,8 @@ void mark_mounts_for_expiry(struct list_head *mounts)list_for_each_entry_safe (mnt, next, mounts, mnt_expire) {if (!is_mounted (&mnt->mnt))continue ; +/* lock_mnt_tree() leaves expirable mounts alone */ +VFS_WARN_ON_ONCE (IS_MNT_LOCKED (mnt));if (!xchg (&mnt->mnt_expiry_mark,1 ) ||propagate_mount_busy (mnt,1 ))continue ;
@@ -4058,7 +4060,8 @@ EXPORT_SYMBOL_GPL(mark_mounts_for_expiry);*/ static bool shrink_submount (struct mount *mnt) { -if (propagate_mount_busy (mnt,1 )) +/* not the kernel's to remove either */ +if (IS_MNT_LOCKED (mnt) ||propagate_mount_busy (mnt,1 ))return false;touch_mnt_namespace (mnt->mnt_ns);umount_tree (mnt,UMOUNT_PROPAGATE |UMOUNT_SYNC );