From: Christian Brauner <brauner@kernel.org>
To: linux-fsdevel@vger.kernel.org, bpf@vger.kernel.org
Cc: linux-security-module@vger.kernel.org,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Paul Moore <paul@paul-moore.com>,
netdev@vger.kernel.org,
"Christian Brauner (Amutable)" <brauner@kernel.org>,
stable@kernel.org
Subject: [PATCH 5/8] ns: allocate the namespace id before the namespace_init hook
Date: Mon, 26 Oct 2026 10:57:13 +0100 [thread overview]
Message-ID: <20261026-work-security-namespace_free-v1-5-ffa3ebbf71bd@kernel.org> (raw)
In-Reply-To: <20261026-work-security-namespace_free-v1-0-ffa3ebbf71bd@kernel.org>
Currently the namespace id is allocated only after __ns_common_init()
has called the namespace_init LSM hook. Most namespace types allocate it
in ns_tree_add() right before the namespace is added to the namespace
trees. So the namespace_init hook always sees an id of zero.
The namespace id is the only identifier of a namespace that is never
recycled. A bpf LSM wants to use it to track a namespace from
namespace_init until namespace_free, e.g., by using it as the key into a
map that associates data with the namespace. The inode number doesn't
work for that as it is quickly recycled.
So allocate the id in __ns_common_init() before calling the
namespace_init hook. Every namespace then has its id by the time it is
added to the namespace trees. The initial namespaces still get their
fixed ids, either statically from NS_COMMON_INIT() or for init_net from
ns_common_init(). So ns_tree_add() doesn't need to allocate an id
anymore. Ids are still handed out in creation order so mnt_ns_loop()
keeps working. Mount and ipc namespaces already allocated their id right
after ns_common_init() anyway.
If creating the namespace fails after the id has been allocated the id
is simply never used.
While at it, drop ns_tree_gen_id() as it has no users left.
Reproducer, 100 user and uts namespaces:
bpftrace -e 'fentry:bpf_lsm_namespace_init {
@[args.ns->ns_id ? "set" : "zero"] = count(); }' &
for i in $(seq 100); do unshare -Uu true; done
before: @[zero]: 200
after: @[set]: 200
Fixes: f675d2e95569 ("lsm: add LSM blob and hooks for namespaces")
Cc: <stable@kernel.org> # mainline only
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
fs/namespace.c | 2 --
include/linux/ns_common.h | 16 +++++++++-------
include/linux/nstree.h | 18 +++---------------
ipc/namespace.c | 1 -
kernel/nscommon.c | 7 +++++--
net/core/net_namespace.c | 2 +-
6 files changed, 18 insertions(+), 28 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index 9f6ec35c7b9c..f81d6a4bc3fe 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -4394,8 +4394,6 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns, bool a
dec_mnt_namespaces(ucounts);
return ERR_PTR(ret);
}
- ns_tree_gen_id(new_ns);
-
new_ns->is_anon = anon;
refcount_set(&new_ns->passive, 1);
new_ns->mounts = RB_ROOT;
diff --git a/include/linux/ns_common.h b/include/linux/ns_common.h
index c8e227a3f9e2..e8b2bf0da5ed 100644
--- a/include/linux/ns_common.h
+++ b/include/linux/ns_common.h
@@ -9,7 +9,8 @@
#include <uapi/linux/nsfs.h>
bool is_current_namespace(struct ns_common *ns);
-int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_operations *ops, int inum);
+int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_operations *ops,
+ int inum, u64 ns_id);
void __ns_common_free(struct ns_common *ns);
struct ns_common *__must_check ns_owner(struct ns_common *ns);
@@ -41,17 +42,18 @@ static __always_inline bool is_ns_init_id(const struct ns_common *ns)
.ns_owner_root.ns_list_head = LIST_HEAD_INIT(nsname.ns.ns_owner_root.ns_list_head), \
}
-#define ns_common_init(__ns) \
- __ns_common_init(to_ns_common(__ns), \
- ns_common_type(__ns), \
- to_ns_operations(__ns), \
- (((__ns) == ns_init_ns(__ns)) ? ns_init_inum(__ns) : 0))
+#define ns_common_init(__ns) \
+ __ns_common_init(to_ns_common(__ns), \
+ ns_common_type(__ns), \
+ to_ns_operations(__ns), \
+ (((__ns) == ns_init_ns(__ns)) ? ns_init_inum(__ns) : 0), \
+ (((__ns) == ns_init_ns(__ns)) ? ns_init_id(__ns) : 0))
#define ns_common_init_inum(__ns, __inum) \
__ns_common_init(to_ns_common(__ns), \
ns_common_type(__ns), \
to_ns_operations(__ns), \
- __inum)
+ __inum, 0)
#define ns_common_free(__ns) __ns_common_free(to_ns_common((__ns)))
diff --git a/include/linux/nstree.h b/include/linux/nstree.h
index 5b64d4572881..3293df17397d 100644
--- a/include/linux/nstree.h
+++ b/include/linux/nstree.h
@@ -41,10 +41,6 @@ void ns_tree_node_del(struct ns_tree_node *node, struct ns_tree_root *root);
struct user_namespace *: &(user_ns_tree), \
struct uts_namespace *: &(uts_ns_tree))
-#define ns_tree_gen_id(__ns) \
- __ns_tree_gen_id(to_ns_common(__ns), \
- (((__ns) == ns_init_ns(__ns)) ? ns_init_id(__ns) : 0))
-
u64 __ns_tree_gen_id(struct ns_common *ns, u64 id);
void __ns_tree_add_raw(struct ns_common *ns, struct ns_tree_root *ns_tree);
void __ns_tree_remove(struct ns_common *ns, struct ns_tree_root *ns_tree);
@@ -53,12 +49,6 @@ struct ns_common *__ns_tree_adjoined_rcu(struct ns_common *ns,
struct ns_tree_root *ns_tree,
bool previous);
-static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree_root *ns_tree, u64 id)
-{
- __ns_tree_gen_id(ns, id);
- __ns_tree_add_raw(ns, ns_tree);
-}
-
/**
* ns_tree_add_raw - Add a namespace to a namespace
* @__ns: Namespace to add
@@ -72,12 +62,10 @@ static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree_root *ns_t
* ns_tree_add - Add a namespace to a namespace tree
* @__ns: Namespace to add
*
- * This function assigns a new id to the namespace and adds it to the
- * appropriate namespace tree and list.
+ * This function adds a namespace to the appropriate namespace tree and
+ * list. The namespace must already have been assigned an id.
*/
-#define ns_tree_add(__ns) \
- __ns_tree_add(to_ns_common(__ns), to_ns_tree(__ns), \
- (((__ns) == ns_init_ns(__ns)) ? ns_init_id(__ns) : 0))
+#define ns_tree_add(__ns) __ns_tree_add_raw(to_ns_common(__ns), to_ns_tree(__ns))
/**
* ns_tree_remove - Remove a namespace from a namespace tree
diff --git a/ipc/namespace.c b/ipc/namespace.c
index 75aa7b469348..9084e0643017 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -66,7 +66,6 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
if (err)
goto fail_free;
- ns_tree_gen_id(ns);
ns->user_ns = get_user_ns(user_ns);
ns->ucounts = ucounts;
diff --git a/kernel/nscommon.c b/kernel/nscommon.c
index e72426bba29a..4438c6b663f9 100644
--- a/kernel/nscommon.c
+++ b/kernel/nscommon.c
@@ -54,7 +54,8 @@ static void ns_debug(struct ns_common *ns, const struct proc_ns_operations *ops)
}
#endif
-int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_operations *ops, int inum)
+int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_operations *ops,
+ int inum, u64 ns_id)
{
int ret = 0;
@@ -64,7 +65,6 @@ int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_ope
ns->ns_security = NULL;
#endif
ns->ops = ops;
- ns->ns_id = 0;
ns->ns_type = ns_type;
ns_tree_node_init(&ns->ns_tree_node);
ns_tree_node_init(&ns->ns_unified_node);
@@ -82,6 +82,9 @@ int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_ope
if (ret)
return ret;
+ /* Allocate the id before the LSM hook so it can track the namespace by it. */
+ __ns_tree_gen_id(ns, ns_id);
+
ret = security_namespace_init(ns);
if (ret) {
if (!inum)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index da5f881fbd3b..ec4077b81389 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -437,7 +437,7 @@ static __net_init int setup_net(struct net *net)
LIST_HEAD(net_exit_list);
int error = 0;
- net->net_cookie = ns_tree_gen_id(net);
+ net->net_cookie = to_ns_common(net)->ns_id;
list_for_each_entry(ops, &pernet_list, list) {
error = ops_init(ops, net);
--
2.53.0
next prev parent reply other threads:[~2026-10-26 9:57 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-26 9:57 [PATCH 0/8] ns: fixes for the namespace LSM hooks Christian Brauner
2026-10-26 9:57 ` [PATCH 1/8] lsm: always call the namespace_free hook Christian Brauner
2026-10-26 10:37 ` sashiko-bot
2026-10-26 9:57 ` [PATCH 2/8] bpf: don't mark namespace_init and namespace_free arguments as trusted Christian Brauner
2026-10-26 10:41 ` sashiko-bot
2026-10-26 9:57 ` [PATCH 3/8] selftests/bpf: add verifier tests for the namespace LSM hooks Christian Brauner
2026-10-26 10:44 ` sashiko-bot
2026-10-26 9:57 ` [PATCH 4/8] landlock: pass the namespace id to log to check_ns_type() Christian Brauner
2026-10-26 10:45 ` sashiko-bot
2026-10-29 11:27 ` Mickaël Salaün
2026-10-26 9:57 ` Christian Brauner [this message]
2026-10-26 10:51 ` [PATCH 5/8] ns: allocate the namespace id before the namespace_init hook sashiko-bot
2026-10-26 9:57 ` [PATCH 6/8] nstree: drop ns_tree_add_raw() Christian Brauner
2026-10-26 10:55 ` sashiko-bot
2026-10-26 9:57 ` [PATCH 7/8] lsm: fix the security_namespace_init() kernel-doc Christian Brauner
2026-10-26 10:57 ` sashiko-bot
2026-10-26 9:57 ` [PATCH 8/8] selftests/bpf: add a lifecycle test for the namespace LSM hooks Christian Brauner
2026-10-26 11:03 ` sashiko-bot
2026-10-26 20:31 ` [PATCH 0/8] ns: fixes " Paul Moore
2026-10-27 9:24 ` Christian Brauner
2026-10-27 14:36 ` Daniel Borkmann
2026-10-27 22:37 ` Paul Moore
2026-10-28 10:42 ` Christian Brauner
2026-10-28 15:59 ` Paul Moore
2026-10-26 23:31 ` Alexei Starovoitov
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=20261026-work-security-namespace_free-v1-5-ffa3ebbf71bd@kernel.org \
--to=brauner@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=paul@paul-moore.com \
--cc=stable@kernel.org \
/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.