From 81c94e76ce8e14a487bca210b3fd92ca661516ac Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Thu, 6 Feb 2014 07:34:02 -0500 Subject: selinux: fix the output of ./scripts/get_maintainer.pl for SELinux Correctly tag the SELinux mailing list as moderated for non-subscribers and do some shuffling of the SELinux maintainers to try and make things more clear when the scripts/get_maintainer.pl script is used. # ./scripts/get_maintainer.pl -f security/selinux Paul Moore (supporter:SELINUX SECURITY...) Stephen Smalley (supporter:SELINUX SECURITY...) Eric Paris (supporter:SELINUX SECURITY...) James Morris (supporter:SECURITY SUBSYSTEM) selinux@tycho.nsa.gov (moderated list:SELINUX SECURITY...) linux-security-module@vger.kernel.org (open list:SECURITY SUBSYSTEM) linux-kernel@vger.kernel.org (open list) Cc: Stephen Smalley Cc: Eric Paris Cc: James Morris Signed-off-by: Paul Moore --- MAINTAINERS | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 6a6e4ac72287..bfe8da460f7a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7583,11 +7583,10 @@ M: Security Officers S: Supported SELINUX SECURITY MODULE +M: Paul Moore M: Stephen Smalley -M: James Morris M: Eric Paris -M: Paul Moore -L: selinux@tycho.nsa.gov (subscribers-only, general discussion) +L: selinux@tycho.nsa.gov (moderated for non-subscribers) W: http://selinuxproject.org T: git git://git.infradead.org/users/pcmoore/selinux S: Supported -- cgit v1.2.3-58-ga151 From 0909c0ae999c325b9d34c6f4710f40730ae3bc24 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 28 Feb 2014 07:23:24 -0500 Subject: selinux: put the mmap() DAC controls before the MAC controls It turns out that doing the SELinux MAC checks for mmap() before the DAC checks was causing users and the SELinux policy folks headaches as users were seeing a lot of SELinux AVC denials for the memprotect:mmap_zero permission that would have also been denied by the normal DAC capability checks (CAP_SYS_RAWIO). Example: # cat mmap_test.c #include #include #include #include int main(int argc, char *argv[]) { int rc; void *mem; mem = mmap(0x0, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); if (mem == MAP_FAILED) return errno; printf("mem = %p\n", mem); munmap(mem, 4096); return 0; } # gcc -g -O0 -o mmap_test mmap_test.c # ./mmap_test mem = (nil) # ausearch -m AVC | grep mmap_zero type=AVC msg=audit(...): avc: denied { mmap_zero } for pid=1025 comm="mmap_test" scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=memprotect This patch corrects things so that when the above example is run by a user without CAP_SYS_RAWIO the SELinux AVC is no longer generated as the DAC capability check fails before the SELinux permission check. Signed-off-by: Paul Moore Acked-by: Stephen Smalley --- security/selinux/hooks.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4b34847208cc..a3230de656e4 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3204,24 +3204,20 @@ error: static int selinux_mmap_addr(unsigned long addr) { - int rc = 0; - u32 sid = current_sid(); + int rc; + + /* do DAC check on address space usage */ + rc = cap_mmap_addr(addr); + if (rc) + return rc; - /* - * notice that we are intentionally putting the SELinux check before - * the secondary cap_file_mmap check. This is such a likely attempt - * at bad behaviour/exploit that we always want to get the AVC, even - * if DAC would have also denied the operation. - */ if (addr < CONFIG_LSM_MMAP_MIN_ADDR) { + u32 sid = current_sid(); rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, NULL); - if (rc) - return rc; } - /* do DAC check on address space usage */ - return cap_mmap_addr(addr); + return rc; } static int selinux_mmap_file(struct file *file, unsigned long reqprot, -- cgit v1.2.3-58-ga151 From eee3094683fbc7fe6bcdaef58c1ef31f8460cdca Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 5 Mar 2014 15:54:57 -0500 Subject: selinux: correctly label /proc inodes in use before the policy is loaded This patch is based on an earlier patch by Eric Paris, he describes the problem below: "If an inode is accessed before policy load it will get placed on a list of inodes to be initialized after policy load. After policy load we call inode_doinit() which calls inode_doinit_with_dentry() on all inodes accessed before policy load. In the case of inodes in procfs that means we'll end up at the bottom where it does: /* Default to the fs superblock SID. */ isec->sid = sbsec->sid; if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) { if (opt_dentry) { isec->sclass = inode_mode_to_security_class(...) rc = selinux_proc_get_sid(opt_dentry, isec->sclass, &sid); if (rc) goto out_unlock; isec->sid = sid; } } Since opt_dentry is null, we'll never call selinux_proc_get_sid() and will leave the inode labeled with the label on the superblock. I believe a fix would be to mimic the behavior of xattrs. Look for an alias of the inode. If it can't be found, just leave the inode uninitialized (and pick it up later) if it can be found, we should be able to call selinux_proc_get_sid() ..." On a system exhibiting this problem, you will notice a lot of files in /proc with the generic "proc_t" type (at least the ones that were accessed early in the boot), for example: # ls -Z /proc/sys/kernel/shmmax | awk '{ print $4 " " $5 }' system_u:object_r:proc_t:s0 /proc/sys/kernel/shmmax However, with this patch in place we see the expected result: # ls -Z /proc/sys/kernel/shmmax | awk '{ print $4 " " $5 }' system_u:object_r:sysctl_kernel_t:s0 /proc/sys/kernel/shmmax Cc: Eric Paris Signed-off-by: Paul Moore Acked-by: Eric Paris --- security/selinux/hooks.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a3230de656e4..8b1656f053f8 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1418,15 +1418,33 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent isec->sid = sbsec->sid; if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) { - if (opt_dentry) { - isec->sclass = inode_mode_to_security_class(inode->i_mode); - rc = selinux_proc_get_sid(opt_dentry, - isec->sclass, - &sid); - if (rc) - goto out_unlock; - isec->sid = sid; - } + /* We must have a dentry to determine the label on + * procfs inodes */ + if (opt_dentry) + /* Called from d_instantiate or + * d_splice_alias. */ + dentry = dget(opt_dentry); + else + /* Called from selinux_complete_init, try to + * find a dentry. */ + dentry = d_find_alias(inode); + /* + * This can be hit on boot when a file is accessed + * before the policy is loaded. When we load policy we + * may find inodes that have no dentry on the + * sbsec->isec_head list. No reason to complain as + * these will get fixed up the next time we go through + * inode_doinit() with a dentry, before these inodes + * could be used again by userspace. + */ + if (!dentry) + goto out_unlock; + isec->sclass = inode_mode_to_security_class(inode->i_mode); + rc = selinux_proc_get_sid(dentry, isec->sclass, &sid); + dput(dentry); + if (rc) + goto out_unlock; + isec->sid = sid; } break; } -- cgit v1.2.3-58-ga151 From 626b9740fa73cad043e136bfb3b6fca68a4f8a7c Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Tue, 29 Apr 2014 11:29:04 -0700 Subject: selinux: Report permissive mode in avc: denied messages. We cannot presently tell from an avc: denied message whether access was in fact denied or was allowed due to global or per-domain permissive mode. Add a permissive= field to the avc message to reflect this information. Signed-off-by: Stephen Smalley Acked-by: Eric Paris Signed-off-by: Paul Moore --- security/selinux/avc.c | 7 ++++++- security/selinux/hooks.c | 5 +++-- security/selinux/include/avc.h | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/security/selinux/avc.c b/security/selinux/avc.c index fc3e6628a864..a18f1fa6440b 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -444,11 +444,15 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) avc_dump_query(ab, ad->selinux_audit_data->ssid, ad->selinux_audit_data->tsid, ad->selinux_audit_data->tclass); + if (ad->selinux_audit_data->denied) { + audit_log_format(ab, " permissive=%u", + ad->selinux_audit_data->result ? 0 : 1); + } } /* This is the slow part of avc audit with big stack footprint */ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, - u32 requested, u32 audited, u32 denied, + u32 requested, u32 audited, u32 denied, int result, struct common_audit_data *a, unsigned flags) { @@ -477,6 +481,7 @@ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, sad.tsid = tsid; sad.audited = audited; sad.denied = denied; + sad.result = result; a->selinux_audit_data = &sad; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d58946dca8c9..889cf4c3c3fa 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2770,6 +2770,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na static noinline int audit_inode_permission(struct inode *inode, u32 perms, u32 audited, u32 denied, + int result, unsigned flags) { struct common_audit_data ad; @@ -2780,7 +2781,7 @@ static noinline int audit_inode_permission(struct inode *inode, ad.u.inode = inode; rc = slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms, - audited, denied, &ad, flags); + audited, denied, result, &ad, flags); if (rc) return rc; return 0; @@ -2822,7 +2823,7 @@ static int selinux_inode_permission(struct inode *inode, int mask) if (likely(!audited)) return rc; - rc2 = audit_inode_permission(inode, perms, audited, denied, flags); + rc2 = audit_inode_permission(inode, perms, audited, denied, rc, flags); if (rc2) return rc2; return rc; diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index f53ee3c58d0f..ddf8eec03f21 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -102,7 +102,7 @@ static inline u32 avc_audit_required(u32 requested, } int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, - u32 requested, u32 audited, u32 denied, + u32 requested, u32 audited, u32 denied, int result, struct common_audit_data *a, unsigned flags); @@ -137,7 +137,7 @@ static inline int avc_audit(u32 ssid, u32 tsid, if (likely(!audited)) return 0; return slow_avc_audit(ssid, tsid, tclass, - requested, audited, denied, + requested, audited, denied, result, a, 0); } -- cgit v1.2.3-58-ga151 From 4f189988a0a5890db597ec48fc0e8b09922f290a Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Thu, 15 May 2014 11:16:06 -0400 Subject: selinux: reject setexeccon() on MNT_NOSUID applications with -EACCES We presently prevent processes from using setexecon() to set the security label of exec()'d processes when NO_NEW_PRIVS is enabled by returning an error; however, we silently ignore setexeccon() when exec()'ing from a nosuid mounted filesystem. This patch makes things a bit more consistent by returning an error in the setexeccon()/nosuid case. Signed-off-by: Paul Moore Acked-by: Andy Lutomirski Acked-by: Stephen Smalley --- security/selinux/hooks.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 889cf4c3c3fa..b03b0776955a 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2123,11 +2123,13 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) new_tsec->exec_sid = 0; /* - * Minimize confusion: if no_new_privs and a transition is - * explicitly requested, then fail the exec. + * Minimize confusion: if no_new_privs or nosuid and a + * transition is explicitly requested, then fail the exec. */ if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) return -EPERM; + if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) + return -EACCES; } else { /* Check for a default transition on this program. */ rc = security_transition_sid(old_tsec->sid, isec->sid, -- cgit v1.2.3-58-ga151 From 612c353178c45250fbec271e7e8e75596d5cbbea Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 15 May 2014 15:02:53 -0400 Subject: selinux: conditionally reschedule in mls_convert_context while loading selinux policy On a slow machine (with debugging enabled), upgrading selinux policy may take a considerable amount of time. Long enough that the softlockup detector gets triggered. The backtrace looks like this.. > BUG: soft lockup - CPU#2 stuck for 23s! [load_policy:19045] > Call Trace: > [] symcmp+0xf/0x20 > [] hashtab_search+0x47/0x80 > [] mls_convert_context+0xdc/0x1c0 > [] convert_context+0x378/0x460 > [] ? security_context_to_sid_core+0x240/0x240 > [] sidtab_map+0x45/0x80 > [] security_load_policy+0x3ff/0x580 > [] ? sched_clock_cpu+0xa8/0x100 > [] ? sched_clock_local+0x1d/0x80 > [] ? sched_clock_cpu+0xa8/0x100 > [] ? __change_page_attr_set_clr+0x82a/0xa50 > [] ? sched_clock_local+0x1d/0x80 > [] ? sched_clock_cpu+0xa8/0x100 > [] ? __change_page_attr_set_clr+0x82a/0xa50 > [] ? sched_clock_cpu+0xa8/0x100 > [] ? retint_restore_args+0xe/0xe > [] ? trace_hardirqs_on_caller+0xfd/0x1c0 > [] ? trace_hardirqs_on_thunk+0x3a/0x3f > [] ? rcu_irq_exit+0x68/0xb0 > [] ? retint_restore_args+0xe/0xe > [] sel_write_load+0xa7/0x770 > [] ? vfs_write+0x1c3/0x200 > [] ? security_file_permission+0x1e/0xa0 > [] vfs_write+0xbb/0x200 > [] ? fget_light+0x397/0x4b0 > [] SyS_write+0x47/0xa0 > [] tracesys+0xdd/0xe2 Stephen Smalley suggested: > Maybe put a cond_resched() within the ebitmap_for_each_positive_bit() > loop in mls_convert_context()? That seems to do the trick. Tested by downgrading and re-upgrading selinux-policy-targeted. Signed-off-by: Dave Jones Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/ss/mls.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index c85bc1ec040c..d307b37ddc2b 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -492,6 +492,8 @@ int mls_convert_context(struct policydb *oldp, rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1); if (rc) return rc; + + cond_resched(); } ebitmap_destroy(&c->range.level[l].cat); c->range.level[l].cat = bitmap; -- cgit v1.2.3-58-ga151 From 47dd0b76ace953bd2c0479076db0d3e3b9594003 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 15 May 2014 15:03:53 -0400 Subject: selinux: conditionally reschedule in hashtab_insert while loading selinux policy After silencing the sleeping warning in mls_convert_context() I started seeing similar traces from hashtab_insert. Do a cond_resched there too. Signed-off-by: Dave Jones Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/ss/hashtab.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index 933e735bb185..2cc496149842 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "hashtab.h" struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key), @@ -40,6 +41,8 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum) u32 hvalue; struct hashtab_node *prev, *cur, *newnode; + cond_resched(); + if (!h || h->nel == HASHTAB_MAX_NODES) return -EINVAL; -- cgit v1.2.3-58-ga151