|
@@ -128,6 +128,11 @@ static struct policydb_compat_info policydb_compat[] = {
|
|
|
.sym_num = SYM_NUM,
|
|
|
.ocon_num = OCON_NUM,
|
|
|
},
|
|
|
+ {
|
|
|
+ .version = POLICYDB_VERSION_ROLETRANS,
|
|
|
+ .sym_num = SYM_NUM,
|
|
|
+ .ocon_num = OCON_NUM,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
static struct policydb_compat_info *policydb_lookup_compat(int version)
|
|
@@ -179,6 +184,43 @@ out:
|
|
|
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)
|
|
|
{
|
|
|
const struct range_trans *key = k;
|
|
@@ -231,15 +273,22 @@ static int policydb_init(struct policydb *p)
|
|
|
if (rc)
|
|
|
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);
|
|
|
if (!p->range_tr)
|
|
|
goto out;
|
|
|
|
|
|
+ ebitmap_init(&p->filename_trans_ttypes);
|
|
|
ebitmap_init(&p->policycaps);
|
|
|
ebitmap_init(&p->permissive_map);
|
|
|
|
|
|
return 0;
|
|
|
out:
|
|
|
+ hashtab_destroy(p->filename_trans);
|
|
|
+ hashtab_destroy(p->range_tr);
|
|
|
for (i = 0; i < SYM_NUM; i++)
|
|
|
hashtab_destroy(p->symtab[i].table);
|
|
|
return rc;
|
|
@@ -417,32 +466,26 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
|
|
|
};
|
|
|
|
|
|
#ifdef DEBUG_HASHES
|
|
|
-static void symtab_hash_eval(struct symtab *s)
|
|
|
+static void hash_eval(struct hashtab *h, const char *hash_name)
|
|
|
{
|
|
|
- int i;
|
|
|
-
|
|
|
- for (i = 0; i < SYM_NUM; i++) {
|
|
|
- struct hashtab *h = s[i].table;
|
|
|
- struct hashtab_info info;
|
|
|
+ struct hashtab_info info;
|
|
|
|
|
|
- hashtab_stat(h, &info);
|
|
|
- printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, "
|
|
|
- "longest chain length %d\n", symtab_name[i], h->nel,
|
|
|
- info.slots_used, h->size, info.max_chain_len);
|
|
|
- }
|
|
|
+ hashtab_stat(h, &info);
|
|
|
+ printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, "
|
|
|
+ "longest chain length %d\n", hash_name, h->nel,
|
|
|
+ info.slots_used, h->size, info.max_chain_len);
|
|
|
}
|
|
|
|
|
|
-static void rangetr_hash_eval(struct hashtab *h)
|
|
|
+static void symtab_hash_eval(struct symtab *s)
|
|
|
{
|
|
|
- struct hashtab_info info;
|
|
|
+ int i;
|
|
|
|
|
|
- hashtab_stat(h, &info);
|
|
|
- printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, "
|
|
|
- "longest chain length %d\n", h->nel,
|
|
|
- info.slots_used, h->size, info.max_chain_len);
|
|
|
+ for (i = 0; i < SYM_NUM; i++)
|
|
|
+ hash_eval(s[i].table, symtab_name[i]);
|
|
|
}
|
|
|
+
|
|
|
#else
|
|
|
-static inline void rangetr_hash_eval(struct hashtab *h)
|
|
|
+static inline void hash_eval(struct hashtab *h, char *hash_name)
|
|
|
{
|
|
|
}
|
|
|
#endif
|
|
@@ -675,6 +718,16 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
|
|
|
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)
|
|
|
{
|
|
|
struct mls_range *rt = datum;
|
|
@@ -709,7 +762,6 @@ void policydb_destroy(struct policydb *p)
|
|
|
int i;
|
|
|
struct role_allow *ra, *lra = NULL;
|
|
|
struct role_trans *tr, *ltr = NULL;
|
|
|
- struct filename_trans *ft, *nft;
|
|
|
|
|
|
for (i = 0; i < SYM_NUM; i++) {
|
|
|
cond_resched();
|
|
@@ -773,6 +825,9 @@ void policydb_destroy(struct policydb *p)
|
|
|
}
|
|
|
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_destroy(p->range_tr);
|
|
|
|
|
@@ -788,14 +843,7 @@ void policydb_destroy(struct policydb *p)
|
|
|
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->policycaps);
|
|
|
ebitmap_destroy(&p->permissive_map);
|
|
|
|
|
@@ -1795,7 +1843,7 @@ static int range_read(struct policydb *p, void *fp)
|
|
|
rt = NULL;
|
|
|
r = NULL;
|
|
|
}
|
|
|
- rangetr_hash_eval(p->range_tr);
|
|
|
+ hash_eval(p->range_tr, "rangetr");
|
|
|
rc = 0;
|
|
|
out:
|
|
|
kfree(rt);
|
|
@@ -1805,9 +1853,10 @@ out:
|
|
|
|
|
|
static int filename_trans_read(struct policydb *p, void *fp)
|
|
|
{
|
|
|
- struct filename_trans *ft, *last;
|
|
|
- u32 nel, len;
|
|
|
+ struct filename_trans *ft;
|
|
|
+ struct filename_trans_datum *otype;
|
|
|
char *name;
|
|
|
+ u32 nel, len;
|
|
|
__le32 buf[4];
|
|
|
int rc, i;
|
|
|
|
|
@@ -1816,25 +1865,23 @@ static int filename_trans_read(struct policydb *p, void *fp)
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
|
if (rc)
|
|
|
- goto out;
|
|
|
+ return rc;
|
|
|
nel = le32_to_cpu(buf[0]);
|
|
|
|
|
|
- last = p->filename_trans;
|
|
|
- while (last && last->next)
|
|
|
- last = last->next;
|
|
|
-
|
|
|
for (i = 0; i < nel; i++) {
|
|
|
+ ft = NULL;
|
|
|
+ otype = NULL;
|
|
|
+ name = NULL;
|
|
|
+
|
|
|
rc = -ENOMEM;
|
|
|
ft = kzalloc(sizeof(*ft), GFP_KERNEL);
|
|
|
if (!ft)
|
|
|
goto out;
|
|
|
|
|
|
- /* add it to the tail of the list */
|
|
|
- if (!last)
|
|
|
- p->filename_trans = ft;
|
|
|
- else
|
|
|
- last->next = ft;
|
|
|
- last = ft;
|
|
|
+ rc = -ENOMEM;
|
|
|
+ otype = kmalloc(sizeof(*otype), GFP_KERNEL);
|
|
|
+ if (!otype)
|
|
|
+ goto out;
|
|
|
|
|
|
/* length of the path component string */
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
@@ -1862,10 +1909,22 @@ static int filename_trans_read(struct policydb *p, void *fp)
|
|
|
ft->stype = le32_to_cpu(buf[0]);
|
|
|
ft->ttype = le32_to_cpu(buf[1]);
|
|
|
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);
|
|
|
+ if (rc)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ hashtab_insert(p->filename_trans, ft, otype);
|
|
|
}
|
|
|
- rc = 0;
|
|
|
+ hash_eval(p->filename_trans, "filenametr");
|
|
|
+ return 0;
|
|
|
out:
|
|
|
+ kfree(ft);
|
|
|
+ kfree(name);
|
|
|
+ kfree(otype);
|
|
|
+
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
@@ -2266,6 +2325,11 @@ int policydb_read(struct policydb *p, void *fp)
|
|
|
p->symtab[i].nprim = nprim;
|
|
|
}
|
|
|
|
|
|
+ rc = -EINVAL;
|
|
|
+ p->process_class = string_to_security_class(p, "process");
|
|
|
+ if (!p->process_class)
|
|
|
+ goto bad;
|
|
|
+
|
|
|
rc = avtab_read(&p->te_avtab, fp, p);
|
|
|
if (rc)
|
|
|
goto bad;
|
|
@@ -2298,8 +2362,17 @@ int policydb_read(struct policydb *p, void *fp)
|
|
|
tr->role = le32_to_cpu(buf[0]);
|
|
|
tr->type = le32_to_cpu(buf[1]);
|
|
|
tr->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]);
|
|
|
+ } else
|
|
|
+ tr->tclass = p->process_class;
|
|
|
+
|
|
|
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))
|
|
|
goto bad;
|
|
|
ltr = tr;
|
|
@@ -2340,11 +2413,6 @@ int policydb_read(struct policydb *p, void *fp)
|
|
|
if (rc)
|
|
|
goto bad;
|
|
|
|
|
|
- rc = -EINVAL;
|
|
|
- p->process_class = string_to_security_class(p, "process");
|
|
|
- if (!p->process_class)
|
|
|
- goto bad;
|
|
|
-
|
|
|
rc = -EINVAL;
|
|
|
p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition");
|
|
|
p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition");
|
|
@@ -2517,8 +2585,9 @@ static int cat_write(void *vkey, void *datum, void *ptr)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int role_trans_write(struct role_trans *r, void *fp)
|
|
|
+static int role_trans_write(struct policydb *p, void *fp)
|
|
|
{
|
|
|
+ struct role_trans *r = p->role_tr;
|
|
|
struct role_trans *tr;
|
|
|
u32 buf[3];
|
|
|
size_t nel;
|
|
@@ -2538,6 +2607,12 @@ static int role_trans_write(struct role_trans *r, void *fp)
|
|
|
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;
|
|
@@ -3045,7 +3120,7 @@ static int genfs_write(struct policydb *p, void *fp)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int range_count(void *key, void *data, void *ptr)
|
|
|
+static int hashtab_cnt(void *key, void *data, void *ptr)
|
|
|
{
|
|
|
int *cnt = ptr;
|
|
|
*cnt = *cnt + 1;
|
|
@@ -3093,7 +3168,7 @@ static int range_write(struct policydb *p, void *fp)
|
|
|
|
|
|
/* count the number of entries in the hashtab */
|
|
|
nel = 0;
|
|
|
- rc = hashtab_map(p->range_tr, range_count, &nel);
|
|
|
+ rc = hashtab_map(p->range_tr, hashtab_cnt, &nel);
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
|
|
@@ -3110,43 +3185,60 @@ static int range_write(struct policydb *p, void *fp)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int filename_trans_write(struct policydb *p, void *fp)
|
|
|
+static int filename_write_helper(void *key, void *data, void *ptr)
|
|
|
{
|
|
|
- struct filename_trans *ft;
|
|
|
- u32 len, nel = 0;
|
|
|
__le32 buf[4];
|
|
|
+ struct filename_trans *ft = key;
|
|
|
+ struct filename_trans_datum *otype = data;
|
|
|
+ void *fp = ptr;
|
|
|
int rc;
|
|
|
+ u32 len;
|
|
|
|
|
|
- for (ft = p->filename_trans; ft; ft = ft->next)
|
|
|
- nel++;
|
|
|
-
|
|
|
- buf[0] = cpu_to_le32(nel);
|
|
|
+ len = strlen(ft->name);
|
|
|
+ buf[0] = cpu_to_le32(len);
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
|
|
|
- for (ft = p->filename_trans; ft; ft = ft->next) {
|
|
|
- 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;
|
|
|
|
|
|
- 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;
|
|
|
|
|
|
- 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;
|
|
|
|
|
|
- rc = put_entry(buf, sizeof(u32), 4, fp);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
- }
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
+static int filename_trans_write(struct policydb *p, void *fp)
|
|
|
+{
|
|
|
+ u32 nel;
|
|
|
+ __le32 buf[1];
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ nel = 0;
|
|
|
+ rc = hashtab_map(p->filename_trans, hashtab_cnt, &nel);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ buf[0] = cpu_to_le32(nel);
|
|
|
+ rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ rc = hashtab_map(p->filename_trans, filename_write_helper, fp);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Write the configuration data in a policy database
|
|
|
* structure to a policy database binary representation
|
|
@@ -3249,7 +3341,7 @@ int policydb_write(struct policydb *p, void *fp)
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
|
|
|
- rc = role_trans_write(p->role_tr, fp);
|
|
|
+ rc = role_trans_write(p, fp);
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
|