Introduce a separate SECURITY_SELINUX_NS Kconfig option for enabling SELinux namespaces and have it default to n since it is experimental. Make the SECURITY_SELINUX_MAXNS and SECURITY_SELINUX_MAXNSDEPTH Kconfig options depend on this new option. This option only controls whether the SELinux namespace support is exposed to userspace, not the underlying infrastructure support. When set to n, the kernel APIs for unsharing the SELinux namespace (/sys/fs/selinux/unshare) and for setting limits on SELinux namespaces (/sys/fs/selinux/{maxns,maxnsdepth}) are not created and only a single initial SELinux namespace is created during startup and associated with all tasks. When set to y, the kernel APIs are created and userspace can use them (if permitted by policy and constrained by the limits) to unshare the SELinux namespace. Signed-off-by: Stephen Smalley <stephen.smalley.work@xxxxxxxxx> --- security/selinux/Kconfig | 42 +++++++++++++++++++++++++++++++++--- security/selinux/hooks.c | 4 ++++ security/selinux/selinuxfs.c | 7 +++++- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index 82db54462253..aa25da389c46 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig @@ -88,10 +88,46 @@ config SECURITY_SELINUX_DEBUG echo -n 'file "security/selinux/*" +p' > \ /proc/dynamic_debug/control +config SECURITY_SELINUX_NS + bool "SELinux namespace support (experimental)" + depends on SECURITY_SELINUX + default n + help + This enables (experimental) support for SELinux namespaces, + i.e the ability to create multiple SELinux namespaces where + each namespace has its own independent enforcing mode, + AVC, and policy, accessible through its own independent + selinuxfs instance. When a task unshares its SELinux namespace, + it is associated with a new child namespace whose initial + state is permissive with no policy loaded, and the task is assigned + a separate SID in the new namespace, initially the kernel SID, + which is likewise independent of its SID in ancestor namespaces. + Subsequent actions by the task and its descendants are checked + against the new namespace and all ancestor namespaces, using the + SID it has in each namespace for that namespace's checks. Objects + like inodes only have a single SID irrespective of the namespace + in which they are created or accessed. If the context associated + with a SID is not defined in a namespace, then it is treated as + the unlabeled SID for access checking purposes in that namespace. + The current kernel API for unsharing the SELinux namespace is to + write a "1" to /sys/fs/selinux/unshare; this is likely to change + before upstreaming. Experimental patches for libselinux and + systemd to use this support can be found in the selinuxns + branches of https://github.com/stephensmalley/selinux, which + provides a selinux_unshare() API that wraps the kernel interface, + and https://github.com/stephensmalley/systemd, which has + a modified systemd-nspawn that uses this API when called + with --selinux-namespace and a modified systemd to perform + SELinux initialization when started within a container that + has its own SELinux namespace. Userspace can also detect + whether it is running in a non-init SELinux namespace by + reading /sys/fs/selinux/unshare ("1" means it has been unshared, + "0" means it has not) but an API for this might not be retained. + config SECURITY_SELINUX_MAXNS int "SELinux default maximum number of namespaces" - depends on SECURITY_SELINUX - range 0 65535 + depends on SECURITY_SELINUX_NS + range 1 65535 default 65535 help This option sets the default maximum number of SELinux namespaces. @@ -99,7 +135,7 @@ config SECURITY_SELINUX_MAXNS config SECURITY_SELINUX_MAXNSDEPTH int "SELinux default maximum depth of namespaces" - depends on SECURITY_SELINUX + depends on SECURITY_SELINUX_NS range 0 32 default 32 help diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 8c0e44effdbc..a6c980f9117b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -7622,8 +7622,10 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { static void selinux_state_free(struct work_struct *work); +#ifdef CONFIG_SECURITY_SELINUX_NS unsigned int selinux_maxns = CONFIG_SECURITY_SELINUX_MAXNS; unsigned int selinux_maxnsdepth = CONFIG_SECURITY_SELINUX_MAXNSDEPTH; +#endif static atomic_t selinux_nsnum = ATOMIC_INIT(0); @@ -7635,11 +7637,13 @@ int selinux_state_create(const struct cred *cred) struct selinux_state *newstate; int rc; +#ifdef CONFIG_SECURITY_SELINUX_NS if (parent && atomic_read(&selinux_nsnum) >= selinux_maxns) return -ENOSPC; if (parent && parent->depth >= selinux_maxnsdepth) return -ENOSPC; +#endif newstate = kzalloc(sizeof(*newstate), GFP_KERNEL); if (!newstate) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index efceb3ac9157..785991d77166 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -65,9 +65,11 @@ enum sel_inos { SEL_STATUS, /* export current status using mmap() */ SEL_POLICY, /* allow userspace to read the in kernel policy */ SEL_VALIDATE_TRANS, /* compute validatetrans decision */ +#ifdef CONFIG_SECURITY_SELINUX_NS SEL_UNSHARE, /* unshare selinux namespace */ SEL_MAXNS, /* maximum number of SELinux namespaces */ SEL_MAXNSDEPTH, /* maximum depth of SELinux namespaces */ +#endif SEL_INO_NEXT, /* The next inode number to use */ }; @@ -329,6 +331,7 @@ static const struct file_operations sel_disable_ops = { .llseek = generic_file_llseek, }; +#ifdef CONFIG_SECURITY_SELINUX_NS static ssize_t sel_read_unshare(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { @@ -531,7 +534,7 @@ static const struct file_operations sel_maxnsdepth_ops = { .write = sel_write_maxnsdepth, .llseek = generic_file_llseek, }; - +#endif static ssize_t sel_read_policyvers(struct file *filp, char __user *buf, size_t count, loff_t *ppos) @@ -2353,9 +2356,11 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc) [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO}, [SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops, S_IWUGO}, +#ifdef CONFIG_SECURITY_SELINUX_NS [SEL_UNSHARE] = {"unshare", &sel_unshare_ops, 0600}, [SEL_MAXNS] = {"maxns", &sel_maxns_ops, 0600}, [SEL_MAXNSDEPTH] = {"maxnsdepth", &sel_maxnsdepth_ops, 0600}, +#endif /* last one */ {""} }; -- 2.47.1