ns: Free anonymous mount namespaces via ns_common_free()

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@google.com>
Cc: Paul Moore <paul@paul-moore.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
Co-developed-by: Mickaël Salaün <mic@digikod.net>
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Reviewed-by: Christian Brauner (Amutable) <brauner@kernel.org>
Signed-off-by: Paul Moore <paul@paul-moore.com>
This commit is contained in:
Christian Brauner 2026-07-26 18:13:46 +02:00 committed by Paul Moore
parent b030ffaedc
commit 4f238e6e1c
3 changed files with 4 additions and 3 deletions

View File

@ -4193,8 +4193,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);
}

View File

@ -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
};

View File

@ -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)