]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
nsproxy: Add FOR_EACH_NS_TYPE() X-macro and CLONE_NS_ALL
authorMickaël Salaün <mic@digikod.net>
Thu, 12 Mar 2026 10:04:36 +0000 (11:04 +0100)
committerChristian Brauner <brauner@kernel.org>
Thu, 26 Mar 2026 14:22:41 +0000 (15:22 +0100)
Introduce the FOR_EACH_NS_TYPE(X) macro as the single source of truth
for the set of (struct type, CLONE_NEW* flag) pairs that define Linux
namespace types.

Currently, the list of CLONE_NEW* flags is duplicated inline in
multiple call sites and would need another copy in each new consumer.
This makes it easy to miss one when a new namespace type is added.

Derive two things from the X-macro:

- CLONE_NS_ALL: Bitmask of all known CLONE_NEW* flags, usable as a
  validity mask or iteration bound.

- ns_common_type(): Rewritten to use the X-macro via a leading-comma
  _Generic pattern, so the struct-to-flag mapping stays in sync with the
  flag set automatically.

Replace the inline flag enumerations in copy_namespaces(),
unshare_nsproxy_namespaces(), check_setns_flags(), and
ksys_unshare() with CLONE_NS_ALL.

When a new namespace type is added, only FOR_EACH_NS_TYPE needs to
be updated; CLONE_NS_ALL, ns_common_type(), and all the call sites
pick up the change automatically.

Cc: Christian Brauner <brauner@kernel.org>
Cc: Günther Noack <gnoack@google.com>
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Link: https://patch.msgid.link/20260312100444.2609563-4-mic@digikod.net
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
include/linux/ns/ns_common_types.h
kernel/fork.c
kernel/nsproxy.c

index 0014fbc1c62692069820c10d772c7b4b6a6605d6..ea45c54e4435ede4e18033faa0248f4896ba9185 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/rbtree.h>
 #include <linux/refcount.h>
 #include <linux/types.h>
+#include <uapi/linux/sched.h>
 
 struct cgroup_namespace;
 struct dentry;
@@ -184,15 +185,38 @@ struct ns_common {
                struct user_namespace *:   (IS_ENABLED(CONFIG_USER_NS) ? &userns_operations   : NULL), \
                struct uts_namespace *:    (IS_ENABLED(CONFIG_UTS_NS)  ? &utsns_operations    : NULL))
 
-#define ns_common_type(__ns)                                \
-       _Generic((__ns),                                    \
-               struct cgroup_namespace *: CLONE_NEWCGROUP, \
-               struct ipc_namespace *:    CLONE_NEWIPC,    \
-               struct mnt_namespace *:    CLONE_NEWNS,     \
-               struct net *:              CLONE_NEWNET,    \
-               struct pid_namespace *:    CLONE_NEWPID,    \
-               struct time_namespace *:   CLONE_NEWTIME,   \
-               struct user_namespace *:   CLONE_NEWUSER,   \
-               struct uts_namespace *:    CLONE_NEWUTS)
+/*
+ * FOR_EACH_NS_TYPE - Canonical list of namespace types
+ *
+ * Enumerates all (struct type, CLONE_NEW* flag) pairs.  This is the
+ * single source of truth used to derive ns_common_type() and
+ * CLONE_NS_ALL.  When adding a new namespace type, add a single entry
+ * here; all consumers update automatically.
+ *
+ * @X: Callback macro taking (struct_name, clone_flag) as arguments.
+ */
+#define FOR_EACH_NS_TYPE(X)                  \
+       X(cgroup_namespace, CLONE_NEWCGROUP) \
+       X(ipc_namespace, CLONE_NEWIPC)       \
+       X(mnt_namespace, CLONE_NEWNS)        \
+       X(net, CLONE_NEWNET)                 \
+       X(pid_namespace, CLONE_NEWPID)       \
+       X(time_namespace, CLONE_NEWTIME)     \
+       X(user_namespace, CLONE_NEWUSER)     \
+       X(uts_namespace, CLONE_NEWUTS)
+
+/* Bitmask of all known CLONE_NEW* flags. */
+#define _NS_TYPE_FLAG_OR(struct_name, flag) | (flag)
+#define CLONE_NS_ALL                        (0 FOR_EACH_NS_TYPE(_NS_TYPE_FLAG_OR))
+
+/*
+ * ns_common_type - Map a namespace struct pointer to its CLONE_NEW* flag
+ *
+ * Uses a leading-comma pattern so the FOR_EACH_NS_TYPE expansion
+ * produces ", struct foo *: FLAG" entries without a trailing comma.
+ */
+#define _NS_TYPE_ASSOC(struct_name, flag) , struct struct_name *: (flag)
+
+#define ns_common_type(__ns) _Generic((__ns)FOR_EACH_NS_TYPE(_NS_TYPE_ASSOC))
 
 #endif /* _LINUX_NS_COMMON_TYPES_H */
