]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
nstree: assign fixed ids to the initial namespaces
authorChristian Brauner <brauner@kernel.org>
Wed, 29 Oct 2025 12:20:28 +0000 (13:20 +0100)
committerChristian Brauner <brauner@kernel.org>
Mon, 3 Nov 2025 16:41:17 +0000 (17:41 +0100)
The initial set of namespace comes with fixed inode numbers making it
easy for userspace to identify them solely based on that information.
This has long preceeded anything here.

Similarly, let's assign fixed namespace ids for the initial namespaces.

Kill the cookie and use a sequentially increasing number. This has the
nice side-effect that the owning user namespace will always have a
namespace id that is smaller than any of it's descendant namespaces.

Link: https://patch.msgid.link/20251029-work-namespace-nstree-listns-v4-15-2e6f823ebdc0@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/namespace.c
include/linux/ns_common.h
include/linux/nstree.h
include/uapi/linux/nsfs.h
kernel/nstree.c
net/core/net_namespace.c

index 7b78dd48b6c356d9cf9cb2027d157f3d3bf6d990..eded33eeb6473ee2ef8ad9c75872f3c3c50cf906 100644 (file)
@@ -4094,7 +4094,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns, bool a
                return ERR_PTR(ret);
        }
        if (!anon)
-               ns_tree_gen_id(&new_ns->ns);
+               ns_tree_gen_id(new_ns);
        refcount_set(&new_ns->passive, 1);
        new_ns->mounts = RB_ROOT;
        init_waitqueue_head(&new_ns->poll);
index 7a3c71b3a76f462f3a7f738a49c4de7ef60bc667..009a6dea724f1c277204a75d6293407b72790ab5 100644 (file)
@@ -173,6 +173,17 @@ static __always_inline bool is_initial_namespace(struct ns_common *ns)
                struct user_namespace *:   &init_user_ns,   \
                struct uts_namespace *:    &init_uts_ns)
 
+#define ns_init_id(__ns)                                               \
+       _Generic((__ns),                                                \
+               struct cgroup_namespace *:      CGROUP_NS_INIT_ID,      \
+               struct ipc_namespace *:         IPC_NS_INIT_ID,         \
+               struct mnt_namespace *:         MNT_NS_INIT_ID,         \
+               struct net *:                   NET_NS_INIT_ID,         \
+               struct pid_namespace *:         PID_NS_INIT_ID,         \
+               struct time_namespace *:        TIME_NS_INIT_ID,        \
+               struct user_namespace *:        USER_NS_INIT_ID,        \
+               struct uts_namespace *:         UTS_NS_INIT_ID)
+
 #define to_ns_operations(__ns)                                                                         \
        _Generic((__ns),                                                                               \
                struct cgroup_namespace *: (IS_ENABLED(CONFIG_CGROUPS) ? &cgroupns_operations : NULL), \
@@ -198,7 +209,7 @@ static __always_inline bool is_initial_namespace(struct ns_common *ns)
 #define NS_COMMON_INIT(nsname, refs)                                                   \
 {                                                                                      \
        .ns_type                = ns_common_type(&nsname),                              \
-       .ns_id                  = 0,                                                    \
+       .ns_id                  = ns_init_id(&nsname),                                  \
        .inum                   = ns_init_inum(&nsname),                                \
        .ops                    = to_ns_operations(&nsname),                            \
        .stashed                = NULL,                                                 \
index 43aa262c0ea1542f2b3393e675e123498b0ba51c..38674c6fa4f78774f00d6cfb042f9c8ca5304fc9 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/seqlock.h>
 #include <linux/rculist.h>
 #include <linux/cookie.h>
+#include <uapi/linux/nsfs.h>
 
 extern struct ns_tree cgroup_ns_tree;
 extern struct ns_tree ipc_ns_tree;
@@ -30,7 +31,11 @@ extern struct ns_tree uts_ns_tree;
                struct user_namespace *:   &(user_ns_tree),     \
                struct uts_namespace *:    &(uts_ns_tree))
 
-u64 ns_tree_gen_id(struct ns_common *ns);
+#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 *ns_tree);
 void __ns_tree_remove(struct ns_common *ns, struct ns_tree *ns_tree);
 struct ns_common *ns_tree_lookup_rcu(u64 ns_id, int ns_type);
@@ -38,9 +43,9 @@ struct ns_common *__ns_tree_adjoined_rcu(struct ns_common *ns,
                                         struct ns_tree *ns_tree,
                                         bool previous);
 
-static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree *ns_tree)
+static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree *ns_tree, u64 id)
 {
-       ns_tree_gen_id(ns);
+       __ns_tree_gen_id(ns, id);
        __ns_tree_add_raw(ns, ns_tree);
 }
 
