mirror of https://gitee.com/openkylin/linux.git
selinux/stable-5.12 PR 20210409
-----BEGIN PGP SIGNATURE----- iQJIBAABCAAyFiEES0KozwfymdVUl37v6iDy2pc3iXMFAmBwjZcUHHBhdWxAcGF1 bC1tb29yZS5jb20ACgkQ6iDy2pc3iXOAcg//eZL4z0ksGo9s/Y+/9qOIYH2tMPU5 OOVZCekBENiq2LOuVbzAndeHOLZflf3iigBwtMvqHaAsdPAKH/3UedzD0/nxG39m S2gowEuNEfxtuBwuIZMFaMGzzLyjlZJ3xxi6omIyj/2JqPNyBbbFxR/VC4agJZI5 oG6VfwhZJmFi1oJiNoGKjwihKHZQ90yd8UU5rMI+Np0TnP1Or3OvRaZjR47r+dWS tAu3nTKrVEyGTcPeGzg9TS5tIko0jQ1FyrqPDBhfaJta48bX/9s70We6rwqJj8Vg HiiSDPMK5EKkPLso+1vqvBI9q6xdhNeS+M2JP+/ewK/cqVKMkTVVys6l+T3a6HcY rIXdgTWdMFiAQ6OW44z30fiwSxW3kI5M62um31nepoqvzX7acl6R1laILFztedWM EOfCznZmE6ccYmcZnrqEmNsdF+Se1TUiM87bN90tAGmF9F4Yw2qGM0raiV3OJhDZ P2zR/+DceSHI2pNfFtB5VVXZelHoKVhoRcRWvpzn7YW3UmnAl83HoJasBfa/j4rx qvo+nj5ptCSX/kUYjvfvrRV1rY/BAaSVlFLpgYKY1r8/hdRN5DLpdE5cHh6Gky6B fJen4a7yVecp8IKK+WR3maJ0hymo5ccUoB5AKzMOXeECKRqKkIDAKiEN59g9t96+ avKfojgsh1tNHA0= =mGDl -----END PGP SIGNATURE----- Merge tag 'selinux-pr-20210409' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux Pull selinux fixes from Paul Moore: "Three SELinux fixes. These fix known problems relating to (re)loading SELinux policy or changing the policy booleans, and pass our test suite without problem" * tag 'selinux-pr-20210409' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux: selinux: fix race between old and new sidtab selinux: fix cond_list corruption when changing booleans selinux: make nslot handling in avtab more robust
This commit is contained in:
commit
60144b23c9
|
@ -109,7 +109,7 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat
|
|||
struct avtab_node *prev, *cur, *newnode;
|
||||
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
|
||||
|
||||
if (!h)
|
||||
if (!h || !h->nslot)
|
||||
return -EINVAL;
|
||||
|
||||
hvalue = avtab_hash(key, h->mask);
|
||||
|
@ -154,7 +154,7 @@ avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datu
|
|||
struct avtab_node *prev, *cur;
|
||||
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
|
||||
|
||||
if (!h)
|
||||
if (!h || !h->nslot)
|
||||
return NULL;
|
||||
hvalue = avtab_hash(key, h->mask);
|
||||
for (prev = NULL, cur = h->htable[hvalue];
|
||||
|
@ -184,7 +184,7 @@ struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)
|
|||
struct avtab_node *cur;
|
||||
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
|
||||
|
||||
if (!h)
|
||||
if (!h || !h->nslot)
|
||||
return NULL;
|
||||
|
||||
hvalue = avtab_hash(key, h->mask);
|
||||
|
@ -220,7 +220,7 @@ avtab_search_node(struct avtab *h, struct avtab_key *key)
|
|||
struct avtab_node *cur;
|
||||
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
|
||||
|
||||
if (!h)
|
||||
if (!h || !h->nslot)
|
||||
return NULL;
|
||||
|
||||
hvalue = avtab_hash(key, h->mask);
|
||||
|
@ -295,6 +295,7 @@ void avtab_destroy(struct avtab *h)
|
|||
}
|
||||
kvfree(h->htable);
|
||||
h->htable = NULL;
|
||||
h->nel = 0;
|
||||
h->nslot = 0;
|
||||
h->mask = 0;
|
||||
}
|
||||
|
@ -303,88 +304,52 @@ void avtab_init(struct avtab *h)
|
|||
{
|
||||
h->htable = NULL;
|
||||
h->nel = 0;
|
||||
h->nslot = 0;
|
||||
h->mask = 0;
|
||||
}
|
||||
|
||||
int avtab_alloc(struct avtab *h, u32 nrules)
|
||||
static int avtab_alloc_common(struct avtab *h, u32 nslot)
|
||||
{
|
||||
u32 mask = 0;
|
||||
u32 shift = 0;
|
||||
u32 work = nrules;
|
||||
u32 nslot = 0;
|
||||
|
||||
if (nrules == 0)
|
||||
goto avtab_alloc_out;
|
||||
|
||||
while (work) {
|
||||
work = work >> 1;
|
||||
shift++;
|
||||
}
|
||||
if (shift > 2)
|
||||
shift = shift - 2;
|
||||
nslot = 1 << shift;
|
||||
if (nslot > MAX_AVTAB_HASH_BUCKETS)
|
||||
nslot = MAX_AVTAB_HASH_BUCKETS;
|
||||
mask = nslot - 1;
|
||||
if (!nslot)
|
||||
return 0;
|
||||
|
||||
h->htable = kvcalloc(nslot, sizeof(void *), GFP_KERNEL);
|
||||
if (!h->htable)
|
||||
return -ENOMEM;
|
||||
|
||||
avtab_alloc_out:
|
||||
h->nel = 0;
|
||||
h->nslot = nslot;
|
||||
h->mask = mask;
|
||||
pr_debug("SELinux: %d avtab hash slots, %d rules.\n",
|
||||
h->nslot, nrules);
|
||||
h->mask = nslot - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int avtab_duplicate(struct avtab *new, struct avtab *orig)
|
||||
int avtab_alloc(struct avtab *h, u32 nrules)
|
||||
{
|
||||
int i;
|
||||
struct avtab_node *node, *tmp, *tail;
|
||||
int rc;
|
||||
u32 nslot = 0;
|
||||
|
||||
memset(new, 0, sizeof(*new));
|
||||
|
||||
new->htable = kvcalloc(orig->nslot, sizeof(void *), GFP_KERNEL);
|
||||
if (!new->htable)
|
||||
return -ENOMEM;
|
||||
new->nslot = orig->nslot;
|
||||
new->mask = orig->mask;
|
||||
|
||||
for (i = 0; i < orig->nslot; i++) {
|
||||
tail = NULL;
|
||||
for (node = orig->htable[i]; node; node = node->next) {
|
||||
tmp = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL);
|
||||
if (!tmp)
|
||||
goto error;
|
||||
tmp->key = node->key;
|
||||
if (tmp->key.specified & AVTAB_XPERMS) {
|
||||
tmp->datum.u.xperms =
|
||||
kmem_cache_zalloc(avtab_xperms_cachep,
|
||||
GFP_KERNEL);
|
||||
if (!tmp->datum.u.xperms) {
|
||||
kmem_cache_free(avtab_node_cachep, tmp);
|
||||
goto error;
|
||||
}
|
||||
tmp->datum.u.xperms = node->datum.u.xperms;
|
||||
} else
|
||||
tmp->datum.u.data = node->datum.u.data;
|
||||
|
||||
if (tail)
|
||||
tail->next = tmp;
|
||||
else
|
||||
new->htable[i] = tmp;
|
||||
|
||||
tail = tmp;
|
||||
new->nel++;
|
||||
if (nrules != 0) {
|
||||
u32 shift = 1;
|
||||
u32 work = nrules >> 3;
|
||||
while (work) {
|
||||
work >>= 1;
|
||||
shift++;
|
||||
}
|
||||
nslot = 1 << shift;
|
||||
if (nslot > MAX_AVTAB_HASH_BUCKETS)
|
||||
nslot = MAX_AVTAB_HASH_BUCKETS;
|
||||
|
||||
rc = avtab_alloc_common(h, nslot);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
pr_debug("SELinux: %d avtab hash slots, %d rules.\n", nslot, nrules);
|
||||
return 0;
|
||||
error:
|
||||
avtab_destroy(new);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int avtab_alloc_dup(struct avtab *new, const struct avtab *orig)
|
||||
{
|
||||
return avtab_alloc_common(new, orig->nslot);
|
||||
}
|
||||
|
||||
void avtab_hash_eval(struct avtab *h, char *tag)
|
||||
|
|
|
@ -89,7 +89,7 @@ struct avtab {
|
|||
|
||||
void avtab_init(struct avtab *h);
|
||||
int avtab_alloc(struct avtab *, u32);
|
||||
int avtab_duplicate(struct avtab *new, struct avtab *orig);
|
||||
int avtab_alloc_dup(struct avtab *new, const struct avtab *orig);
|
||||
struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
|
||||
void avtab_destroy(struct avtab *h);
|
||||
void avtab_hash_eval(struct avtab *h, char *tag);
|
||||
|
|
|
@ -605,7 +605,6 @@ static int cond_dup_av_list(struct cond_av_list *new,
|
|||
struct cond_av_list *orig,
|
||||
struct avtab *avtab)
|
||||
{
|
||||
struct avtab_node *avnode;
|
||||
u32 i;
|
||||
|
||||
memset(new, 0, sizeof(*new));
|
||||
|
@ -615,10 +614,11 @@ static int cond_dup_av_list(struct cond_av_list *new,
|
|||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < orig->len; i++) {
|
||||
avnode = avtab_search_node(avtab, &orig->nodes[i]->key);
|
||||
if (WARN_ON(!avnode))
|
||||
return -EINVAL;
|
||||
new->nodes[i] = avnode;
|
||||
new->nodes[i] = avtab_insert_nonunique(avtab,
|
||||
&orig->nodes[i]->key,
|
||||
&orig->nodes[i]->datum);
|
||||
if (!new->nodes[i])
|
||||
return -ENOMEM;
|
||||
new->len++;
|
||||
}
|
||||
|
||||
|
@ -630,7 +630,7 @@ static int duplicate_policydb_cond_list(struct policydb *newp,
|
|||
{
|
||||
int rc, i, j;
|
||||
|
||||
rc = avtab_duplicate(&newp->te_cond_avtab, &origp->te_cond_avtab);
|
||||
rc = avtab_alloc_dup(&newp->te_cond_avtab, &origp->te_cond_avtab);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
|
@ -1552,6 +1552,7 @@ static int security_context_to_sid_core(struct selinux_state *state,
|
|||
if (!str)
|
||||
goto out;
|
||||
}
|
||||
retry:
|
||||
rcu_read_lock();
|
||||
policy = rcu_dereference(state->policy);
|
||||
policydb = &policy->policydb;
|
||||
|
@ -1565,6 +1566,15 @@ static int security_context_to_sid_core(struct selinux_state *state,
|
|||
} else if (rc)
|
||||
goto out_unlock;
|
||||
rc = sidtab_context_to_sid(sidtab, &context, sid);
|
||||
if (rc == -ESTALE) {
|
||||
rcu_read_unlock();
|
||||
if (context.str) {
|
||||
str = context.str;
|
||||
context.str = NULL;
|
||||
}
|
||||
context_destroy(&context);
|
||||
goto retry;
|
||||
}
|
||||
context_destroy(&context);
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
|
@ -1714,7 +1724,7 @@ static int security_compute_sid(struct selinux_state *state,
|
|||
struct selinux_policy *policy;
|
||||
struct policydb *policydb;
|
||||
struct sidtab *sidtab;
|
||||
struct class_datum *cladatum = NULL;
|
||||
struct class_datum *cladatum;
|
||||
struct context *scontext, *tcontext, newcontext;
|
||||
struct sidtab_entry *sentry, *tentry;
|
||||
struct avtab_key avkey;
|
||||
|
@ -1736,6 +1746,8 @@ static int security_compute_sid(struct selinux_state *state,
|
|||
goto out;
|
||||
}
|
||||
|
||||
retry:
|
||||
cladatum = NULL;
|
||||
context_init(&newcontext);
|
||||
|
||||
rcu_read_lock();
|
||||
|
@ -1880,6 +1892,11 @@ static int security_compute_sid(struct selinux_state *state,
|
|||
}
|
||||
/* Obtain the sid for the context. */
|
||||
rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid);
|
||||
if (rc == -ESTALE) {
|
||||
rcu_read_unlock();
|
||||
context_destroy(&newcontext);
|
||||
goto retry;
|
||||
}
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
context_destroy(&newcontext);
|
||||
|
@ -2192,6 +2209,7 @@ void selinux_policy_commit(struct selinux_state *state,
|
|||
struct selinux_load_state *load_state)
|
||||
{
|
||||
struct selinux_policy *oldpolicy, *newpolicy = load_state->policy;
|
||||
unsigned long flags;
|
||||
u32 seqno;
|
||||
|
||||
oldpolicy = rcu_dereference_protected(state->policy,
|
||||
|
@ -2213,7 +2231,13 @@ void selinux_policy_commit(struct selinux_state *state,
|
|||
seqno = newpolicy->latest_granting;
|
||||
|
||||
/* Install the new policy. */
|
||||
rcu_assign_pointer(state->policy, newpolicy);
|
||||
if (oldpolicy) {
|
||||
sidtab_freeze_begin(oldpolicy->sidtab, &flags);
|
||||
rcu_assign_pointer(state->policy, newpolicy);
|
||||
sidtab_freeze_end(oldpolicy->sidtab, &flags);
|
||||
} else {
|
||||
rcu_assign_pointer(state->policy, newpolicy);
|
||||
}
|
||||
|
||||
/* Load the policycaps from the new policy */
|
||||
security_load_policycaps(state, newpolicy);
|
||||
|
@ -2357,13 +2381,15 @@ int security_port_sid(struct selinux_state *state,
|
|||
struct policydb *policydb;
|
||||
struct sidtab *sidtab;
|
||||
struct ocontext *c;
|
||||
int rc = 0;
|
||||
int rc;
|
||||
|
||||
if (!selinux_initialized(state)) {
|
||||
*out_sid = SECINITSID_PORT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
retry:
|
||||
rc = 0;
|
||||
rcu_read_lock();
|
||||
policy = rcu_dereference(state->policy);
|
||||
policydb = &policy->policydb;
|
||||
|
@ -2382,6 +2408,10 @@ int security_port_sid(struct selinux_state *state,
|
|||
if (!c->sid[0]) {
|
||||
rc = sidtab_context_to_sid(sidtab, &c->context[0],
|
||||
&c->sid[0]);
|
||||
if (rc == -ESTALE) {
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
}
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
@ -2408,13 +2438,15 @@ int security_ib_pkey_sid(struct selinux_state *state,
|
|||
struct policydb *policydb;
|
||||
struct sidtab *sidtab;
|
||||
struct ocontext *c;
|
||||
int rc = 0;
|
||||
int rc;
|
||||
|
||||
if (!selinux_initialized(state)) {
|
||||
*out_sid = SECINITSID_UNLABELED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
retry:
|
||||
rc = 0;
|
||||
rcu_read_lock();
|
||||
policy = rcu_dereference(state->policy);
|
||||
policydb = &policy->policydb;
|
||||
|
@ -2435,6 +2467,10 @@ int security_ib_pkey_sid(struct selinux_state *state,
|
|||
rc = sidtab_context_to_sid(sidtab,
|
||||
&c->context[0],
|
||||
&c->sid[0]);
|
||||
if (rc == -ESTALE) {
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
}
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
@ -2460,13 +2496,15 @@ int security_ib_endport_sid(struct selinux_state *state,
|
|||
struct policydb *policydb;
|
||||
struct sidtab *sidtab;
|
||||
struct ocontext *c;
|
||||
int rc = 0;
|
||||
int rc;
|
||||
|
||||
if (!selinux_initialized(state)) {
|
||||
*out_sid = SECINITSID_UNLABELED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
retry:
|
||||
rc = 0;
|
||||
rcu_read_lock();
|
||||
policy = rcu_dereference(state->policy);
|
||||
policydb = &policy->policydb;
|
||||
|
@ -2487,6 +2525,10 @@ int security_ib_endport_sid(struct selinux_state *state,
|
|||
if (!c->sid[0]) {
|
||||
rc = sidtab_context_to_sid(sidtab, &c->context[0],
|
||||
&c->sid[0]);
|
||||
if (rc == -ESTALE) {
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
}
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
@ -2510,7 +2552,7 @@ int security_netif_sid(struct selinux_state *state,
|
|||
struct selinux_policy *policy;
|
||||
struct policydb *policydb;
|
||||
struct sidtab *sidtab;
|
||||
int rc = 0;
|
||||
int rc;
|
||||
struct ocontext *c;
|
||||
|
||||
if (!selinux_initialized(state)) {
|
||||
|
@ -2518,6 +2560,8 @@ int security_netif_sid(struct selinux_state *state,
|
|||
return 0;
|
||||
}
|
||||
|
||||
retry:
|
||||
rc = 0;
|
||||
rcu_read_lock();
|
||||
policy = rcu_dereference(state->policy);
|
||||
policydb = &policy->policydb;
|
||||
|
@ -2534,10 +2578,18 @@ int security_netif_sid(struct selinux_state *state,
|
|||
if (!c->sid[0] || !c->sid[1]) {
|
||||
rc = sidtab_context_to_sid(sidtab, &c->context[0],
|
||||
&c->sid[0]);
|
||||
if (rc == -ESTALE) {
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
}
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = sidtab_context_to_sid(sidtab, &c->context[1],
|
||||
&c->sid[1]);
|
||||
if (rc == -ESTALE) {
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
}
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
@ -2587,6 +2639,7 @@ int security_node_sid(struct selinux_state *state,
|
|||
return 0;
|
||||
}
|
||||
|
||||
retry:
|
||||
rcu_read_lock();
|
||||
policy = rcu_dereference(state->policy);
|
||||
policydb = &policy->policydb;
|
||||
|
@ -2635,6 +2688,10 @@ int security_node_sid(struct selinux_state *state,
|
|||
rc = sidtab_context_to_sid(sidtab,
|
||||
&c->context[0],
|
||||
&c->sid[0]);
|
||||
if (rc == -ESTALE) {
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
}
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
@ -2676,18 +2733,24 @@ int security_get_user_sids(struct selinux_state *state,
|
|||
struct sidtab *sidtab;
|
||||
struct context *fromcon, usercon;
|
||||
u32 *mysids = NULL, *mysids2, sid;
|
||||
u32 mynel = 0, maxnel = SIDS_NEL;
|
||||
u32 i, j, mynel, maxnel = SIDS_NEL;
|
||||
struct user_datum *user;
|
||||
struct role_datum *role;
|
||||
struct ebitmap_node *rnode, *tnode;
|
||||
int rc = 0, i, j;
|
||||
int rc;
|
||||
|
||||
*sids = NULL;
|
||||
*nel = 0;
|
||||
|
||||
if (!selinux_initialized(state))
|
||||
goto out;
|
||||
return 0;
|
||||
|
||||
mysids = kcalloc(maxnel, sizeof(*mysids), GFP_KERNEL);
|
||||
if (!mysids)
|
||||
return -ENOMEM;
|
||||
|
||||
retry:
|
||||
mynel = 0;
|
||||
rcu_read_lock();
|
||||
policy = rcu_dereference(state->policy);
|
||||
policydb = &policy->policydb;
|
||||
|
@ -2707,11 +2770,6 @@ int security_get_user_sids(struct selinux_state *state,
|
|||
|
||||
usercon.user = user->value;
|
||||
|
||||
rc = -ENOMEM;
|
||||
mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC);
|
||||
if (!mysids)
|
||||
goto out_unlock;
|
||||
|
||||
ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
|
||||
role = policydb->role_val_to_struct[i];
|
||||
usercon.role = i + 1;
|
||||
|
@ -2723,6 +2781,10 @@ int security_get_user_sids(struct selinux_state *state,
|
|||
continue;
|
||||
|
||||
rc = sidtab_context_to_sid(sidtab, &usercon, &sid);
|
||||
if (rc == -ESTALE) {
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
}
|
||||
if (rc)
|
||||
goto out_unlock;
|
||||
if (mynel < maxnel) {
|
||||
|
@ -2745,14 +2807,14 @@ int security_get_user_sids(struct selinux_state *state,
|
|||
rcu_read_unlock();
|
||||
if (rc || !mynel) {
|
||||
kfree(mysids);
|
||||
goto out;
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = -ENOMEM;
|
||||
mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
|
||||
if (!mysids2) {
|
||||
kfree(mysids);
|
||||
goto out;
|
||||
return rc;
|
||||
}
|
||||
for (i = 0, j = 0; i < mynel; i++) {
|
||||
struct av_decision dummy_avd;
|
||||
|
@ -2765,12 +2827,10 @@ int security_get_user_sids(struct selinux_state *state,
|
|||
mysids2[j++] = mysids[i];
|
||||
cond_resched();
|
||||
}
|
||||
rc = 0;
|
||||
kfree(mysids);
|
||||
*sids = mysids2;
|
||||
*nel = j;
|
||||
out:
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2783,6 +2843,9 @@ int security_get_user_sids(struct selinux_state *state,
|
|||
* Obtain a SID to use for a file in a filesystem that
|
||||
* cannot support xattr or use a fixed labeling behavior like
|
||||
* transition SIDs or task SIDs.
|
||||
*
|
||||
* WARNING: This function may return -ESTALE, indicating that the caller
|
||||
* must retry the operation after re-acquiring the policy pointer!
|
||||
*/
|
||||
static inline int __security_genfs_sid(struct selinux_policy *policy,
|
||||
const char *fstype,
|
||||
|
@ -2861,11 +2924,13 @@ int security_genfs_sid(struct selinux_state *state,
|
|||
return 0;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
policy = rcu_dereference(state->policy);
|
||||
retval = __security_genfs_sid(policy,
|
||||
fstype, path, orig_sclass, sid);
|
||||
rcu_read_unlock();
|
||||
do {
|
||||
rcu_read_lock();
|
||||
policy = rcu_dereference(state->policy);
|
||||
retval = __security_genfs_sid(policy, fstype, path,
|
||||
orig_sclass, sid);
|
||||
rcu_read_unlock();
|
||||
} while (retval == -ESTALE);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -2888,7 +2953,7 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
|
|||
struct selinux_policy *policy;
|
||||
struct policydb *policydb;
|
||||
struct sidtab *sidtab;
|
||||
int rc = 0;
|
||||
int rc;
|
||||
struct ocontext *c;
|
||||
struct superblock_security_struct *sbsec = sb->s_security;
|
||||
const char *fstype = sb->s_type->name;
|
||||
|
@ -2899,6 +2964,8 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
retry:
|
||||
rc = 0;
|
||||
rcu_read_lock();
|
||||
policy = rcu_dereference(state->policy);
|
||||
policydb = &policy->policydb;
|
||||
|
@ -2916,6 +2983,10 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
|
|||
if (!c->sid[0]) {
|
||||
rc = sidtab_context_to_sid(sidtab, &c->context[0],
|
||||
&c->sid[0]);
|
||||
if (rc == -ESTALE) {
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
}
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
@ -2923,6 +2994,10 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
|
|||
} else {
|
||||
rc = __security_genfs_sid(policy, fstype, "/",
|
||||
SECCLASS_DIR, &sbsec->sid);
|
||||
if (rc == -ESTALE) {
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
}
|
||||
if (rc) {
|
||||
sbsec->behavior = SECURITY_FS_USE_NONE;
|
||||
rc = 0;
|
||||
|
@ -3132,12 +3207,13 @@ int security_sid_mls_copy(struct selinux_state *state,
|
|||
u32 len;
|
||||
int rc;
|
||||
|
||||
rc = 0;
|
||||
if (!selinux_initialized(state)) {
|
||||
*new_sid = sid;
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
retry:
|
||||
rc = 0;
|
||||
context_init(&newcon);
|
||||
|
||||
rcu_read_lock();
|
||||
|
@ -3196,10 +3272,14 @@ int security_sid_mls_copy(struct selinux_state *state,
|
|||
}
|
||||
}
|
||||
rc = sidtab_context_to_sid(sidtab, &newcon, new_sid);
|
||||
if (rc == -ESTALE) {
|
||||
rcu_read_unlock();
|
||||
context_destroy(&newcon);
|
||||
goto retry;
|
||||
}
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
context_destroy(&newcon);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -3792,6 +3872,8 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state,
|
|||
return 0;
|
||||
}
|
||||
|
||||
retry:
|
||||
rc = 0;
|
||||
rcu_read_lock();
|
||||
policy = rcu_dereference(state->policy);
|
||||
policydb = &policy->policydb;
|
||||
|
@ -3818,23 +3900,24 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state,
|
|||
goto out;
|
||||
}
|
||||
rc = -EIDRM;
|
||||
if (!mls_context_isvalid(policydb, &ctx_new))
|
||||
goto out_free;
|
||||
if (!mls_context_isvalid(policydb, &ctx_new)) {
|
||||
ebitmap_destroy(&ctx_new.range.level[0].cat);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = sidtab_context_to_sid(sidtab, &ctx_new, sid);
|
||||
ebitmap_destroy(&ctx_new.range.level[0].cat);
|
||||
if (rc == -ESTALE) {
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
}
|
||||
if (rc)
|
||||
goto out_free;
|
||||
goto out;
|
||||
|
||||
security_netlbl_cache_add(secattr, *sid);
|
||||
|
||||
ebitmap_destroy(&ctx_new.range.level[0].cat);
|
||||
} else
|
||||
*sid = SECSID_NULL;
|
||||
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
out_free:
|
||||
ebitmap_destroy(&ctx_new.range.level[0].cat);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
return rc;
|
||||
|
|
|
@ -39,6 +39,7 @@ int sidtab_init(struct sidtab *s)
|
|||
for (i = 0; i < SECINITSID_NUM; i++)
|
||||
s->isids[i].set = 0;
|
||||
|
||||
s->frozen = false;
|
||||
s->count = 0;
|
||||
s->convert = NULL;
|
||||
hash_init(s->context_to_sid);
|
||||
|
@ -281,6 +282,15 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context,
|
|||
if (*sid)
|
||||
goto out_unlock;
|
||||
|
||||
if (unlikely(s->frozen)) {
|
||||
/*
|
||||
* This sidtab is now frozen - tell the caller to abort and
|
||||
* get the new one.
|
||||
*/
|
||||
rc = -ESTALE;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
count = s->count;
|
||||
convert = s->convert;
|
||||
|
||||
|
@ -474,6 +484,17 @@ void sidtab_cancel_convert(struct sidtab *s)
|
|||
spin_unlock_irqrestore(&s->lock, flags);
|
||||
}
|
||||
|
||||
void sidtab_freeze_begin(struct sidtab *s, unsigned long *flags) __acquires(&s->lock)
|
||||
{
|
||||
spin_lock_irqsave(&s->lock, *flags);
|
||||
s->frozen = true;
|
||||
s->convert = NULL;
|
||||
}
|
||||
void sidtab_freeze_end(struct sidtab *s, unsigned long *flags) __releases(&s->lock)
|
||||
{
|
||||
spin_unlock_irqrestore(&s->lock, *flags);
|
||||
}
|
||||
|
||||
static void sidtab_destroy_entry(struct sidtab_entry *entry)
|
||||
{
|
||||
context_destroy(&entry->context);
|
||||
|
|
|
@ -86,6 +86,7 @@ struct sidtab {
|
|||
u32 count;
|
||||
/* access only under spinlock */
|
||||
struct sidtab_convert_params *convert;
|
||||
bool frozen;
|
||||
spinlock_t lock;
|
||||
|
||||
#if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0
|
||||
|
@ -125,6 +126,9 @@ int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params);
|
|||
|
||||
void sidtab_cancel_convert(struct sidtab *s);
|
||||
|
||||
void sidtab_freeze_begin(struct sidtab *s, unsigned long *flags) __acquires(&s->lock);
|
||||
void sidtab_freeze_end(struct sidtab *s, unsigned long *flags) __releases(&s->lock);
|
||||
|
||||
int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid);
|
||||
|
||||
void sidtab_destroy(struct sidtab *s);
|
||||
|
|
Loading…
Reference in New Issue