SELinux: put name based create rules in a hashtable
To shorten the list we need to run if filename trans rules exist for the type of the given parent directory I put them in a hashtable. Given the policy we are expecting to use in Fedora this takes the worst case list run from about 5,000 entries to 17. Signed-off-by: Eric Paris <eparis@redhat.com> Reviewed-by: James Morris <jmorris@namei.org>
This commit is contained in:
parent
3f058ef778
commit
2463c26d50
|
@ -184,6 +184,43 @@ out:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 filenametr_hash(struct hashtab *h, const void *k)
|
||||||
|
{
|
||||||
|
const struct filename_trans *ft = k;
|
||||||
|
unsigned long hash;
|
||||||
|
unsigned int byte_num;
|
||||||
|
unsigned char focus;
|
||||||
|
|
||||||
|
hash = ft->stype ^ ft->ttype ^ ft->tclass;
|
||||||
|
|
||||||
|
byte_num = 0;
|
||||||
|
while ((focus = ft->name[byte_num++]))
|
||||||
|
hash = partial_name_hash(focus, hash);
|
||||||
|
return hash & (h->size - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2)
|
||||||
|
{
|
||||||
|
const struct filename_trans *ft1 = k1;
|
||||||
|
const struct filename_trans *ft2 = k2;
|
||||||
|
int v;
|
||||||
|
|
||||||
|
v = ft1->stype - ft2->stype;
|
||||||
|
if (v)
|
||||||
|
return v;
|
||||||
|
|
||||||
|
v = ft1->ttype - ft2->ttype;
|
||||||
|
if (v)
|
||||||
|
return v;
|
||||||
|
|
||||||
|
v = ft1->tclass - ft2->tclass;
|
||||||
|
if (v)
|
||||||
|
return v;
|
||||||
|
|
||||||
|
return strcmp(ft1->name, ft2->name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static u32 rangetr_hash(struct hashtab *h, const void *k)
|
static u32 rangetr_hash(struct hashtab *h, const void *k)
|
||||||
{
|
{
|
||||||
const struct range_trans *key = k;
|
const struct range_trans *key = k;
|
||||||
|
@ -236,6 +273,10 @@ static int policydb_init(struct policydb *p)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10));
|
||||||
|
if (!p->filename_trans)
|
||||||
|
goto out;
|
||||||
|
|
||||||
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
|
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
|
||||||
if (!p->range_tr)
|
if (!p->range_tr)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -246,6 +287,8 @@ static int policydb_init(struct policydb *p)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
out:
|
out:
|
||||||
|
hashtab_destroy(p->filename_trans);
|
||||||
|
hashtab_destroy(p->range_tr);
|
||||||
for (i = 0; i < SYM_NUM; i++)
|
for (i = 0; i < SYM_NUM; i++)
|
||||||
hashtab_destroy(p->symtab[i].table);
|
hashtab_destroy(p->symtab[i].table);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -675,6 +718,16 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
|
||||||
cat_destroy,
|
cat_destroy,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int filenametr_destroy(void *key, void *datum, void *p)
|
||||||
|
{
|
||||||
|
struct filename_trans *ft = key;
|
||||||
|
kfree(ft->name);
|
||||||
|
kfree(key);
|
||||||
|
kfree(datum);
|
||||||
|
cond_resched();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int range_tr_destroy(void *key, void *datum, void *p)
|
static int range_tr_destroy(void *key, void *datum, void *p)
|
||||||
{
|
{
|
||||||
struct mls_range *rt = datum;
|
struct mls_range *rt = datum;
|
||||||
|
@ -709,7 +762,6 @@ void policydb_destroy(struct policydb *p)
|
||||||
int i;
|
int i;
|
||||||
struct role_allow *ra, *lra = NULL;
|
struct role_allow *ra, *lra = NULL;
|
||||||
struct role_trans *tr, *ltr = NULL;
|
struct role_trans *tr, *ltr = NULL;
|
||||||
struct filename_trans *ft, *nft;
|
|
||||||
|
|
||||||
for (i = 0; i < SYM_NUM; i++) {
|
for (i = 0; i < SYM_NUM; i++) {
|
||||||
cond_resched();
|
cond_resched();
|
||||||
|
@ -773,6 +825,9 @@ void policydb_destroy(struct policydb *p)
|
||||||
}
|
}
|
||||||
kfree(lra);
|
kfree(lra);
|
||||||
|
|
||||||
|
hashtab_map(p->filename_trans, filenametr_destroy, NULL);
|
||||||
|
hashtab_destroy(p->filename_trans);
|
||||||
|
|
||||||
hashtab_map(p->range_tr, range_tr_destroy, NULL);
|
hashtab_map(p->range_tr, range_tr_destroy, NULL);
|
||||||
hashtab_destroy(p->range_tr);
|
hashtab_destroy(p->range_tr);
|
||||||
|
|
||||||
|
@ -788,14 +843,6 @@ void policydb_destroy(struct policydb *p)
|
||||||
flex_array_free(p->type_attr_map_array);
|
flex_array_free(p->type_attr_map_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
ft = p->filename_trans;
|
|
||||||
while (ft) {
|
|
||||||
nft = ft->next;
|
|
||||||
kfree(ft->name);
|
|
||||||
kfree(ft);
|
|
||||||
ft = nft;
|
|
||||||
}
|
|
||||||
|
|
||||||
ebitmap_destroy(&p->filename_trans_ttypes);
|
ebitmap_destroy(&p->filename_trans_ttypes);
|
||||||
ebitmap_destroy(&p->policycaps);
|
ebitmap_destroy(&p->policycaps);
|
||||||
ebitmap_destroy(&p->permissive_map);
|
ebitmap_destroy(&p->permissive_map);
|
||||||
|
@ -1806,9 +1853,10 @@ out:
|
||||||
|
|
||||||
static int filename_trans_read(struct policydb *p, void *fp)
|
static int filename_trans_read(struct policydb *p, void *fp)
|
||||||
{
|
{
|
||||||
struct filename_trans *ft, *last;
|
struct filename_trans *ft;
|
||||||
u32 nel, len;
|
struct filename_trans_datum *otype;
|
||||||
char *name;
|
char *name;
|
||||||
|
u32 nel, len;
|
||||||
__le32 buf[4];
|
__le32 buf[4];
|
||||||
int rc, i;
|
int rc, i;
|
||||||
|
|
||||||
|
@ -1817,25 +1865,23 @@ static int filename_trans_read(struct policydb *p, void *fp)
|
||||||
|
|
||||||
rc = next_entry(buf, fp, sizeof(u32));
|
rc = next_entry(buf, fp, sizeof(u32));
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out;
|
return rc;
|
||||||
nel = le32_to_cpu(buf[0]);
|
nel = le32_to_cpu(buf[0]);
|
||||||
|
|
||||||
last = p->filename_trans;
|
|
||||||
while (last && last->next)
|
|
||||||
last = last->next;
|
|
||||||
|
|
||||||
for (i = 0; i < nel; i++) {
|
for (i = 0; i < nel; i++) {
|
||||||
|
ft = NULL;
|
||||||
|
otype = NULL;
|
||||||
|
name = NULL;
|
||||||
|
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
ft = kzalloc(sizeof(*ft), GFP_KERNEL);
|
ft = kzalloc(sizeof(*ft), GFP_KERNEL);
|
||||||
if (!ft)
|
if (!ft)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* add it to the tail of the list */
|
rc = -ENOMEM;
|
||||||
if (!last)
|
otype = kmalloc(sizeof(*otype), GFP_KERNEL);
|
||||||
p->filename_trans = ft;
|
if (!otype)
|
||||||
else
|
goto out;
|
||||||
last->next = ft;
|
|
||||||
last = ft;
|
|
||||||
|
|
||||||
/* length of the path component string */
|
/* length of the path component string */
|
||||||
rc = next_entry(buf, fp, sizeof(u32));
|
rc = next_entry(buf, fp, sizeof(u32));
|
||||||
|
@ -1863,14 +1909,22 @@ static int filename_trans_read(struct policydb *p, void *fp)
|
||||||
ft->stype = le32_to_cpu(buf[0]);
|
ft->stype = le32_to_cpu(buf[0]);
|
||||||
ft->ttype = le32_to_cpu(buf[1]);
|
ft->ttype = le32_to_cpu(buf[1]);
|
||||||
ft->tclass = le32_to_cpu(buf[2]);
|
ft->tclass = le32_to_cpu(buf[2]);
|
||||||
ft->otype = le32_to_cpu(buf[3]);
|
|
||||||
|
otype->otype = le32_to_cpu(buf[3]);
|
||||||
|
|
||||||
rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1);
|
rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
hashtab_insert(p->filename_trans, ft, otype);
|
||||||
}
|
}
|
||||||
rc = 0;
|
hash_eval(p->filename_trans, "filenametr");
|
||||||
|
return 0;
|
||||||
out:
|
out:
|
||||||
|
kfree(ft);
|
||||||
|
kfree(name);
|
||||||
|
kfree(otype);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3131,43 +3185,60 @@ static int range_write(struct policydb *p, void *fp)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int filename_write_helper(void *key, void *data, void *ptr)
|
||||||
|
{
|
||||||
|
__le32 buf[4];
|
||||||
|
struct filename_trans *ft = key;
|
||||||
|
struct filename_trans_datum *otype = data;
|
||||||
|
void *fp = ptr;
|
||||||
|
int rc;
|
||||||
|
u32 len;
|
||||||
|
|
||||||
|
len = strlen(ft->name);
|
||||||
|
buf[0] = cpu_to_le32(len);
|
||||||
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = put_entry(ft->name, sizeof(char), len, fp);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
buf[0] = ft->stype;
|
||||||
|
buf[1] = ft->ttype;
|
||||||
|
buf[2] = ft->tclass;
|
||||||
|
buf[3] = otype->otype;
|
||||||
|
|
||||||
|
rc = put_entry(buf, sizeof(u32), 4, fp);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int filename_trans_write(struct policydb *p, void *fp)
|
static int filename_trans_write(struct policydb *p, void *fp)
|
||||||
{
|
{
|
||||||
struct filename_trans *ft;
|
u32 nel;
|
||||||
u32 len, nel = 0;
|
__le32 buf[1];
|
||||||
__le32 buf[4];
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
for (ft = p->filename_trans; ft; ft = ft->next)
|
nel = 0;
|
||||||
nel++;
|
rc = hashtab_map(p->filename_trans, hashtab_cnt, &nel);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
buf[0] = cpu_to_le32(nel);
|
buf[0] = cpu_to_le32(nel);
|
||||||
rc = put_entry(buf, sizeof(u32), 1, fp);
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
for (ft = p->filename_trans; ft; ft = ft->next) {
|
rc = hashtab_map(p->filename_trans, filename_write_helper, fp);
|
||||||
len = strlen(ft->name);
|
if (rc)
|
||||||
buf[0] = cpu_to_le32(len);
|
return rc;
|
||||||
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
rc = put_entry(ft->name, sizeof(char), len, fp);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
buf[0] = ft->stype;
|
|
||||||
buf[1] = ft->ttype;
|
|
||||||
buf[2] = ft->tclass;
|
|
||||||
buf[3] = ft->otype;
|
|
||||||
|
|
||||||
rc = put_entry(buf, sizeof(u32), 4, fp);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write the configuration data in a policy database
|
* Write the configuration data in a policy database
|
||||||
* structure to a policy database binary representation
|
* structure to a policy database binary representation
|
||||||
|
|
|
@ -79,11 +79,13 @@ struct role_trans {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct filename_trans {
|
struct filename_trans {
|
||||||
struct filename_trans *next;
|
|
||||||
u32 stype; /* current process */
|
u32 stype; /* current process */
|
||||||
u32 ttype; /* parent dir context */
|
u32 ttype; /* parent dir context */
|
||||||
u16 tclass; /* class of new object */
|
u16 tclass; /* class of new object */
|
||||||
const char *name; /* last path component */
|
const char *name; /* last path component */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct filename_trans_datum {
|
||||||
u32 otype; /* expected of new object */
|
u32 otype; /* expected of new object */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -227,10 +229,11 @@ struct policydb {
|
||||||
/* role transitions */
|
/* role transitions */
|
||||||
struct role_trans *role_tr;
|
struct role_trans *role_tr;
|
||||||
|
|
||||||
|
/* file transitions with the last path component */
|
||||||
/* quickly exclude lookups when parent ttype has no rules */
|
/* quickly exclude lookups when parent ttype has no rules */
|
||||||
struct ebitmap filename_trans_ttypes;
|
struct ebitmap filename_trans_ttypes;
|
||||||
/* file transitions with the last path component */
|
/* actual set of filename_trans rules */
|
||||||
struct filename_trans *filename_trans;
|
struct hashtab *filename_trans;
|
||||||
|
|
||||||
/* bools indexed by (value - 1) */
|
/* bools indexed by (value - 1) */
|
||||||
struct cond_bool_datum **bool_val_to_struct;
|
struct cond_bool_datum **bool_val_to_struct;
|
||||||
|
|
|
@ -1362,7 +1362,8 @@ static void filename_compute_type(struct policydb *p, struct context *newcontext
|
||||||
u32 stype, u32 ttype, u16 tclass,
|
u32 stype, u32 ttype, u16 tclass,
|
||||||
const char *objname)
|
const char *objname)
|
||||||
{
|
{
|
||||||
struct filename_trans *ft;
|
struct filename_trans ft;
|
||||||
|
struct filename_trans_datum *otype;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Most filename trans rules are going to live in specific directories
|
* Most filename trans rules are going to live in specific directories
|
||||||
|
@ -1372,15 +1373,14 @@ static void filename_compute_type(struct policydb *p, struct context *newcontext
|
||||||
if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype))
|
if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (ft = p->filename_trans; ft; ft = ft->next) {
|
ft.stype = stype;
|
||||||
if (ft->stype == stype &&
|
ft.ttype = ttype;
|
||||||
ft->ttype == ttype &&
|
ft.tclass = tclass;
|
||||||
ft->tclass == tclass &&
|
ft.name = objname;
|
||||||
!strcmp(ft->name, objname)) {
|
|
||||||
newcontext->type = ft->otype;
|
otype = hashtab_search(p->filename_trans, &ft);
|
||||||
return;
|
if (otype)
|
||||||
}
|
newcontext->type = otype->otype;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int security_compute_sid(u32 ssid,
|
static int security_compute_sid(u32 ssid,
|
||||||
|
|
Loading…
Reference in New Issue