index 65113a304518ae73590704034513ba06e708928a..767559acd060ba2dc0646ab8f4d0c72d8b9e2c8e 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/mm_inline.h>
 #include <linux/memblock.h>
 #include <linux/nsproxy.h>
+#include <linux/ns/ns_common_types.h>
 #include <linux/capability.h>
 #include <linux/cpu.h>
 #include <linux/cgroup.h>
@@ -3046,11 +3047,9 @@ void __init proc_caches_init(void)
  */
 static int check_unshare_flags(unsigned long unshare_flags)
 {
-       if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
+       if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_SIGHAND|
                                CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
-                               CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET|
-                               CLONE_NEWUSER|CLONE_NEWPID|CLONE_NEWCGROUP|
-                               CLONE_NEWTIME))
+                               CLONE_NS_ALL))
                return -EINVAL;
        /*
         * Not implemented, but pretend it works if there is nothing
index 259c4b4f1eeb96288669854b816235dd01d9e5e0..63b44ee79847fc4fbbc7de721bf4931fb048a5cb 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/export.h>
 #include <linux/nsproxy.h>
+#include <linux/ns/ns_common_types.h>
 #include <linux/init_task.h>
 #include <linux/mnt_namespace.h>
 #include <linux/utsname.h>
@@ -170,9 +171,7 @@ int copy_namespaces(u64 flags, struct task_struct *tsk)
        struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns);
        struct nsproxy *new_ns;
 
-       if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
-                             CLONE_NEWPID | CLONE_NEWNET |
-                             CLONE_NEWCGROUP | CLONE_NEWTIME)))) {
+       if (likely(!(flags & (CLONE_NS_ALL & ~CLONE_NEWUSER)))) {
                if ((flags & CLONE_VM) ||
                    likely(old_ns->time_ns_for_children == old_ns->time_ns)) {
                        get_nsproxy(old_ns);
@@ -214,9 +213,7 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags,
        struct user_namespace *user_ns;
        int err = 0;
 
-       if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
-                              CLONE_NEWNET | CLONE_NEWPID | CLONE_NEWCGROUP |
-                              CLONE_NEWTIME)))
+       if (!(unshare_flags & (CLONE_NS_ALL & ~CLONE_NEWUSER)))
                return 0;
 
        user_ns = new_cred ? new_cred->user_ns : current_user_ns();
@@ -292,9 +289,7 @@ int exec_task_namespaces(void)
 
 static int check_setns_flags(unsigned long flags)
 {
-       if (!flags || (flags & ~(CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
-                                CLONE_NEWNET | CLONE_NEWTIME | CLONE_NEWUSER |
-                                CLONE_NEWPID | CLONE_NEWCGROUP)))
+       if (!flags || (flags & ~CLONE_NS_ALL))
                return -EINVAL;
 
 #ifndef CONFIG_USER_NS