diff options
author | Stephen Smalley <sds@tycho.nsa.gov> | 2007-06-07 15:34:10 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2007-07-11 22:52:25 -0400 |
commit | 2c3c05dbcbc7b9d71549fe0e2b249f10f5a66518 (patch) | |
tree | bab75df9fafc435f3370a6d773d3284716347249 /security/selinux/ss/services.c | |
parent | 9dc9978084ea2a96b9f42752753d9e38a9f9d7b2 (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>
Diffstat (limited to 'security/selinux/ss/services.c')
-rw-r--r-- | security/selinux/ss/services.c | 49 |
1 files changed, 30 insertions, 19 deletions
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 | |||
1670 | out_unlock: | 1657 | out_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; | ||
1672 | out: | 1683 | out: |
1673 | return rc; | 1684 | return rc; |
1674 | } | 1685 | } |