[RFC PATCH v1 03/11] nsproxy: Add FOR_EACH_NS_TYPE() X-macro and CLONE_NS_ALL

Mickaël Salaün posted 11 patches 3 weeks, 5 days ago
[RFC PATCH v1 03/11] nsproxy: Add FOR_EACH_NS_TYPE() X-macro and CLONE_NS_ALL
Posted by Mickaël Salaün 3 weeks, 5 days ago
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>
---
 include/linux/ns/ns_common_types.h | 44 +++++++++++++++++++++++-------
 kernel/fork.c                      |  7 ++---
 kernel/nsproxy.c                   | 13 +++------
 3 files changed, 41 insertions(+), 23 deletions(-)

diff --git a/include/linux/ns/ns_common_types.h b/include/linux/ns/ns_common_types.h
index 170288e2e895..5cfe0ce3c881 100644
--- a/include/linux/ns/ns_common_types.h
+++ b/include/linux/ns/ns_common_types.h
@@ -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;
@@ -187,15 +188,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 */
diff --git a/kernel/fork.c b/kernel/fork.c
index 65113a304518..767559acd060 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -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
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index f0b30d1907e7..7181886331c8 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -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
-- 
2.53.0

Re: [RFC PATCH v1 03/11] nsproxy: Add FOR_EACH_NS_TYPE() X-macro and CLONE_NS_ALL
Posted by Christian Brauner 1 week, 6 days ago
On Thu, Mar 12, 2026 at 11:04:36AM +0100, Mickaël Salaün wrote:
> 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>
> ---

Yeah, I love that. I can take that as a separate patch right now even.

Reviewed-by: Christian Brauner <brauner@kernel.org>
Re: [RFC PATCH v1 03/11] nsproxy: Add FOR_EACH_NS_TYPE() X-macro and CLONE_NS_ALL
Posted by Mickaël Salaün 1 week, 6 days ago
On Wed, Mar 25, 2026 at 01:33:31PM +0100, Christian Brauner wrote:
> On Thu, Mar 12, 2026 at 11:04:36AM +0100, Mickaël Salaün wrote:
> > 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>
> > ---
> 
> Yeah, I love that. I can take that as a separate patch right now even.

Yes, please take it.

> 
> Reviewed-by: Christian Brauner <brauner@kernel.org>
> 
Re: (subset) [RFC PATCH v1 03/11] nsproxy: Add FOR_EACH_NS_TYPE() X-macro and CLONE_NS_ALL
Posted by Christian Brauner 1 week, 5 days ago
On Thu, 12 Mar 2026 11:04:36 +0100, Mickaël Salaün wrote:
> 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.
> 
> [...]

Applied to the namespaces-7.1.misc branch of the vfs/vfs.git tree.
Patches in the namespaces-7.1.misc branch should appear in linux-next soon.

Please report any outstanding bugs that were missed during review in a
new review to the original patch series allowing us to drop it.

It's encouraged to provide Acked-bys and Reviewed-bys even though the
patch has now been applied. If possible patch trailers will be updated.

Note that commit hashes shown below are subject to change due to rebase,
trailer updates or similar. If in doubt, please check the listed branch.

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
branch: namespaces-7.1.misc

[03/11] nsproxy: Add FOR_EACH_NS_TYPE() X-macro and CLONE_NS_ALL
        https://git.kernel.org/vfs/vfs/c/935a04923ad2