@@ -60,7 +65,9 @@ static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree *ns_tree)
  * This function assigns a new id to the namespace and adds it to the
  * appropriate namespace tree and list.
  */
-#define ns_tree_add(__ns) __ns_tree_add(to_ns_common(__ns), to_ns_tree(__ns))
+#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))
 
 /**
  * ns_tree_remove - Remove a namespace from a namespace tree
index e098759ec917ac489dc94cd11e97414831c4022e..f8bc2aad74d69ebf5bbf52ee2236a533fbfc4c45 100644 (file)
@@ -67,4 +67,18 @@ struct nsfs_file_handle {
 #define NSFS_FILE_HANDLE_SIZE_VER0 16 /* sizeof first published struct */
 #define NSFS_FILE_HANDLE_SIZE_LATEST sizeof(struct nsfs_file_handle) /* sizeof latest published struct */
 
+enum init_ns_id {
+       IPC_NS_INIT_ID          = 1ULL,
+       UTS_NS_INIT_ID          = 2ULL,
+       USER_NS_INIT_ID         = 3ULL,
+       PID_NS_INIT_ID          = 4ULL,
+       CGROUP_NS_INIT_ID       = 5ULL,
+       TIME_NS_INIT_ID         = 6ULL,
+       NET_NS_INIT_ID          = 7ULL,
+       MNT_NS_INIT_ID          = 8ULL,
+#ifdef __KERNEL__
+       NS_LAST_INIT_ID         = MNT_NS_INIT_ID,
+#endif
+};
+
 #endif /* __LINUX_NSFS_H */
index bbb34b46b01b691719b2a4de4bf3ceb93ed4c7cb..cf102c5bb849f344c7a4fd5779b96083e2f4ee0b 100644 (file)
@@ -69,8 +69,6 @@ struct ns_tree time_ns_tree = {
        .type = CLONE_NEWTIME,
 };
 
-DEFINE_COOKIE(namespace_cookie);
-
 static inline struct ns_common *node_to_ns(const struct rb_node *node)
 {
        if (!node)
@@ -285,15 +283,20 @@ struct ns_common *__ns_tree_adjoined_rcu(struct ns_common *ns,
 /**
  * ns_tree_gen_id - generate a new namespace id
  * @ns: namespace to generate id for
+ * @id: if non-zero, this is the initial namespace and this is a fixed id
  *
  * Generates a new namespace id and assigns it to the namespace. All
  * namespaces types share the same id space and thus can be compared
  * directly. IOW, when two ids of two namespace are equal, they are
  * identical.
  */
-u64 ns_tree_gen_id(struct ns_common *ns)
+u64 __ns_tree_gen_id(struct ns_common *ns, u64 id)
 {
-       guard(preempt)();
-       ns->ns_id = gen_cookie_next(&namespace_cookie);
+       static atomic64_t namespace_cookie = ATOMIC64_INIT(NS_LAST_INIT_ID + 1);
+
+       if (id)
+               ns->ns_id = id;
+       else
+               ns->ns_id = atomic64_inc_return(&namespace_cookie);
        return ns->ns_id;
 }
index b0e0f22d7b213c522c2b83a5fcbcabb43e72cd11..83cbec4afcb3a09a41af4758dc006b7498033b77 100644 (file)
@@ -439,7 +439,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->ns);
+       net->net_cookie = ns_tree_gen_id(net);
 
        list_for_each_entry(ops, &pernet_list, list) {
                error = ops_init(ops, net);