OpenVZ / Virtuozzo kernel development (devel@openvz.org)
 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: unlink the mount namespace on the copy_mnt_ns() error path
Date: Wed, 26 Aug 2026 17:38:39 +0200	[thread overview]
Message-ID: <202608261538.67QFcd7Z907504@f0.sw.ru> (raw)
In-Reply-To: <2c65bce961b8be0c34e3714181c3bdc533e82b51.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 5e3e3c3facbcd29dfa49f7f6ab5aabb39a60d1f9
Author: Mirian Shilakadze <mirian.shilakadze@virtuozzo.com>
Date:   Mon Aug 17 11:16:39 2026 +0400

    ve/fs: unlink the mount namespace on the copy_mnt_ns() error path
    
    alloc_mnt_ns() does two things upstream does not: it links the namespace
    onto all_mntns_list and takes a reference on its owning VE. Both are
    undone in free_mnt_ns(), which holds the only list_del() of mntns_list
    and the only put_ve(ns->ve_owner) in the file.
    
    copy_mnt_ns() does not call it when copy_tree() fails. It open codes the
    teardown and finishes with mnt_ns_release(), which drops the passive
    count and kfree()s the namespace without unlinking it, so the namespace
    is freed while all_mntns_list still points at it and the VE reference is
    leaked. The next namespace creation runs list_add_tail() through the
    dangling entry.
    
    A container reaches this deterministically. alloc_vfsmnt() returns NULL
    when !ve_mount_allowed(), that is when the VE is at sysctl_ve_mount_nr,
    clone_mnt() turns that into -ENOMEM and copy_tree() propagates it. So a
    container sitting at its own mount limit that calls unshare(CLONE_NEWNS)
    takes the error path every time, with no memory pressure and nothing
    beyond CAP_SYS_ADMIN in its own user namespace, and panics the host:
    
      list_add corruption. prev->next should be next (ffffffffa9ca77f0), but
      was ff2834a3cdfaeed0. (prev=ff2834a3cdfaeed0).
      kernel BUG at lib/list_debug.c:32!
      CPU: 94 UID: 0 PID: 7139 Comm: unshare ve: 900
       alloc_mnt_ns+0xd5/0x210
       copy_mnt_ns+0x82/0x3c0
       create_new_namespaces+0x5d/0x2f0
       unshare_nsproxy_namespaces+0x69/0xc0
       ksys_unshare+0x213/0x3f0
    
    prev->next == prev is INIT_LIST_HEAD() on reallocated memory, the freed
    namespace reused while the list still referenced it. CONFIG_DEBUG_LIST is
    only what makes it a clean BUG, without it the same list_add_tail()
    writes through the dangling pointer silently.
    
    The path used to call free_mnt_ns() and was correct. Upstream replaced
    that with the open coded sequence because free_mnt_ns() reaches
    mnt_ns_tree_remove(), which rb_erase()s a node that copy_mnt_ns() has not
    inserted yet, mnt_ns_tree_add() running only after the copy succeeds.
    Upstream is unaffected by the replacement because its free_mnt_ns()
    carries nothing else. Ours does.
    
    So do not restore the free_mnt_ns() call, that would reintroduce the
    rb_erase() upstream fixed. Split the part that is ours into
    mnt_ns_unlink() and call it from both places, so a future addition to
    namespace teardown has one home rather than two that can drift apart,
    which is how this happened.
    
    Fixes: 229fd15908fe ("fs: don't try and remove empty rbtree node")
    Fixes: 1db60e545f65 ("ve/mntns: add ve_owner to struct mnt_namespace")
    https://virtuozzo.atlassian.net/browse/VSTOR-141545
    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 | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/fs/namespace.c b/fs/namespace.c
index 4d4dc52903508..7e27537dcdaf9 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -4243,17 +4243,30 @@ static void dec_mnt_namespaces(struct ucounts *ucounts)
 static LIST_HEAD(all_mntns_list);
 static DEFINE_SPINLOCK(all_mntns_list_lock);
 
-static void free_mnt_ns(struct mnt_namespace *ns)
+/*
+ * Undo the bookkeeping alloc_mnt_ns() sets up beyond what upstream does: the
+ * entry on all_mntns_list and the reference on the owning VE.
+ *
+ * Kept separate from free_mnt_ns() because copy_mnt_ns() has to unwind a
+ * namespace that is not in mnt_ns_tree yet, so it cannot use free_mnt_ns()
+ * without rb_erase()ing a node that was never inserted.
+ */
+static void mnt_ns_unlink(struct mnt_namespace *ns)
 {
-	if (!is_anon_ns(ns))
-		ns_free_inum(&ns->ns);
-	dec_mnt_namespaces(ns->ucounts);
-
 	spin_lock(&all_mntns_list_lock);
 	list_del(&ns->mntns_list);
 	spin_unlock(&all_mntns_list_lock);
 
 	put_ve(ns->ve_owner);
+}
+
+static void free_mnt_ns(struct mnt_namespace *ns)
+{
+	if (!is_anon_ns(ns))
+		ns_free_inum(&ns->ns);
+	dec_mnt_namespaces(ns->ucounts);
+
+	mnt_ns_unlink(ns);
 
 	mnt_ns_tree_remove(ns);
 }
@@ -4347,6 +4360,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
 		namespace_unlock();
 		ns_free_inum(&new_ns->ns);
 		dec_mnt_namespaces(new_ns->ucounts);
+		mnt_ns_unlink(new_ns);
 		mnt_ns_release(new_ns);
 		return ERR_CAST(new);
 	}
_______________________________________________
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   ` Konstantin Khorenko [this message]
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   ` [Devel] [PATCH RHEL10 COMMIT] " Konstantin Khorenko
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.67QFcd7Z907504@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox