// SPDX-License-Identifier: GPL-2.0 #define _GNU_SOURCE #include #include #include #include #include #include #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