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>
This commit is contained in:
committed by
James Morris
parent
9dc9978084
commit
2c3c05dbcb
@ -1587,19 +1587,18 @@ int security_get_user_sids(u32 fromsid,
|
||||
u32 *nel)
|
||||
{
|
||||
struct context *fromcon, usercon;
|
||||
u32 *mysids, *mysids2, sid;
|
||||
u32 *mysids = NULL, *mysids2, sid;
|
||||
u32 mynel = 0, maxnel = SIDS_NEL;
|
||||
struct user_datum *user;
|
||||
struct role_datum *role;
|
||||
struct av_decision avd;
|
||||
struct ebitmap_node *rnode, *tnode;
|
||||
int rc = 0, i, j;
|
||||
|
||||
if (!ss_initialized) {
|
||||
*sids = NULL;
|
||||
*nel = 0;
|
||||
*sids = NULL;
|
||||
*nel = 0;
|
||||
|
||||
if (!ss_initialized)
|
||||
goto out;
|
||||
}
|
||||
|
||||
POLICY_RDLOCK;
|
||||
|
||||
@ -1635,17 +1634,9 @@ int security_get_user_sids(u32 fromsid,
|
||||
if (mls_setup_user_range(fromcon, user, &usercon))
|
||||
continue;
|
||||
|
||||
rc = context_struct_compute_av(fromcon, &usercon,
|
||||
SECCLASS_PROCESS,
|
||||
PROCESS__TRANSITION,
|
||||
&avd);
|
||||
if (rc || !(avd.allowed & PROCESS__TRANSITION))
|
||||
continue;
|
||||
rc = sidtab_context_to_sid(&sidtab, &usercon, &sid);
|
||||
if (rc) {
|
||||
kfree(mysids);
|
||||
if (rc)
|
||||
goto out_unlock;
|
||||
}
|
||||
if (mynel < maxnel) {
|
||||
mysids[mynel++] = sid;
|
||||
} else {
|
||||
@ -1653,7 +1644,6 @@ int security_get_user_sids(u32 fromsid,
|
||||
mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
|
||||
if (!mysids2) {
|
||||
rc = -ENOMEM;
|
||||
kfree(mysids);
|
||||
goto out_unlock;
|
||||
}
|
||||
memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
|
||||
@ -1664,11 +1654,32 @@ int security_get_user_sids(u32 fromsid,
|
||||
}
|
||||
}
|
||||
|
||||
*sids = mysids;
|
||||
*nel = mynel;
|
||||
|
||||
out_unlock:
|
||||
POLICY_RDUNLOCK;
|
||||
if (rc || !mynel) {
|
||||
kfree(mysids);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
|
||||
if (!mysids2) {
|
||||
rc = -ENOMEM;
|
||||
kfree(mysids);
|
||||
goto out;
|
||||
}
|
||||
for (i = 0, j = 0; i < mynel; i++) {
|
||||
rc = avc_has_perm_noaudit(fromsid, mysids[i],
|
||||
SECCLASS_PROCESS,
|
||||
PROCESS__TRANSITION, AVC_STRICT,
|
||||
NULL);
|
||||
if (!rc)
|
||||
mysids2[j++] = mysids[i];
|
||||
cond_resched();
|
||||
}
|
||||
rc = 0;
|
||||
kfree(mysids);
|
||||
*sids = mysids2;
|
||||
*nel = j;
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
Reference in New Issue
Block a user