All Virtuozzo development lists (kernel + QEMU)
 help / color / mirror / Atom feed
From: Konstantin Khorenko <khorenko@virtuozzo.com>
To: Mirian Shilakadze <mirian.shilakadze@virtuozzo.com>
Cc: OpenVZ devel <devel@openvz.org>
Subject: Re: [Devel] [PATCH RHEL10 COMMIT] ve/fs: take the owner of copied mounts from the namespace, not the task
Date: Wed, 26 Aug 2026 17:38:47 +0200	[thread overview]
Message-ID: <202608261538.67QFclYJ907570@f0.sw.ru> (raw)
In-Reply-To: <07f25e8bb318c82bc628051fe3882ccfc37befc2.1786950779.git.mirian.shilakadze@virtuozzo.com>

The commit is pushed to "branch-rh10-6.12.0-211.39.1.16.x.vz10-ovz" and will appear at git@bitbucket.org:openvz/vzkernel.git
after rh10-6.12.0-211.39.1.16.10.vz10
------>
commit a614531f0672e6ab3ad4f13c91fe813dc8927009
Author: Mirian Shilakadze <mirian.shilakadze@virtuozzo.com>
Date:   Mon Aug 17 11:16:41 2026 +0400

    ve/fs: take the owner of copied mounts from the namespace, not the task
    
    A new mount takes its ve_owner from get_exec_env(), the VE of the task
    doing the work, rather than the VE of the mount namespace it is working
    in. The two differ for a ve0 task that has entered a container's mount
    namespace and stayed ve0, which is what nsenter -m gives you.
    
    Two places build mounts that way and neither passes through
    commit_tree(), so the transfer added by the previous patch cannot correct
    them. copy_mnt_ns() takes the owner from the unsharing task unless an
    explicit VE was threaded in, which only happens for CLONE_NEWVE, so a
    plain unshare(CLONE_NEWNS) hands back a ve0 owned copy of every mount in
    the namespace. open_detached_copy() passes NULL to __do_loopback(), so
    open_tree(OPEN_TREE_CLONE) mints ve0 owned clones in an anonymous
    namespace the mount never leaves before being executed from.
    
    Either one undoes the trusted exec check with one extra command:
    
      nsenter -t $INITPID -m -- unshare -m -- /ctown/planted
    
    This is older than the mount transfer it defeats. Both paths also launder
    a tmpfs the container created entirely on its own, which
    ve_check_trusted_file() was already supposed to refuse, so the check has
    been avoidable this way since it was added.
    
    Take the owner from the namespace being worked in rather than from the
    caller, the same rule commit_tree() follows for a mount that moves. An
    explicit VE for a container being created still wins, and nothing changes
    for a task working inside its own VE's namespace, which is every normal
    mount, bind and unshare.
    
    Note that ve_mount_allowed() tests the limit against get_exec_env() while
    ve_mount_nr_inc() charges the owner, so in the mismatched case a ve0 task
    passes the check against ve0 and the copies are charged to the container.
    That split is older than this patch, which only widens where it applies.
    
    Fixes: d65efacf542b ("trusted/ve/fs/exec: Don't allow a privileged user to execute untrusted files")
    Fixes: fc7157b84c32 ("trusted/ve/mmap: Protect from unsecure library load from CT image")
    https://virtuozzo.atlassian.net/browse/VSTOR-141429
    Feature: ve: ve generic structures
    Signed-off-by: Mirian Shilakadze <mirian.shilakadze@virtuozzo.com>
    Reviewed-by: Vasileios Almpanis <vasileios.almpanis@virtuozzo.com>
    Reviewed-by: Konstantin Khorenko <khorenko@virtuozzo.com>
---
 fs/namespace.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/fs/namespace.c b/fs/namespace.c
index f8319a2b33df8..4adc1db84b4c0 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2830,6 +2830,7 @@ static int do_change_type(struct path *path, int ms_flags)
 
 static struct mount *__do_loopback(struct path *old_path, int recurse)
 {
+	struct ve_struct *owner = current->nsproxy->mnt_ns->ve_owner;
 	struct mount *mnt = ERR_PTR(-EINVAL), *old = real_mount(old_path->mnt);
 
 	if (IS_MNT_UNBINDABLE(old))
@@ -2846,11 +2847,17 @@ static struct mount *__do_loopback(struct path *old_path, int recurse)
 	if (!recurse && __has_locked_children(old, old_path->dentry))
 		return mnt;
 
+	/*
+	 * The copy belongs to the namespace it is taken from, not to whoever
+	 * is asking. The two differ for a ve0 task working inside a
+	 * container's mount namespace, and open_detached_copy() never reaches
+	 * commit_tree() to have the owner corrected later.
+	 */
 	if (recurse)
 		mnt = copy_tree(old, old_path->dentry, CL_COPY_MNT_NS_FILE,
-				NULL);
+				owner);
 	else
-		mnt = clone_mnt(old, old_path->dentry, 0, NULL);
+		mnt = clone_mnt(old, old_path->dentry, 0, owner);
 
 	if (!IS_ERR(mnt))
 		mnt->mnt.mnt_flags &= ~MNT_LOCKED;
@@ -4372,7 +4379,16 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
 
 	old = ns->root;
 
-	new_ns = alloc_mnt_ns(user_ns, false, new_ve);
+	/*
+	 * A copied namespace holds copies of @ns's mounts, so it belongs to
+	 * whoever owns @ns rather than to whoever is unsharing. The two differ
+	 * for a ve0 task working inside a container's mount namespace, and
+	 * copy_mnt_ns() populates the namespace directly, without going
+	 * through commit_tree() where the owner would otherwise be corrected.
+	 * An explicit @new_ve still wins: a container being created owns the
+	 * namespace made for it.
+	 */
+	new_ns = alloc_mnt_ns(user_ns, false, new_ve ?: ns->ve_owner);
 	if (IS_ERR(new_ns))
 		return new_ns;
 
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

  reply	other threads:[~2026-08-26 15:40 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-17  7:16 [Devel] [PATCH vz10 0/3] ve/fs: make mount ownership follow the mount namespace Mirian Shilakadze
2026-08-17  7:16 ` [Devel] [PATCH vz10 1/3] ve/fs: unlink the mount namespace on the copy_mnt_ns() error path Mirian Shilakadze
2026-08-26 15:38   ` [Devel] [PATCH RHEL10 COMMIT] " Konstantin Khorenko
2026-08-17  7:16 ` [Devel] [PATCH vz10 2/3] ve/fs: transfer mount ownership when a mount enters another VE Mirian Shilakadze
2026-08-26 15:38   ` [Devel] [PATCH RHEL10 COMMIT] " Konstantin Khorenko
2026-08-17  7:16 ` [Devel] [PATCH vz10 3/3] ve/fs: take the owner of copied mounts from the namespace, not the task Mirian Shilakadze
2026-08-26 15:38   ` Konstantin Khorenko [this message]
2026-08-18 10:40 ` [Devel] [PATCH vz10 0/3] ve/fs: make mount ownership follow the mount namespace Vasileios Almpanis
2026-08-26 15:30   ` Konstantin Khorenko

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=202608261538.67QFclYJ907570@f0.sw.ru \
    --to=khorenko@virtuozzo.com \
    --cc=devel@openvz.org \
    --cc=mirian.shilakadze@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.