From: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Subject: Re: [Devel] [PATCH vz10 2/2] selftests/ve: check that hiding an entry does not unmount it
Date: Tue, 25 Aug 2026 17:40:27 +0200 [thread overview]
Message-ID: <1e09adbd-f820-482b-9c48-814e4d62f5be@virtuozzo.com> (raw)
In-Reply-To: <20260825133013.704924-3-mirian.shilakadze@virtuozzo.com>
On 8/25/26 15:29, Mirian Shilakadze wrote:
> kernfs_dop_revalidate() answered the per VE visibility check with the same
> "return 0" the staleness checks use, and the VFS reads 0 as a global fact:
> d_invalidate() hands every mountpoint under that dentry to
> __detach_mounts(), whose mountpoint hash is not scoped to a mount
> namespace. A single lookup from inside a Container unmounted the host's
> bpffs, and libvzctl needs bpffs for the cgroup v2 device controller, so
> the whole node stopped being manageable.
>
> Mount a tmpfs on the entry the variant already keeps host only, look it up
> from inside a VE, and require both that the VE is told ENOENT and that the
> mount is still there afterwards. The mount is made in the test's own
> mount namespace so the machine running the test cannot lose a mount it
> needs, while the dentry the mount hangs on is still the shared one the bug
> worked through.
>
> Fails without the preceding fix, on both the sysfs and the proc variant.
>
> Feature: kernfs: per-CT entries visibility and permissions configuration
> https://virtuozzo.atlassian.net/browse/VSTOR-142552
> Signed-off-by: Mirian Shilakadze <mirian.shilakadze@virtuozzo.com>
> ---
> tools/testing/selftests/ve/ve_perms_test.c | 52 ++++++++++++++++++++++
> tools/testing/selftests/ve/ve_selftest.h | 27 ++++++++++-
> 2 files changed, 77 insertions(+), 2 deletions(-)
>
> diff --git a/tools/testing/selftests/ve/ve_perms_test.c b/tools/testing/selftests/ve/ve_perms_test.c
> index 4522950c17f2..25ffbd42c380 100644
> --- a/tools/testing/selftests/ve/ve_perms_test.c
> +++ b/tools/testing/selftests/ve/ve_perms_test.c
> @@ -24,6 +24,7 @@
> #include <unistd.h>
> #include <fcntl.h>
> #include <limits.h>
> +#include <sys/mount.h>
> #include <sys/wait.h>
> #include <errno.h>
>
> @@ -412,4 +413,55 @@ TEST_F(ve_perms, enforce_denies)
> absent, O_RDONLY), EACCES);
> }
>
> +/*
> + * Looking up an entry that a VE cannot see must not disturb a mount that
> + * sits on it.
> + *
> + * The lookup used to answer "this dentry is stale" where it meant "this name
> + * is not here for you", and the VFS acts on stale globally: d_invalidate()
> + * detaches every mount on that dentry in every mount namespace. One lookup
> + * from inside a Container took the host's bpffs and tracefs with it.
> + *
> + * The tmpfs is mounted in the test's own mount namespace, so the machine
> + * running this cannot lose a mount it needs, while the dentry the mount hangs
> + * on is still the shared one the bug worked through.
> + */
> +TEST_F(ve_perms, hidden_entry_keeps_its_mount)
> +{
> + char path[PATH_MAX];
> + int status;
> + pid_t pid;
> +
> + if (!entry_present(variant->dir_prefix, variant->dir))
> + SKIP(return, "%s/%s absent", variant->dir_prefix, variant->dir);
> + snprintf(path, sizeof(path), "%s/%s", variant->dir_prefix, variant->dir);
> +
> + pid = fork();
> + ASSERT_GE(pid, 0);
> + if (pid == 0) {
> + if (unshare(CLONE_NEWNS) != 0 ||
> + mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0 ||
> + mount("ve_selftest", path, "tmpfs", 0, NULL) != 0)
> + _exit(255);
> + if (is_mounted(path) != 1)
> + _exit(254);
> +
> + /*
> + * The lookup that used to unmount it. What the VE is told
> + * depends on the filesystem and on the mount now covering the
> + * entry, and enforce_denies() already covers that. Here only
> + * the mount surviving the lookup is the point.
> + */
> + ve_open_rel(self->cgv2_fd, self->ctid_a, variant->dir_prefix,
> + variant->dir, O_RDONLY | O_DIRECTORY);
> +
> + _exit(is_mounted(path) == 1 ? 0 : 2);
> + }
> + ASSERT_EQ(waitpid(pid, &status, 0), pid);
> + ASSERT_TRUE(WIFEXITED(status));
> + if (WEXITSTATUS(status) == 2)
> + TH_LOG("the VE lookup unmounted %s", path);
> + EXPECT_EQ(WEXITSTATUS(status), 0);
> +}
> +
> TEST_HARNESS_MAIN
> diff --git a/tools/testing/selftests/ve/ve_selftest.h b/tools/testing/selftests/ve/ve_selftest.h
> index 69c0a52dd7ef..83ace9e6db42 100644
> --- a/tools/testing/selftests/ve/ve_selftest.h
> +++ b/tools/testing/selftests/ve/ve_selftest.h
> @@ -1,8 +1,8 @@
> /* SPDX-License-Identifier: GPL-2.0 */
> /*
> * Shared helpers for the ve selftests: a private cgroup2 mount, small file and
> - * cgroup helpers, and VE cgroup create and destroy, used across the tests in
> - * this directory.
> + * cgroup helpers, VE cgroup create and destroy, and a mount point query, used
> + * across the tests in this directory.
> */
> #ifndef __SELFTESTS_VE_VE_SELFTEST_H
> #define __SELFTESTS_VE_VE_SELFTEST_H
> @@ -180,4 +180,27 @@ static inline void destroy_ve(int cgv2_fd, int id)
> __func__, id, strerror(errno));
> }
>
> +/* Is @path a mount point in this task's mount namespace? */
> +static inline int is_mounted(const char *path)
> +{
> + char line[PATH_MAX + 128], target[PATH_MAX];
> + int found = 0;
> + unsigned int u;
> + FILE *f;
> +
> + f = fopen("/proc/self/mountinfo", "r");
> + if (!f)
> + return -1;
> + while (fgets(line, sizeof(line), f)) {
> + if (sscanf(line, "%u %u %u:%u %*s %s", &u, &u, &u, &u, target) != 5)
> + continue;
> + if (strcmp(target, path) == 0) {
> + found = 1;
> + break;
> + }
> + }
Take a look at openat2 RESOLVE_NO_XDEV, it detects the crossing of mount boundary
(open parent, open child from parent), and avoids heavy mountinfo reading.
> + fclose(f);
> + return found;
> +}
> +
> #endif /* __SELFTESTS_VE_VE_SELFTEST_H */
--
Best regards, Pavel Tikhomirov
Senior Software Developer, Virtuozzo.
next prev parent reply other threads:[~2026-08-25 15:40 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-25 13:29 [Devel] [PATCH vz10 0/2] fs/kernfs, ve: stop a container lookup unmounting host filesystems Mirian Shilakadze
2026-08-25 13:29 ` [Devel] [PATCH vz10 1/2] fs/kernfs, ve: hide entries from a VE without invalidating the dentry Mirian Shilakadze
2026-08-25 14:59 ` Pavel Tikhomirov
2026-08-25 13:29 ` [Devel] [PATCH vz10 2/2] selftests/ve: check that hiding an entry does not unmount it Mirian Shilakadze
2026-08-25 15:40 ` Pavel Tikhomirov [this message]
2026-08-25 15:46 ` [Devel] [PATCH vz10 0/2] fs/kernfs, ve: stop a container lookup unmounting host filesystems Pavel Tikhomirov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1e09adbd-f820-482b-9c48-814e4d62f5be@virtuozzo.com \
--to=ptikhomirov@virtuozzo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.