mirror of
https://github.com/torvalds/linux.git
synced 2026-10-13 05:41:02 +02:00
Merge patch series "Revert "put_mnt_ns(): leave mounts connected""
Christian Brauner <brauner@kernel.org> says:
Keeping every mount of a dying namespace attached to its parent changes
who owns it. An attached but unmounted mount is owned by its parent: the
parent's final mntput() is what drops the child's reference and takes
its superblock down. Before that commit only the namespace root was in
that position and every other mount dropped its own reference in
namespace_unlock().
That ownership rule turns any reference from a child's superblock back
to one of its ancestors into a cycle. The obvious case is a loop device:
unshare -m sh -c 'mount -o loop /var/tmp/img /var/tmp/mp'
mount(8) opens the image from inside the new namespace, so the loop
device's backing file pins that namespace's copy of the root mount.
When the namespace dies the loop mount stays attached to that copy and
is owned by it. The copy can't reach zero because the backing file
holds it. The backing file is only put once the ext4 superblock
releases the block device and autoclear runs, and that needs the loop
mount to go first. Nothing breaks the cycle. The superblock, the loop
device and, since the root copy keeps all of its children.
systemd-sysext sets up its loop devices in a private mount namespace and
relies on autoclear when that namespace goes away, which is how this was
found. Anything that holds a file on an ancestor from a mounted
filesystem has the same problem. That includes ecryptfs lower paths,
erofs file-backed mounts, fuse passthrough backing files.
That's a bigger fix and not an -rc change. Revert.
* patches from https://patch.msgid.link/20260917-work-put_mnt_ns-revert-v1-0-34d9b8679e68@kernel.org:
Revert "put_mnt_ns(): leave mounts connected"
Revert "selftests/filesystems: add mntns cleanup test"
Link: https://patch.msgid.link/20260917-work-put_mnt_ns-revert-v1-0-34d9b8679e68@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
commit
fabd324212
|
|
@ -6301,7 +6301,7 @@ void put_mnt_ns(struct mnt_namespace *ns)
|
|||
guard(namespace_excl)();
|
||||
emptied_ns = ns;
|
||||
guard(mount_writer)();
|
||||
umount_tree(ns->root, UMOUNT_CONNECTED);
|
||||
umount_tree(ns->root, 0);
|
||||
}
|
||||
|
||||
struct vfsmount *kern_mount(struct file_system_type *type)
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ TARGETS += filesystems/move_mount
|
|||
TARGETS += filesystems/empty_mntns
|
||||
TARGETS += filesystems/fsmount_ns
|
||||
TARGETS += filesystems/fscontext_ns
|
||||
TARGETS += filesystems/mntns_cleanup
|
||||
TARGETS += filesystems/xattr
|
||||
TARGETS += firmware
|
||||
TARGETS += fpu
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
mntns_cleanup_test
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
TEST_GEN_PROGS := mntns_cleanup_test
|
||||
|
||||
CFLAGS += -Wall -O2 -g $(KHDR_INCLUDES)
|
||||
|
||||
include ../../lib.mk
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../../kselftest_harness.h"
|
||||
|
||||
FIXTURE(mntns_cleanup) {
|
||||
};
|
||||
|
||||
FIXTURE_SETUP(mntns_cleanup)
|
||||
{
|
||||
if (geteuid() != 0)
|
||||
SKIP(return, "test requires CAP_SYS_ADMIN");
|
||||
|
||||
ASSERT_EQ(unshare(CLONE_NEWNS), 0);
|
||||
ASSERT_EQ(mount("", "/", NULL, MS_REC | MS_PRIVATE, NULL), 0);
|
||||
|
||||
rmdir("/mnt_dir");
|
||||
ASSERT_EQ(mkdir("/mnt_dir", 0755), 0);
|
||||
ASSERT_EQ(mount("tmpfs", "/mnt_dir", "tmpfs", 0, NULL), 0);
|
||||
ASSERT_EQ(mkdir("/mnt_dir/hidden", 0755), 0);
|
||||
ASSERT_EQ(mkdir("/mnt_dir/hidden/secret", 0755), 0);
|
||||
ASSERT_EQ(mount("tmpfs", "/mnt_dir/hidden", "tmpfs", 0, NULL), 0);
|
||||
}
|
||||
|
||||
FIXTURE_TEARDOWN(mntns_cleanup)
|
||||
{
|
||||
}
|
||||
|
||||
/* Mounts must stay connected when a mount namespace is cleaned up. */
|
||||
TEST_F(mntns_cleanup, keeps_mounts_connected)
|
||||
{
|
||||
int fd, sfd, err;
|
||||
|
||||
fd = open("/mnt_dir", O_PATH | O_DIRECTORY | O_CLOEXEC);
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
/* Destroy the namespace; the fd keeps /mnt_dir alive. */
|
||||
ASSERT_EQ(unshare(CLONE_NEWNS), 0);
|
||||
|
||||
sfd = openat(fd, "hidden/secret", O_RDONLY);
|
||||
err = errno;
|
||||
if (sfd >= 0)
|
||||
close(sfd);
|
||||
close(fd);
|
||||
|
||||
ASSERT_LT(sfd, 0)
|
||||
TH_LOG("mount namespace teardown revealed what the overmount covered");
|
||||
ASSERT_EQ(err, ENOENT);
|
||||
}
|
||||
|
||||
TEST_HARNESS_MAIN
|
||||
Loading…
Reference in New Issue
Block a user