[PATCH v3 01/12] ns: Free anonymous mount namespaces via ns_common_free()

Mickaël Salaün mic at digikod.net
Sun Jul 26 16:13:46 UTC 2026


From: Christian Brauner <brauner at kernel.org>

free_mnt_ns() skipped ns_common_free() for anonymous mount namespaces
(the "if (!is_anon_ns(ns))" guard) because they carry the reserved inum
MNT_NS_ANON_INO, which proc_free_inum() must never release.

A following change needs ns_common_free() to run for every namespace, to
release per-namespace state attached during __ns_common_init().  Move
the reserved-inum decision into __ns_common_free() and let free_mnt_ns()
call ns_common_free() unconditionally.

__ns_common_free() is shared by all namespace types, so it gates
proc_free_inum() on ns->inum > MNT_NS_INO_SPECIAL_MAX (a new alias for
MNT_NS_ANON_INO) rather than the mount-specific is_anon_ns().  The
reserved inums (MNT_NS_ANON_INO and the *_NS_INIT_INO values just above
it) belong to namespaces that are never freed, except the anonymous
mount namespace; dynamically allocated inums are >= PROC_DYNAMIC_FIRST.
So the comparison frees every dynamic inum and skips exactly the
anonymous mount namespace, matching the previous guard.

Cc: Günther Noack <gnoack at google.com>
Cc: Paul Moore <paul at paul-moore.com>
Signed-off-by: Christian Brauner <brauner at kernel.org>
Co-developed-by: Mickaël Salaün <mic at digikod.net>
Signed-off-by: Mickaël Salaün <mic at digikod.net>
---

Changes since v2:
- New patch, split from "security: add LSM blob and hooks for
  namespaces" (suggested by Paul Moore).
---
 fs/namespace.c            | 3 +--
 include/uapi/linux/nsfs.h | 1 +
 kernel/nscommon.c         | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/fs/namespace.c b/fs/namespace.c
index 3d5cd5bf3b05..0602f133f3a0 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -4186,8 +4186,7 @@ static void dec_mnt_namespaces(struct ucounts *ucounts)
 
 static void free_mnt_ns(struct mnt_namespace *ns)
 {
-	if (!is_anon_ns(ns))
-		ns_common_free(ns);
+	ns_common_free(ns);
 	dec_mnt_namespaces(ns->ucounts);
 	mnt_ns_tree_remove(ns);
 }
diff --git a/include/uapi/linux/nsfs.h b/include/uapi/linux/nsfs.h
index a25e38d1c874..ea0f0267d90f 100644
--- a/include/uapi/linux/nsfs.h
+++ b/include/uapi/linux/nsfs.h
@@ -55,6 +55,7 @@ enum init_ns_ino {
 	MNT_NS_INIT_INO		= 0xEFFFFFF8U,
 #ifdef __KERNEL__
 	MNT_NS_ANON_INO		= 0xEFFFFFF7U,
+	MNT_NS_INO_SPECIAL_MAX	= MNT_NS_ANON_INO,
 #endif
 };
 
diff --git a/kernel/nscommon.c b/kernel/nscommon.c
index 3166c1fd844a..e6f623e1bc37 100644
--- a/kernel/nscommon.c
+++ b/kernel/nscommon.c
@@ -91,7 +91,8 @@ int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_ope
 
 void __ns_common_free(struct ns_common *ns)
 {
-	proc_free_inum(ns->inum);
+	if (ns->inum > MNT_NS_INO_SPECIAL_MAX)
+		proc_free_inum(ns->inum);
 }
 
 struct ns_common *__must_check ns_owner(struct ns_common *ns)
-- 
2.54.0




More information about the Linux-security-module-archive mailing list