* [RFC PATCH] selinux: implement namespace_alloc and namespace_install hooks
@ 2026-03-30 19:31 danieldurning.work
2026-04-14 16:54 ` Stephen Smalley
0 siblings, 1 reply; 5+ messages in thread
From: danieldurning.work @ 2026-03-30 19:31 UTC (permalink / raw)
To: selinux; +Cc: stephen.smalley.work, paul, omosnace, brauner, mic
From: Daniel Durning <danieldurning.work@gmail.com>
Add implementations of the namespace_alloc and namespace_install
hooks for SELinux. Corresponding permissions are defined for each
hook (create and setns, respectively), New security classes are
defined for each individual namespace type to allow granularity.
In namespace_alloc we check the caller's SID against itself. When
a namespace is allocated the SID of the caller is saved in the
namespace security blob. This SID is checked against the caller
in namespace_install. We fall back to SECINITSID_KERNEL if
ns_common is pointing to an init namespace, since these are
created before policy load and will be lacking a security blob.
Requires Christian Brauner's namespace LSM blob patch and
Mickaël Salaün's LSM namespace audit data patch, which are
the first 2 patches in the series linked below.
As an additional note, the namespace security blob does not
seem to be freed when a mount namespace is marked as anon
in the kernel. The free_mnt_ns() function only calls
ns_common_free() (which ultimately calls the namespace_free()
hook) if a mount namespace is not marked as anon.
This is causing a memory leak. This issue would need to be
addressed in the original LSM namespace blob patch.
Signed-off-by: Daniel Durning <danieldurning.work@gmail.com>
Link: https://lore.kernel.org/all/20260312100444.2609563-3-mic@digikod.net/
---
security/selinux/hooks.c | 65 +++++++++++++++++++++++++++++
security/selinux/include/classmap.h | 12 +++++-
security/selinux/include/objsec.h | 10 +++++
3 files changed, 86 insertions(+), 1 deletion(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 6ef9c1aade65..e3cf07008fc8 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -94,6 +94,7 @@
#include <linux/io_uring/cmd.h>
#include <uapi/linux/lsm.h>
#include <linux/memfd.h>
+#include <linux/ns_common.h>
#include "initcalls.h"
#include "avc.h"
@@ -1327,6 +1328,31 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
return SECCLASS_SOCKET;
}
+static inline u16 ns_type_to_security_class(struct ns_common *ns)
+{
+ switch (ns->ns_type) {
+ case CLONE_NEWCGROUP:
+ return SECCLASS_CGROUP_NAMESPACE;
+ case CLONE_NEWIPC:
+ return SECCLASS_IPC_NAMESPACE;
+ case CLONE_NEWNS:
+ return SECCLASS_MNT_NAMESPACE;
+ case CLONE_NEWNET:
+ return SECCLASS_NET_NAMESPACE;
+ case CLONE_NEWPID:
+ return SECCLASS_PID_NAMESPACE;
+ case CLONE_NEWTIME:
+ return SECCLASS_TIME_NAMESPACE;
+ case CLONE_NEWUSER:
+ return SECCLASS_USER_NAMESPACE;
+ case CLONE_NEWUTS:
+ return SECCLASS_UTS_NAMESPACE;
+ default:
+ WARN_ON(1);
+ return SECCLASS_NAMESPACE;
+ }
+}
+
static int selinux_genfs_get_sid(struct dentry *dentry,
u16 tclass,
u16 flags,
@@ -6899,6 +6925,42 @@ static int selinux_inode_getsecctx(struct inode *inode, struct lsm_context *cp)
cp->id = LSM_ID_SELINUX;
return 0;
}
+
+static int selinux_namespace_alloc(struct ns_common *ns)
+{
+ struct common_audit_data ad;
+ struct ns_security_struct *nssec = selinux_ns(ns);
+ u16 sclass = ns_type_to_security_class(ns);
+ u32 sid = current_sid();
+
+ ad.type = LSM_AUDIT_DATA_NS;
+ ad.u.ns.ns_type = ns->ns_type;
+ ad.u.ns.inum = ns->inum;
+
+ nssec->sid = sid;
+
+ return avc_has_perm(sid, sid, sclass, NAMESPACE__CREATE, &ad);
+}
+
+static int selinux_namespace_install(const struct nsset *nsset,
+ struct ns_common *ns)
+{
+ struct common_audit_data ad;
+ struct ns_security_struct *nssec = selinux_ns(ns);
+ u16 sclass = ns_type_to_security_class(ns);
+ u32 sid = current_sid();
+
+ ad.type = LSM_AUDIT_DATA_NS;
+ ad.u.ns.ns_type = ns->ns_type;
+ ad.u.ns.inum = ns->inum;
+
+ if (!nssec)
+ return avc_has_perm(sid, SECINITSID_KERNEL, sclass,
+ NAMESPACE__SETNS, &ad);
+
+ return avc_has_perm(sid, nssec->sid, sclass, NAMESPACE__SETNS, &ad);
+}
+
#ifdef CONFIG_KEYS
static int selinux_key_alloc(struct key *k, const struct cred *cred,
@@ -7409,6 +7471,7 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
.lbs_bpf_map = sizeof(struct bpf_security_struct),
.lbs_bpf_prog = sizeof(struct bpf_security_struct),
.lbs_bpf_token = sizeof(struct bpf_security_struct),
+ .lbs_ns = sizeof(struct ns_security_struct),
};
/*
@@ -7610,6 +7673,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(tun_dev_attach_queue, selinux_tun_dev_attach_queue),
LSM_HOOK_INIT(tun_dev_attach, selinux_tun_dev_attach),
LSM_HOOK_INIT(tun_dev_open, selinux_tun_dev_open),
+ LSM_HOOK_INIT(namespace_install, selinux_namespace_install),
#ifdef CONFIG_SECURITY_INFINIBAND
LSM_HOOK_INIT(ib_pkey_access, selinux_ib_pkey_access),
LSM_HOOK_INIT(ib_endport_manage_subnet,
@@ -7685,6 +7749,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx),
LSM_HOOK_INIT(sk_alloc_security, selinux_sk_alloc_security),
LSM_HOOK_INIT(tun_dev_alloc_security, selinux_tun_dev_alloc_security),
+ LSM_HOOK_INIT(namespace_alloc, selinux_namespace_alloc),
#ifdef CONFIG_SECURITY_INFINIBAND
LSM_HOOK_INIT(ib_alloc_security, selinux_ib_alloc_security),
#endif
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 90cb61b16425..e904ed795208 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -33,6 +33,8 @@
"mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend", \
"audit_read", "perfmon", "bpf", "checkpoint_restore"
+#define COMMON_NAMESPACE_PERMS "create", "setns"
+
#ifdef __KERNEL__ /* avoid this check when building host programs */
#include <linux/capability.h>
@@ -178,9 +180,17 @@ const struct security_class_mapping secclass_map[] = {
{ "open", "cpu", "kernel", "tracepoint", "read", "write", NULL } },
{ "anon_inode", { COMMON_FILE_PERMS, NULL } },
{ "io_uring", { "override_creds", "sqpoll", "cmd", "allowed", NULL } },
- { "user_namespace", { "create", NULL } },
{ "memfd_file",
{ COMMON_FILE_PERMS, "execute_no_trans", "entrypoint", NULL } },
+ { "cgroup_namespace", { COMMON_NAMESPACE_PERMS, NULL } },
+ { "ipc_namespace", { COMMON_NAMESPACE_PERMS, NULL } },
+ { "mnt_namespace", { COMMON_NAMESPACE_PERMS, NULL } },
+ { "net_namespace", { COMMON_NAMESPACE_PERMS, NULL } },
+ { "pid_namespace", { COMMON_NAMESPACE_PERMS, NULL } },
+ { "time_namespace", { COMMON_NAMESPACE_PERMS, NULL } },
+ { "user_namespace", { COMMON_NAMESPACE_PERMS, NULL } },
+ { "uts_namespace", { COMMON_NAMESPACE_PERMS, NULL } },
+ { "namespace", { COMMON_NAMESPACE_PERMS, NULL } },
/* last one */ { NULL, {} }
};
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 5bddd28ea5cb..4692a67b7c2f 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -27,6 +27,7 @@
#include <linux/msg.h>
#include <net/net_namespace.h>
#include <linux/bpf.h>
+#include <linux/ns_common.h>
#include "flask.h"
#include "avc.h"
@@ -178,6 +179,10 @@ struct perf_event_security_struct {
u32 sid; /* SID of perf_event obj creator */
};
+struct ns_security_struct {
+ u32 sid; /* SID of ns obj creator */
+};
+
extern struct lsm_blob_sizes selinux_blob_sizes;
static inline struct cred_security_struct *selinux_cred(const struct cred *cred)
{
@@ -259,6 +264,11 @@ selinux_perf_event(void *perf_event)
return perf_event + selinux_blob_sizes.lbs_perf_event;
}
+static inline struct ns_security_struct *selinux_ns(struct ns_common *ns)
+{
+ return ns->ns_security + selinux_blob_sizes.lbs_ns;
+}
+
#ifdef CONFIG_BPF_SYSCALL
static inline struct bpf_security_struct *
selinux_bpf_map_security(struct bpf_map *map)
--
2.51.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [RFC PATCH] selinux: implement namespace_alloc and namespace_install hooks
2026-03-30 19:31 [RFC PATCH] selinux: implement namespace_alloc and namespace_install hooks danieldurning.work
@ 2026-04-14 16:54 ` Stephen Smalley
2026-04-15 12:04 ` Stephen Smalley
0 siblings, 1 reply; 5+ messages in thread
From: Stephen Smalley @ 2026-04-14 16:54 UTC (permalink / raw)
To: danieldurning.work; +Cc: selinux, paul, omosnace, brauner, mic
On Mon, Mar 30, 2026 at 3:31 PM <danieldurning.work@gmail.com> wrote:
>
> From: Daniel Durning <danieldurning.work@gmail.com>
>
> Add implementations of the namespace_alloc and namespace_install
> hooks for SELinux. Corresponding permissions are defined for each
> hook (create and setns, respectively), New security classes are
> defined for each individual namespace type to allow granularity.
>
> In namespace_alloc we check the caller's SID against itself. When
> a namespace is allocated the SID of the caller is saved in the
> namespace security blob. This SID is checked against the caller
> in namespace_install. We fall back to SECINITSID_KERNEL if
> ns_common is pointing to an init namespace, since these are
> created before policy load and will be lacking a security blob.
>
> Requires Christian Brauner's namespace LSM blob patch and
> Mickaël Salaün's LSM namespace audit data patch, which are
> the first 2 patches in the series linked below.
>
> As an additional note, the namespace security blob does not
> seem to be freed when a mount namespace is marked as anon
> in the kernel. The free_mnt_ns() function only calls
> ns_common_free() (which ultimately calls the namespace_free()
> hook) if a mount namespace is not marked as anon.
> This is causing a memory leak. This issue would need to be
> addressed in the original LSM namespace blob patch.
Assuming that this gets fixed by the change suggested by Christian
Brauner, we can drop this note from the commit message for this one.
>
> Signed-off-by: Daniel Durning <danieldurning.work@gmail.com>
> Link: https://lore.kernel.org/all/20260312100444.2609563-3-mic@digikod.net/
Otherwise,
Reviewed-by: Stephen Smalley <stephen.smalley.work@gmail.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC PATCH] selinux: implement namespace_alloc and namespace_install hooks
2026-04-14 16:54 ` Stephen Smalley
@ 2026-04-15 12:04 ` Stephen Smalley
2026-04-16 8:57 ` Christian Brauner
0 siblings, 1 reply; 5+ messages in thread
From: Stephen Smalley @ 2026-04-15 12:04 UTC (permalink / raw)
To: danieldurning.work; +Cc: selinux, paul, omosnace, brauner, mic
On Tue, Apr 14, 2026 at 12:54 PM Stephen Smalley
<stephen.smalley.work@gmail.com> wrote:
>
> On Mon, Mar 30, 2026 at 3:31 PM <danieldurning.work@gmail.com> wrote:
> >
> > From: Daniel Durning <danieldurning.work@gmail.com>
> >
> > Add implementations of the namespace_alloc and namespace_install
> > hooks for SELinux. Corresponding permissions are defined for each
> > hook (create and setns, respectively), New security classes are
> > defined for each individual namespace type to allow granularity.
> >
> > In namespace_alloc we check the caller's SID against itself. When
> > a namespace is allocated the SID of the caller is saved in the
> > namespace security blob. This SID is checked against the caller
> > in namespace_install. We fall back to SECINITSID_KERNEL if
> > ns_common is pointing to an init namespace, since these are
> > created before policy load and will be lacking a security blob.
> >
> > Requires Christian Brauner's namespace LSM blob patch and
> > Mickaël Salaün's LSM namespace audit data patch, which are
> > the first 2 patches in the series linked below.
> >
> > As an additional note, the namespace security blob does not
> > seem to be freed when a mount namespace is marked as anon
> > in the kernel. The free_mnt_ns() function only calls
> > ns_common_free() (which ultimately calls the namespace_free()
> > hook) if a mount namespace is not marked as anon.
> > This is causing a memory leak. This issue would need to be
> > addressed in the original LSM namespace blob patch.
>
> Assuming that this gets fixed by the change suggested by Christian
> Brauner, we can drop this note from the commit message for this one.
>
> >
> > Signed-off-by: Daniel Durning <danieldurning.work@gmail.com>
> > Link: https://lore.kernel.org/all/20260312100444.2609563-3-mic@digikod.net/
>
> Otherwise,
> Reviewed-by: Stephen Smalley <stephen.smalley.work@gmail.com>
One aspect of these hooks that I hadn't realized until I exercised the
tests is that at least for mount namespaces, they are sometimes
created automatically as part of other operations (e.g. fsmount(2))
and hence these permission checks are triggered by more than just
clone/unshare(CLONE_NEWNS). And since mount(8) has been updated to use
fsmount(2) followed by move_mount(2) internally, these checks are
applied for "ordinary" mounts even within the current mount namespace.
Not sure if that is what we want.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC PATCH] selinux: implement namespace_alloc and namespace_install hooks
2026-04-15 12:04 ` Stephen Smalley
@ 2026-04-16 8:57 ` Christian Brauner
2026-04-16 14:15 ` Stephen Smalley
0 siblings, 1 reply; 5+ messages in thread
From: Christian Brauner @ 2026-04-16 8:57 UTC (permalink / raw)
To: Stephen Smalley; +Cc: danieldurning.work, selinux, paul, omosnace, mic
On Wed, Apr 15, 2026 at 08:04:27AM -0400, Stephen Smalley wrote:
> On Tue, Apr 14, 2026 at 12:54 PM Stephen Smalley
> <stephen.smalley.work@gmail.com> wrote:
> >
> > On Mon, Mar 30, 2026 at 3:31 PM <danieldurning.work@gmail.com> wrote:
> > >
> > > From: Daniel Durning <danieldurning.work@gmail.com>
> > >
> > > Add implementations of the namespace_alloc and namespace_install
> > > hooks for SELinux. Corresponding permissions are defined for each
> > > hook (create and setns, respectively), New security classes are
> > > defined for each individual namespace type to allow granularity.
> > >
> > > In namespace_alloc we check the caller's SID against itself. When
> > > a namespace is allocated the SID of the caller is saved in the
> > > namespace security blob. This SID is checked against the caller
> > > in namespace_install. We fall back to SECINITSID_KERNEL if
> > > ns_common is pointing to an init namespace, since these are
> > > created before policy load and will be lacking a security blob.
> > >
> > > Requires Christian Brauner's namespace LSM blob patch and
> > > Mickaël Salaün's LSM namespace audit data patch, which are
> > > the first 2 patches in the series linked below.
> > >
> > > As an additional note, the namespace security blob does not
> > > seem to be freed when a mount namespace is marked as anon
> > > in the kernel. The free_mnt_ns() function only calls
> > > ns_common_free() (which ultimately calls the namespace_free()
> > > hook) if a mount namespace is not marked as anon.
> > > This is causing a memory leak. This issue would need to be
> > > addressed in the original LSM namespace blob patch.
> >
> > Assuming that this gets fixed by the change suggested by Christian
> > Brauner, we can drop this note from the commit message for this one.
> >
> > >
> > > Signed-off-by: Daniel Durning <danieldurning.work@gmail.com>
> > > Link: https://lore.kernel.org/all/20260312100444.2609563-3-mic@digikod.net/
> >
> > Otherwise,
> > Reviewed-by: Stephen Smalley <stephen.smalley.work@gmail.com>
>
> One aspect of these hooks that I hadn't realized until I exercised the
> tests is that at least for mount namespaces, they are sometimes
> created automatically as part of other operations (e.g. fsmount(2))
> and hence these permission checks are triggered by more than just
> clone/unshare(CLONE_NEWNS). And since mount(8) has been updated to use
> fsmount(2) followed by move_mount(2) internally, these checks are
> applied for "ordinary" mounts even within the current mount namespace.
> Not sure if that is what we want.
I think what you're referring to is anonymous mount namespace creation.
I think it's a benefit that you can hook into this as well. They can be
distinguished from actual mount namespaces by their namespace id which
is fixed.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC PATCH] selinux: implement namespace_alloc and namespace_install hooks
2026-04-16 8:57 ` Christian Brauner
@ 2026-04-16 14:15 ` Stephen Smalley
0 siblings, 0 replies; 5+ messages in thread
From: Stephen Smalley @ 2026-04-16 14:15 UTC (permalink / raw)
To: Christian Brauner; +Cc: danieldurning.work, selinux, paul, omosnace, mic
On Thu, Apr 16, 2026 at 4:57 AM Christian Brauner <brauner@kernel.org> wrote:
>
> On Wed, Apr 15, 2026 at 08:04:27AM -0400, Stephen Smalley wrote:
> > On Tue, Apr 14, 2026 at 12:54 PM Stephen Smalley
> > <stephen.smalley.work@gmail.com> wrote:
> > >
> > > On Mon, Mar 30, 2026 at 3:31 PM <danieldurning.work@gmail.com> wrote:
> > > >
> > > > From: Daniel Durning <danieldurning.work@gmail.com>
> > > >
> > > > Add implementations of the namespace_alloc and namespace_install
> > > > hooks for SELinux. Corresponding permissions are defined for each
> > > > hook (create and setns, respectively), New security classes are
> > > > defined for each individual namespace type to allow granularity.
> > > >
> > > > In namespace_alloc we check the caller's SID against itself. When
> > > > a namespace is allocated the SID of the caller is saved in the
> > > > namespace security blob. This SID is checked against the caller
> > > > in namespace_install. We fall back to SECINITSID_KERNEL if
> > > > ns_common is pointing to an init namespace, since these are
> > > > created before policy load and will be lacking a security blob.
> > > >
> > > > Requires Christian Brauner's namespace LSM blob patch and
> > > > Mickaël Salaün's LSM namespace audit data patch, which are
> > > > the first 2 patches in the series linked below.
> > > >
> > > > As an additional note, the namespace security blob does not
> > > > seem to be freed when a mount namespace is marked as anon
> > > > in the kernel. The free_mnt_ns() function only calls
> > > > ns_common_free() (which ultimately calls the namespace_free()
> > > > hook) if a mount namespace is not marked as anon.
> > > > This is causing a memory leak. This issue would need to be
> > > > addressed in the original LSM namespace blob patch.
> > >
> > > Assuming that this gets fixed by the change suggested by Christian
> > > Brauner, we can drop this note from the commit message for this one.
> > >
> > > >
> > > > Signed-off-by: Daniel Durning <danieldurning.work@gmail.com>
> > > > Link: https://lore.kernel.org/all/20260312100444.2609563-3-mic@digikod.net/
> > >
> > > Otherwise,
> > > Reviewed-by: Stephen Smalley <stephen.smalley.work@gmail.com>
> >
> > One aspect of these hooks that I hadn't realized until I exercised the
> > tests is that at least for mount namespaces, they are sometimes
> > created automatically as part of other operations (e.g. fsmount(2))
> > and hence these permission checks are triggered by more than just
> > clone/unshare(CLONE_NEWNS). And since mount(8) has been updated to use
> > fsmount(2) followed by move_mount(2) internally, these checks are
> > applied for "ordinary" mounts even within the current mount namespace.
> > Not sure if that is what we want.
>
> I think what you're referring to is anonymous mount namespace creation.
> I think it's a benefit that you can hook into this as well. They can be
> distinguished from actual mount namespaces by their namespace id which
> is fixed.
Yes, thanks for clarifying. In that case, I might suggest adding a
separate permission specific to the mnt_namespace, e.g. create_anon or
similar, and checking that instead of the regular create permission
when the namespace is anonymous.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-04-16 14:16 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-30 19:31 [RFC PATCH] selinux: implement namespace_alloc and namespace_install hooks danieldurning.work
2026-04-14 16:54 ` Stephen Smalley
2026-04-15 12:04 ` Stephen Smalley
2026-04-16 8:57 ` Christian Brauner
2026-04-16 14:15 ` Stephen Smalley
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.