diff options
Diffstat (limited to 'security/selinux/ss/policydb.c')
-rw-r--r-- | security/selinux/ss/policydb.c | 127 |
1 files changed, 80 insertions, 47 deletions
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index f03667213ea8..23c6e53c102c 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -52,8 +52,6 @@ static char *symtab_name[SYM_NUM] = { }; #endif -int selinux_mls_enabled; - static unsigned int symtab_sizes[SYM_NUM] = { 2, 32, @@ -177,6 +175,21 @@ out_free_role: goto out; } +static u32 rangetr_hash(struct hashtab *h, const void *k) +{ + const struct range_trans *key = k; + return (key->source_type + (key->target_type << 3) + + (key->target_class << 5)) & (h->size - 1); +} + +static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2) +{ + const struct range_trans *key1 = k1, *key2 = k2; + return (key1->source_type != key2->source_type || + key1->target_type != key2->target_type || + key1->target_class != key2->target_class); +} + /* * Initialize a policy database structure. */ @@ -204,6 +217,10 @@ static int policydb_init(struct policydb *p) if (rc) goto out_free_symtab; + p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); + if (!p->range_tr) + goto out_free_symtab; + ebitmap_init(&p->policycaps); ebitmap_init(&p->permissive_map); @@ -408,6 +425,20 @@ static void symtab_hash_eval(struct symtab *s) info.slots_used, h->size, info.max_chain_len); } } + +static void rangetr_hash_eval(struct hashtab *h) +{ + struct hashtab_info info; + + 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); +} +#else +static inline void rangetr_hash_eval(struct hashtab *h) +{ +} #endif /* @@ -422,7 +453,7 @@ static int policydb_index_others(struct policydb *p) printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools", p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); - if (selinux_mls_enabled) + if (p->mls_enabled) printk(", %d sens, %d cats", p->p_levels.nprim, p->p_cats.nprim); printk("\n"); @@ -612,6 +643,17 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = cat_destroy, }; +static int range_tr_destroy(void *key, void *datum, void *p) +{ + struct mls_range *rt = datum; + kfree(key); + ebitmap_destroy(&rt->level[0].cat); + ebitmap_destroy(&rt->level[1].cat); + kfree(datum); + cond_resched(); + return 0; +} + static void ocontext_destroy(struct ocontext *c, int i) { context_destroy(&c->context[0]); @@ -632,7 +674,6 @@ void policydb_destroy(struct policydb *p) int i; struct role_allow *ra, *lra = NULL; struct role_trans *tr, *ltr = NULL; - struct range_trans *rt, *lrt = NULL; for (i = 0; i < SYM_NUM; i++) { cond_resched(); @@ -693,20 +734,8 @@ void policydb_destroy(struct policydb *p) } kfree(lra); - for (rt = p->range_tr; rt; rt = rt->next) { - cond_resched(); - if (lrt) { - ebitmap_destroy(&lrt->target_range.level[0].cat); - ebitmap_destroy(&lrt->target_range.level[1].cat); - kfree(lrt); - } - lrt = rt; - } - if (lrt) { - ebitmap_destroy(&lrt->target_range.level[0].cat); - ebitmap_destroy(&lrt->target_range.level[1].cat); - kfree(lrt); - } + hashtab_map(p->range_tr, range_tr_destroy, NULL); + hashtab_destroy(p->range_tr); if (p->type_attr_map) { for (i = 0; i < p->p_types.nprim; i++) @@ -1686,12 +1715,11 @@ int policydb_read(struct policydb *p, void *fp) int i, j, rc; __le32 buf[4]; u32 nodebuf[8]; - u32 len, len2, config, nprim, nel, nel2; + u32 len, len2, nprim, nel, nel2; char *policydb_str; struct policydb_compat_info *info; - struct range_trans *rt, *lrt; - - config = 0; + struct range_trans *rt; + struct mls_range *r; rc = policydb_init(p); if (rc) @@ -1740,7 +1768,7 @@ int policydb_read(struct policydb *p, void *fp) kfree(policydb_str); policydb_str = NULL; - /* Read the version, config, and table sizes. */ + /* Read the version and table sizes. */ rc = next_entry(buf, fp, sizeof(u32)*4); if (rc < 0) goto bad; @@ -1755,13 +1783,7 @@ int policydb_read(struct policydb *p, void *fp) } if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) { - if (ss_initialized && !selinux_mls_enabled) { - printk(KERN_ERR "SELinux: Cannot switch between non-MLS" - " and MLS policies\n"); - goto bad; - } - selinux_mls_enabled = 1; - config |= POLICYDB_CONFIG_MLS; + p->mls_enabled = 1; if (p->policyvers < POLICYDB_VERSION_MLS) { printk(KERN_ERR "SELinux: security policydb version %d " @@ -1769,12 +1791,6 @@ int policydb_read(struct policydb *p, void *fp) p->policyvers); goto bad; } - } else { - if (ss_initialized && selinux_mls_enabled) { - printk(KERN_ERR "SELinux: Cannot switch between MLS and" - " non-MLS policies\n"); - goto bad; - } } p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); @@ -2122,44 +2138,61 @@ int policydb_read(struct policydb *p, void *fp) if (rc < 0) goto bad; nel = le32_to_cpu(buf[0]); - lrt = NULL; for (i = 0; i < nel; i++) { rt = kzalloc(sizeof(*rt), GFP_KERNEL); if (!rt) { rc = -ENOMEM; goto bad; } - if (lrt) - lrt->next = rt; - else - p->range_tr = rt; rc = next_entry(buf, fp, (sizeof(u32) * 2)); - if (rc < 0) + if (rc < 0) { + kfree(rt); goto bad; + } rt->source_type = le32_to_cpu(buf[0]); rt->target_type = le32_to_cpu(buf[1]); if (new_rangetr) { rc = next_entry(buf, fp, sizeof(u32)); - if (rc < 0) + if (rc < 0) { + kfree(rt); goto bad; + } rt->target_class = le32_to_cpu(buf[0]); } else rt->target_class = p->process_class; if (!policydb_type_isvalid(p, rt->source_type) || !policydb_type_isvalid(p, rt->target_type) || !policydb_class_isvalid(p, rt->target_class)) { + kfree(rt); rc = -EINVAL; goto bad; } - rc = mls_read_range_helper(&rt->target_range, fp); - if (rc) + r = kzalloc(sizeof(*r), GFP_KERNEL); + if (!r) { + kfree(rt); + rc = -ENOMEM; goto bad; - if (!mls_range_isvalid(p, &rt->target_range)) { + } + rc = mls_read_range_helper(r, fp); + if (rc) { + kfree(rt); + kfree(r); + goto bad; + } + if (!mls_range_isvalid(p, r)) { printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); + kfree(rt); + kfree(r); + goto bad; + } + rc = hashtab_insert(p->range_tr, rt, r); + if (rc) { + kfree(rt); + kfree(r); goto bad; } - lrt = rt; } + rangetr_hash_eval(p->range_tr); } p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); |