forked from luck/tmp_suning_uos_patched
selinux: store role transitions in a hash table
Currently, they are stored in a linked list, which adds significant overhead to security_transition_sid(). On Fedora, with 428 role transitions in policy, converting this list to a hash table cuts down its run time by about 50%. This was measured by running 'stress-ng --msg 1 --msg-ops 100000' under perf with and without this patch. Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com> Signed-off-by: Paul Moore <paul@paul-moore.com>
This commit is contained in:
parent
433e3aa377
commit
e67b2ec9f6
|
@ -352,6 +352,13 @@ static int range_tr_destroy(void *key, void *datum, void *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int role_tr_destroy(void *key, void *datum, void *p)
|
||||
{
|
||||
kfree(key);
|
||||
kfree(datum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ocontext_destroy(struct ocontext *c, int i)
|
||||
{
|
||||
if (!c)
|
||||
|
@ -458,6 +465,30 @@ static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2)
|
|||
return v;
|
||||
}
|
||||
|
||||
static u32 role_trans_hash(struct hashtab *h, const void *k)
|
||||
{
|
||||
const struct role_trans_key *key = k;
|
||||
|
||||
return (key->role + (key->type << 3) + (key->tclass << 5)) &
|
||||
(h->size - 1);
|
||||
}
|
||||
|
||||
static int role_trans_cmp(struct hashtab *h, const void *k1, const void *k2)
|
||||
{
|
||||
const struct role_trans_key *key1 = k1, *key2 = k2;
|
||||
int v;
|
||||
|
||||
v = key1->role - key2->role;
|
||||
if (v)
|
||||
return v;
|
||||
|
||||
v = key1->type - key2->type;
|
||||
if (v)
|
||||
return v;
|
||||
|
||||
return key1->tclass - key2->tclass;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a policy database structure.
|
||||
*/
|
||||
|
@ -728,7 +759,6 @@ void policydb_destroy(struct policydb *p)
|
|||
struct genfs *g, *gtmp;
|
||||
int i;
|
||||
struct role_allow *ra, *lra = NULL;
|
||||
struct role_trans *tr, *ltr = NULL;
|
||||
|
||||
for (i = 0; i < SYM_NUM; i++) {
|
||||
cond_resched();
|
||||
|
@ -775,12 +805,8 @@ void policydb_destroy(struct policydb *p)
|
|||
|
||||
cond_policydb_destroy(p);
|
||||
|
||||
for (tr = p->role_tr; tr; tr = tr->next) {
|
||||
cond_resched();
|
||||
kfree(ltr);
|
||||
ltr = tr;
|
||||
}
|
||||
kfree(ltr);
|
||||
hashtab_map(p->role_tr, role_tr_destroy, NULL);
|
||||
hashtab_destroy(p->role_tr);
|
||||
|
||||
for (ra = p->role_allow; ra; ra = ra->next) {
|
||||
cond_resched();
|
||||
|
@ -2251,7 +2277,8 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
|
|||
int policydb_read(struct policydb *p, void *fp)
|
||||
{
|
||||
struct role_allow *ra, *lra;
|
||||
struct role_trans *tr, *ltr;
|
||||
struct role_trans_key *rtk = NULL;
|
||||
struct role_trans_datum *rtd = NULL;
|
||||
int i, j, rc;
|
||||
__le32 buf[4];
|
||||
u32 len, nprim, nel;
|
||||
|
@ -2416,39 +2443,50 @@ int policydb_read(struct policydb *p, void *fp)
|
|||
if (rc)
|
||||
goto bad;
|
||||
nel = le32_to_cpu(buf[0]);
|
||||
ltr = NULL;
|
||||
|
||||
p->role_tr = hashtab_create(role_trans_hash, role_trans_cmp, nel);
|
||||
if (!p->role_tr)
|
||||
goto bad;
|
||||
for (i = 0; i < nel; i++) {
|
||||
rc = -ENOMEM;
|
||||
tr = kzalloc(sizeof(*tr), GFP_KERNEL);
|
||||
if (!tr)
|
||||
rtk = kmalloc(sizeof(*rtk), GFP_KERNEL);
|
||||
if (!rtk)
|
||||
goto bad;
|
||||
if (ltr)
|
||||
ltr->next = tr;
|
||||
else
|
||||
p->role_tr = tr;
|
||||
|
||||
rc = -ENOMEM;
|
||||
rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
|
||||
if (!rtd)
|
||||
goto bad;
|
||||
|
||||
rc = next_entry(buf, fp, sizeof(u32)*3);
|
||||
if (rc)
|
||||
goto bad;
|
||||
|
||||
rc = -EINVAL;
|
||||
tr->role = le32_to_cpu(buf[0]);
|
||||
tr->type = le32_to_cpu(buf[1]);
|
||||
tr->new_role = le32_to_cpu(buf[2]);
|
||||
rtk->role = le32_to_cpu(buf[0]);
|
||||
rtk->type = le32_to_cpu(buf[1]);
|
||||
rtd->new_role = le32_to_cpu(buf[2]);
|
||||
if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
|
||||
rc = next_entry(buf, fp, sizeof(u32));
|
||||
if (rc)
|
||||
goto bad;
|
||||
tr->tclass = le32_to_cpu(buf[0]);
|
||||
rtk->tclass = le32_to_cpu(buf[0]);
|
||||
} else
|
||||
tr->tclass = p->process_class;
|
||||
rtk->tclass = p->process_class;
|
||||
|
||||
rc = -EINVAL;
|
||||
if (!policydb_role_isvalid(p, tr->role) ||
|
||||
!policydb_type_isvalid(p, tr->type) ||
|
||||
!policydb_class_isvalid(p, tr->tclass) ||
|
||||
!policydb_role_isvalid(p, tr->new_role))
|
||||
if (!policydb_role_isvalid(p, rtk->role) ||
|
||||
!policydb_type_isvalid(p, rtk->type) ||
|
||||
!policydb_class_isvalid(p, rtk->tclass) ||
|
||||
!policydb_role_isvalid(p, rtd->new_role))
|
||||
goto bad;
|
||||
ltr = tr;
|
||||
|
||||
rc = hashtab_insert(p->role_tr, rtk, rtd);
|
||||
if (rc)
|
||||
goto bad;
|
||||
|
||||
rtk = NULL;
|
||||
rtd = NULL;
|
||||
}
|
||||
|
||||
rc = next_entry(buf, fp, sizeof(u32));
|
||||
|
@ -2536,6 +2574,8 @@ int policydb_read(struct policydb *p, void *fp)
|
|||
out:
|
||||
return rc;
|
||||
bad:
|
||||
kfree(rtk);
|
||||
kfree(rtd);
|
||||
policydb_destroy(p);
|
||||
goto out;
|
||||
}
|
||||
|
@ -2653,37 +2693,43 @@ static int cat_write(void *vkey, void *datum, void *ptr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int role_trans_write(struct policydb *p, void *fp)
|
||||
static int role_trans_write_one(void *key, void *datum, void *ptr)
|
||||
{
|
||||
struct role_trans *r = p->role_tr;
|
||||
struct role_trans *tr;
|
||||
struct role_trans_key *rtk = key;
|
||||
struct role_trans_datum *rtd = datum;
|
||||
struct policy_data *pd = ptr;
|
||||
void *fp = pd->fp;
|
||||
struct policydb *p = pd->p;
|
||||
__le32 buf[3];
|
||||
size_t nel;
|
||||
int rc;
|
||||
|
||||
nel = 0;
|
||||
for (tr = r; tr; tr = tr->next)
|
||||
nel++;
|
||||
buf[0] = cpu_to_le32(nel);
|
||||
buf[0] = cpu_to_le32(rtk->role);
|
||||
buf[1] = cpu_to_le32(rtk->type);
|
||||
buf[2] = cpu_to_le32(rtd->new_role);
|
||||
rc = put_entry(buf, sizeof(u32), 3, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
|
||||
buf[0] = cpu_to_le32(rtk->tclass);
|
||||
rc = put_entry(buf, sizeof(u32), 1, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int role_trans_write(struct policydb *p, void *fp)
|
||||
{
|
||||
struct policy_data pd = { .p = p, .fp = fp };
|
||||
__le32 buf[1];
|
||||
int rc;
|
||||
|
||||
buf[0] = cpu_to_le32(p->role_tr->nel);
|
||||
rc = put_entry(buf, sizeof(u32), 1, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
for (tr = r; tr; tr = tr->next) {
|
||||
buf[0] = cpu_to_le32(tr->role);
|
||||
buf[1] = cpu_to_le32(tr->type);
|
||||
buf[2] = cpu_to_le32(tr->new_role);
|
||||
rc = put_entry(buf, sizeof(u32), 3, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
|
||||
buf[0] = cpu_to_le32(tr->tclass);
|
||||
rc = put_entry(buf, sizeof(u32), 1, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return hashtab_map(p->role_tr, role_trans_write_one, &pd);
|
||||
}
|
||||
|
||||
static int role_allow_write(struct role_allow *r, void *fp)
|
||||
|
|
|
@ -81,12 +81,14 @@ struct role_datum {
|
|||
struct ebitmap types; /* set of authorized types for role */
|
||||
};
|
||||
|
||||
struct role_trans {
|
||||
struct role_trans_key {
|
||||
u32 role; /* current role */
|
||||
u32 type; /* program executable type, or new object type */
|
||||
u32 tclass; /* process class, or new object class */
|
||||
};
|
||||
|
||||
struct role_trans_datum {
|
||||
u32 new_role; /* new role */
|
||||
struct role_trans *next;
|
||||
};
|
||||
|
||||
struct filename_trans_key {
|
||||
|
@ -261,7 +263,7 @@ struct policydb {
|
|||
struct avtab te_avtab;
|
||||
|
||||
/* role transitions */
|
||||
struct role_trans *role_tr;
|
||||
struct hashtab *role_tr;
|
||||
|
||||
/* file transitions with the last path component */
|
||||
/* quickly exclude lookups when parent ttype has no rules */
|
||||
|
|
|
@ -1731,7 +1731,6 @@ static int security_compute_sid(struct selinux_state *state,
|
|||
struct class_datum *cladatum = NULL;
|
||||
struct context *scontext, *tcontext, newcontext;
|
||||
struct sidtab_entry *sentry, *tentry;
|
||||
struct role_trans *roletr = NULL;
|
||||
struct avtab_key avkey;
|
||||
struct avtab_datum *avdatum;
|
||||
struct avtab_node *node;
|
||||
|
@ -1864,16 +1863,16 @@ static int security_compute_sid(struct selinux_state *state,
|
|||
/* Check for class-specific changes. */
|
||||
if (specified & AVTAB_TRANSITION) {
|
||||
/* Look for a role transition rule. */
|
||||
for (roletr = policydb->role_tr; roletr;
|
||||
roletr = roletr->next) {
|
||||
if ((roletr->role == scontext->role) &&
|
||||
(roletr->type == tcontext->type) &&
|
||||
(roletr->tclass == tclass)) {
|
||||
/* Use the role transition rule. */
|
||||
newcontext.role = roletr->new_role;
|
||||
break;
|
||||
}
|
||||
}
|
||||
struct role_trans_datum *rtd;
|
||||
struct role_trans_key rtk = {
|
||||
.role = scontext->role,
|
||||
.type = tcontext->type,
|
||||
.tclass = tclass,
|
||||
};
|
||||
|
||||
rtd = hashtab_search(policydb->role_tr, &rtk);
|
||||
if (rtd)
|
||||
newcontext.role = rtd->new_role;
|
||||
}
|
||||
|
||||
/* Set the MLS attributes.
|
||||
|
|
Loading…
Reference in New Issue
Block a user