aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Smalley <sds@tycho.nsa.gov>2007-06-07 15:34:10 -0400
committerJames Morris <jmorris@namei.org>2007-07-11 22:52:25 -0400
commit2c3c05dbcbc7b9d71549fe0e2b249f10f5a66518 (patch)
treebab75df9fafc435f3370a6d773d3284716347249
parent9dc9978084ea2a96b9f42752753d9e38a9f9d7b2 (diff)
SELinux: allow preemption between transition permission checks
In security_get_user_sids, move the transition permission checks outside of the section holding the policy rdlock, and use the AVC to perform the checks, calling cond_resched after each one. These changes should allow preemption between the individual checks and enable caching of the results. It may however increase the overall time spent in the function in some cases, particularly in the cache miss case. The long term fix will be to take much of this logic to userspace by exporting additional state via selinuxfs, and ultimately deprecating and eliminating this interface from the kernel. Tested-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r--security/selinux/avc.c10
-rw-r--r--security/selinux/hooks.c9
-rw-r--r--security/selinux/include/avc.h6
-rw-r--r--security/selinux/ss/services.c49
4 files changed, 45 insertions, 29 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index e4396a89edc6..cc5fcef9e226 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -832,6 +832,7 @@ int avc_ss_reset(u32 seqno)
832 * @tsid: target security identifier 832 * @tsid: target security identifier
833 * @tclass: target security class 833 * @tclass: target security class
834 * @requested: requested permissions, interpreted based on @tclass 834 * @requested: requested permissions, interpreted based on @tclass
835 * @flags: AVC_STRICT or 0
835 * @avd: access vector decisions 836 * @avd: access vector decisions
836 * 837 *
837 * Check the AVC to determine whether the @requested permissions are granted 838 * Check the AVC to determine whether the @requested permissions are granted
@@ -846,8 +847,9 @@ int avc_ss_reset(u32 seqno)
846 * should be released for the auditing. 847 * should be released for the auditing.
847 */ 848 */
848int avc_has_perm_noaudit(u32 ssid, u32 tsid, 849int avc_has_perm_noaudit(u32 ssid, u32 tsid,
849 u16 tclass, u32 requested, 850 u16 tclass, u32 requested,
850 struct av_decision *avd) 851 unsigned flags,
852 struct av_decision *avd)
851{ 853{
852 struct avc_node *node; 854 struct avc_node *node;
853 struct avc_entry entry, *p_ae; 855 struct avc_entry entry, *p_ae;
@@ -874,7 +876,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
874 denied = requested & ~(p_ae->avd.allowed); 876 denied = requested & ~(p_ae->avd.allowed);
875 877
876 if (!requested || denied) { 878 if (!requested || denied) {
877 if (selinux_enforcing) 879 if (selinux_enforcing || (flags & AVC_STRICT))
878 rc = -EACCES; 880 rc = -EACCES;
879 else 881 else
880 if (node) 882 if (node)
@@ -909,7 +911,7 @@ int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
909 struct av_decision avd; 911 struct av_decision avd;
910 int rc; 912 int rc;
911 913
912 rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, &avd); 914 rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
913 avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata); 915 avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
914 return rc; 916 return rc;
915} 917}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index ad8dd4e8657e..b29059ecc045 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1592,9 +1592,10 @@ static int selinux_vm_enough_memory(long pages)
1592 rc = secondary_ops->capable(current, CAP_SYS_ADMIN); 1592 rc = secondary_ops->capable(current, CAP_SYS_ADMIN);
1593 if (rc == 0) 1593 if (rc == 0)
1594 rc = avc_has_perm_noaudit(tsec->sid, tsec->sid, 1594 rc = avc_has_perm_noaudit(tsec->sid, tsec->sid,
1595 SECCLASS_CAPABILITY, 1595 SECCLASS_CAPABILITY,
1596 CAP_TO_MASK(CAP_SYS_ADMIN), 1596 CAP_TO_MASK(CAP_SYS_ADMIN),
1597 NULL); 1597 0,
1598 NULL);
1598 1599
1599 if (rc == 0) 1600 if (rc == 0)
1600 cap_sys_admin = 1; 1601 cap_sys_admin = 1;
@@ -4626,7 +4627,7 @@ static int selinux_setprocattr(struct task_struct *p,
4626 if (p->ptrace & PT_PTRACED) { 4627 if (p->ptrace & PT_PTRACED) {
4627 error = avc_has_perm_noaudit(tsec->ptrace_sid, sid, 4628 error = avc_has_perm_noaudit(tsec->ptrace_sid, sid,
4628 SECCLASS_PROCESS, 4629 SECCLASS_PROCESS,
4629 PROCESS__PTRACE, &avd); 4630 PROCESS__PTRACE, 0, &avd);
4630 if (!error) 4631 if (!error)
4631 tsec->sid = sid; 4632 tsec->sid = sid;
4632 task_unlock(p); 4633 task_unlock(p);
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 6ed10c3d3339..e145f6e13b0b 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -102,9 +102,11 @@ void avc_audit(u32 ssid, u32 tsid,
102 u16 tclass, u32 requested, 102 u16 tclass, u32 requested,
103 struct av_decision *avd, int result, struct avc_audit_data *auditdata); 103 struct av_decision *avd, int result, struct avc_audit_data *auditdata);
104 104
105#define AVC_STRICT 1 /* Ignore permissive mode. */
105int avc_has_perm_noaudit(u32 ssid, u32 tsid, 106int avc_has_perm_noaudit(u32 ssid, u32 tsid,
106 u16 tclass, u32 requested, 107 u16 tclass, u32 requested,
107 struct av_decision *avd); 108 unsigned flags,
109 struct av_decision *avd);
108 110
109int avc_has_perm(u32 ssid, u32 tsid, 111int avc_has_perm(u32 ssid, u32 tsid,
110 u16 tclass, u32 requested, 112 u16 tclass, u32 requested,
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index e4249adaa880..b5f017f07a75 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1587,19 +1587,18 @@ int security_get_user_sids(u32 fromsid,
1587 u32 *nel) 1587 u32 *nel)
1588{ 1588{
1589 struct context *fromcon, usercon; 1589 struct context *fromcon, usercon;
1590 u32 *mysids, *mysids2, sid; 1590 u32 *mysids = NULL, *mysids2, sid;
1591 u32 mynel = 0, maxnel = SIDS_NEL; 1591 u32 mynel = 0, maxnel = SIDS_NEL;
1592 struct user_datum *user; 1592 struct user_datum *user;
1593 struct role_datum *role; 1593 struct role_datum *role;
1594 struct av_decision avd;
1595 struct ebitmap_node *rnode, *tnode; 1594 struct ebitmap_node *rnode, *tnode;
1596 int rc = 0, i, j; 1595 int rc = 0, i, j;
1597 1596
1598 if (!ss_initialized) { 1597 *sids = NULL;
1599 *sids = NULL; 1598 *nel = 0;
1600 *nel = 0; 1599
1600 if (!ss_initialized)
1601 goto out; 1601 goto out;
1602 }
1603 1602
1604 POLICY_RDLOCK; 1603 POLICY_RDLOCK;
1605 1604
@@ -1635,17 +1634,9 @@ int security_get_user_sids(u32 fromsid,
1635 if (mls_setup_user_range(fromcon, user, &usercon)) 1634 if (mls_setup_user_range(fromcon, user, &usercon))
1636 continue; 1635 continue;
1637 1636
1638 rc = context_struct_compute_av(fromcon, &usercon,
1639 SECCLASS_PROCESS,
1640 PROCESS__TRANSITION,
1641 &avd);
1642 if (rc || !(avd.allowed & PROCESS__TRANSITION))
1643 continue;
1644 rc = sidtab_context_to_sid(&sidtab, &usercon, &sid); 1637 rc = sidtab_context_to_sid(&sidtab, &usercon, &sid);
1645 if (rc) { 1638 if (rc)
1646 kfree(mysids);
1647 goto out_unlock; 1639 goto out_unlock;
1648 }
1649 if (mynel < maxnel) { 1640 if (mynel < maxnel) {
1650 mysids[mynel++] = sid; 1641 mysids[mynel++] = sid;
1651 } else { 1642 } else {
@@ -1653,7 +1644,6 @@ int security_get_user_sids(u32 fromsid,
1653 mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC); 1644 mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
1654 if (!mysids2) { 1645 if (!mysids2) {
1655 rc = -ENOMEM; 1646 rc = -ENOMEM;
1656 kfree(mysids);
1657 goto out_unlock; 1647 goto out_unlock;
1658 } 1648 }
1659 memcpy(mysids2, mysids, mynel * sizeof(*mysids2)); 1649 memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
@@ -1664,11 +1654,32 @@ int security_get_user_sids(u32 fromsid,
1664 } 1654 }
1665 } 1655 }
1666 1656
1667 *sids = mysids;
1668 *nel = mynel;
1669
1670out_unlock: 1657out_unlock:
1671 POLICY_RDUNLOCK; 1658 POLICY_RDUNLOCK;
1659 if (rc || !mynel) {
1660 kfree(mysids);
1661 goto out;
1662 }
1663
1664 mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
1665 if (!mysids2) {
1666 rc = -ENOMEM;
1667 kfree(mysids);
1668 goto out;
1669 }
1670 for (i = 0, j = 0; i < mynel; i++) {
1671 rc = avc_has_perm_noaudit(fromsid, mysids[i],
1672 SECCLASS_PROCESS,
1673 PROCESS__TRANSITION, AVC_STRICT,
1674 NULL);
1675 if (!rc)
1676 mysids2[j++] = mysids[i];
1677 cond_resched();
1678 }
1679 rc = 0;
1680 kfree(mysids);
1681 *sids = mysids2;
1682 *nel = j;
1672out: 1683out:
1673 return rc; 1684 return rc;
1674} 1685}