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] = { | |||
52 | }; | 52 | }; |
53 | #endif | 53 | #endif |
54 | 54 | ||
55 | int selinux_mls_enabled; | ||
56 | |||
57 | static unsigned int symtab_sizes[SYM_NUM] = { | 55 | static unsigned int symtab_sizes[SYM_NUM] = { |
58 | 2, | 56 | 2, |
59 | 32, | 57 | 32, |
@@ -177,6 +175,21 @@ out_free_role: | |||
177 | goto out; | 175 | goto out; |
178 | } | 176 | } |
179 | 177 | ||
178 | static u32 rangetr_hash(struct hashtab *h, const void *k) | ||
179 | { | ||
180 | const struct range_trans *key = k; | ||
181 | return (key->source_type + (key->target_type << 3) + | ||
182 | (key->target_class << 5)) & (h->size - 1); | ||
183 | } | ||
184 | |||
185 | static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2) | ||
186 | { | ||
187 | const struct range_trans *key1 = k1, *key2 = k2; | ||
188 | return (key1->source_type != key2->source_type || | ||
189 | key1->target_type != key2->target_type || | ||
190 | key1->target_class != key2->target_class); | ||
191 | } | ||
192 | |||
180 | /* | 193 | /* |
181 | * Initialize a policy database structure. | 194 | * Initialize a policy database structure. |
182 | */ | 195 | */ |
@@ -204,6 +217,10 @@ static int policydb_init(struct policydb *p) | |||
204 | if (rc) | 217 | if (rc) |
205 | goto out_free_symtab; | 218 | goto out_free_symtab; |
206 | 219 | ||
220 | p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); | ||
221 | if (!p->range_tr) | ||
222 | goto out_free_symtab; | ||
223 | |||
207 | ebitmap_init(&p->policycaps); | 224 | ebitmap_init(&p->policycaps); |
208 | ebitmap_init(&p->permissive_map); | 225 | ebitmap_init(&p->permissive_map); |
209 | 226 | ||
@@ -408,6 +425,20 @@ static void symtab_hash_eval(struct symtab *s) | |||
408 | info.slots_used, h->size, info.max_chain_len); | 425 | info.slots_used, h->size, info.max_chain_len); |
409 | } | 426 | } |
410 | } | 427 | } |
428 | |||
429 | static void rangetr_hash_eval(struct hashtab *h) | ||
430 | { | ||
431 | struct hashtab_info info; | ||
432 | |||
433 | hashtab_stat(h, &info); | ||
434 | printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, " | ||
435 | "longest chain length %d\n", h->nel, | ||
436 | info.slots_used, h->size, info.max_chain_len); | ||
437 | } | ||
438 | #else | ||
439 | static inline void rangetr_hash_eval(struct hashtab *h) | ||
440 | { | ||
441 | } | ||
411 | #endif | 442 | #endif |
412 | 443 | ||
413 | /* | 444 | /* |
@@ -422,7 +453,7 @@ static int policydb_index_others(struct policydb *p) | |||
422 | 453 | ||
423 | printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools", | 454 | printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools", |
424 | p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); | 455 | p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); |
425 | if (selinux_mls_enabled) | 456 | if (p->mls_enabled) |
426 | printk(", %d sens, %d cats", p->p_levels.nprim, | 457 | printk(", %d sens, %d cats", p->p_levels.nprim, |
427 | p->p_cats.nprim); | 458 | p->p_cats.nprim); |
428 | printk("\n"); | 459 | printk("\n"); |
@@ -612,6 +643,17 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = | |||
612 | cat_destroy, | 643 | cat_destroy, |
613 | }; | 644 | }; |
614 | 645 | ||
646 | static int range_tr_destroy(void *key, void *datum, void *p) | ||
647 | { | ||
648 | struct mls_range *rt = datum; | ||
649 | kfree(key); | ||
650 | ebitmap_destroy(&rt->level[0].cat); | ||
651 | ebitmap_destroy(&rt->level[1].cat); | ||
652 | kfree(datum); | ||
653 | cond_resched(); | ||
654 | return 0; | ||
655 | } | ||
656 | |||
615 | static void ocontext_destroy(struct ocontext *c, int i) | 657 | static void ocontext_destroy(struct ocontext *c, int i) |
616 | { | 658 | { |
617 | context_destroy(&c->context[0]); | 659 | context_destroy(&c->context[0]); |
@@ -632,7 +674,6 @@ void policydb_destroy(struct policydb *p) | |||
632 | int i; | 674 | int i; |
633 | struct role_allow *ra, *lra = NULL; | 675 | struct role_allow *ra, *lra = NULL; |
634 | struct role_trans *tr, *ltr = NULL; | 676 | struct role_trans *tr, *ltr = NULL; |
635 | struct range_trans *rt, *lrt = NULL; | ||
636 | 677 | ||
637 | for (i = 0; i < SYM_NUM; i++) { | 678 | for (i = 0; i < SYM_NUM; i++) { |
638 | cond_resched(); | 679 | cond_resched(); |
@@ -693,20 +734,8 @@ void policydb_destroy(struct policydb *p) | |||
693 | } | 734 | } |
694 | kfree(lra); | 735 | kfree(lra); |
695 | 736 | ||
696 | for (rt = p->range_tr; rt; rt = rt->next) { | 737 | hashtab_map(p->range_tr, range_tr_destroy, NULL); |
697 | cond_resched(); | 738 | hashtab_destroy(p->range_tr); |
698 | if (lrt) { | ||
699 | ebitmap_destroy(&lrt->target_range.level[0].cat); | ||
700 | ebitmap_destroy(&lrt->target_range.level[1].cat); | ||
701 | kfree(lrt); | ||
702 | } | ||
703 | lrt = rt; | ||
704 | } | ||
705 | if (lrt) { | ||
706 | ebitmap_destroy(&lrt->target_range.level[0].cat); | ||
707 | ebitmap_destroy(&lrt->target_range.level[1].cat); | ||
708 | kfree(lrt); | ||
709 | } | ||
710 | 739 | ||
711 | if (p->type_attr_map) { | 740 | if (p->type_attr_map) { |
712 | for (i = 0; i < p->p_types.nprim; i++) | 741 | for (i = 0; i < p->p_types.nprim; i++) |
@@ -1686,12 +1715,11 @@ int policydb_read(struct policydb *p, void *fp) | |||
1686 | int i, j, rc; | 1715 | int i, j, rc; |
1687 | __le32 buf[4]; | 1716 | __le32 buf[4]; |
1688 | u32 nodebuf[8]; | 1717 | u32 nodebuf[8]; |
1689 | u32 len, len2, config, nprim, nel, nel2; | 1718 | u32 len, len2, nprim, nel, nel2; |
1690 | char *policydb_str; | 1719 | char *policydb_str; |
1691 | struct policydb_compat_info *info; | 1720 | struct policydb_compat_info *info; |
1692 | struct range_trans *rt, *lrt; | 1721 | struct range_trans *rt; |
1693 | 1722 | struct mls_range *r; | |
1694 | config = 0; | ||
1695 | 1723 | ||
1696 | rc = policydb_init(p); | 1724 | rc = policydb_init(p); |
1697 | if (rc) | 1725 | if (rc) |
@@ -1740,7 +1768,7 @@ int policydb_read(struct policydb *p, void *fp) | |||
1740 | kfree(policydb_str); | 1768 | kfree(policydb_str); |
1741 | policydb_str = NULL; | 1769 | policydb_str = NULL; |
1742 | 1770 | ||
1743 | /* Read the version, config, and table sizes. */ | 1771 | /* Read the version and table sizes. */ |
1744 | rc = next_entry(buf, fp, sizeof(u32)*4); | 1772 | rc = next_entry(buf, fp, sizeof(u32)*4); |
1745 | if (rc < 0) | 1773 | if (rc < 0) |
1746 | goto bad; | 1774 | goto bad; |
@@ -1755,13 +1783,7 @@ int policydb_read(struct policydb *p, void *fp) | |||
1755 | } | 1783 | } |
1756 | 1784 | ||
1757 | if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) { | 1785 | if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) { |
1758 | if (ss_initialized && !selinux_mls_enabled) { | 1786 | p->mls_enabled = 1; |
1759 | printk(KERN_ERR "SELinux: Cannot switch between non-MLS" | ||
1760 | " and MLS policies\n"); | ||
1761 | goto bad; | ||
1762 | } | ||
1763 | selinux_mls_enabled = 1; | ||
1764 | config |= POLICYDB_CONFIG_MLS; | ||
1765 | 1787 | ||
1766 | if (p->policyvers < POLICYDB_VERSION_MLS) { | 1788 | if (p->policyvers < POLICYDB_VERSION_MLS) { |
1767 | printk(KERN_ERR "SELinux: security policydb version %d " | 1789 | printk(KERN_ERR "SELinux: security policydb version %d " |
@@ -1769,12 +1791,6 @@ int policydb_read(struct policydb *p, void *fp) | |||
1769 | p->policyvers); | 1791 | p->policyvers); |
1770 | goto bad; | 1792 | goto bad; |
1771 | } | 1793 | } |
1772 | } else { | ||
1773 | if (ss_initialized && selinux_mls_enabled) { | ||
1774 | printk(KERN_ERR "SELinux: Cannot switch between MLS and" | ||
1775 | " non-MLS policies\n"); | ||
1776 | goto bad; | ||
1777 | } | ||
1778 | } | 1794 | } |
1779 | p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); | 1795 | p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); |
1780 | p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); | 1796 | p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); |
@@ -2122,44 +2138,61 @@ int policydb_read(struct policydb *p, void *fp) | |||
2122 | if (rc < 0) | 2138 | if (rc < 0) |
2123 | goto bad; | 2139 | goto bad; |
2124 | nel = le32_to_cpu(buf[0]); | 2140 | nel = le32_to_cpu(buf[0]); |
2125 | lrt = NULL; | ||
2126 | for (i = 0; i < nel; i++) { | 2141 | for (i = 0; i < nel; i++) { |
2127 | rt = kzalloc(sizeof(*rt), GFP_KERNEL); | 2142 | rt = kzalloc(sizeof(*rt), GFP_KERNEL); |
2128 | if (!rt) { | 2143 | if (!rt) { |
2129 | rc = -ENOMEM; | 2144 | rc = -ENOMEM; |
2130 | goto bad; | 2145 | goto bad; |
2131 | } | 2146 | } |
2132 | if (lrt) | ||
2133 | lrt->next = rt; | ||
2134 | else | ||
2135 | p->range_tr = rt; | ||
2136 | rc = next_entry(buf, fp, (sizeof(u32) * 2)); | 2147 | rc = next_entry(buf, fp, (sizeof(u32) * 2)); |
2137 | if (rc < 0) | 2148 | if (rc < 0) { |
2149 | kfree(rt); | ||
2138 | goto bad; | 2150 | goto bad; |
2151 | } | ||
2139 | rt->source_type = le32_to_cpu(buf[0]); | 2152 | rt->source_type = le32_to_cpu(buf[0]); |
2140 | rt->target_type = le32_to_cpu(buf[1]); | 2153 | rt->target_type = le32_to_cpu(buf[1]); |
2141 | if (new_rangetr) { | 2154 | if (new_rangetr) { |
2142 | rc = next_entry(buf, fp, sizeof(u32)); | 2155 | rc = next_entry(buf, fp, sizeof(u32)); |
2143 | if (rc < 0) | 2156 | if (rc < 0) { |
2157 | kfree(rt); | ||
2144 | goto bad; | 2158 | goto bad; |
2159 | } | ||
2145 | rt->target_class = le32_to_cpu(buf[0]); | 2160 | rt->target_class = le32_to_cpu(buf[0]); |
2146 | } else | 2161 | } else |
2147 | rt->target_class = p->process_class; | 2162 | rt->target_class = p->process_class; |
2148 | if (!policydb_type_isvalid(p, rt->source_type) || | 2163 | if (!policydb_type_isvalid(p, rt->source_type) || |
2149 | !policydb_type_isvalid(p, rt->target_type) || | 2164 | !policydb_type_isvalid(p, rt->target_type) || |
2150 | !policydb_class_isvalid(p, rt->target_class)) { | 2165 | !policydb_class_isvalid(p, rt->target_class)) { |
2166 | kfree(rt); | ||
2151 | rc = -EINVAL; | 2167 | rc = -EINVAL; |
2152 | goto bad; | 2168 | goto bad; |
2153 | } | 2169 | } |
2154 | rc = mls_read_range_helper(&rt->target_range, fp); | 2170 | r = kzalloc(sizeof(*r), GFP_KERNEL); |
2155 | if (rc) | 2171 | if (!r) { |
2172 | kfree(rt); | ||
2173 | rc = -ENOMEM; | ||
2156 | goto bad; | 2174 | goto bad; |
2157 | if (!mls_range_isvalid(p, &rt->target_range)) { | 2175 | } |
2176 | rc = mls_read_range_helper(r, fp); | ||
2177 | if (rc) { | ||
2178 | kfree(rt); | ||
2179 | kfree(r); | ||
2180 | goto bad; | ||
2181 | } | ||
2182 | if (!mls_range_isvalid(p, r)) { | ||
2158 | printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); | 2183 | printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); |
2184 | kfree(rt); | ||
2185 | kfree(r); | ||
2186 | goto bad; | ||
2187 | } | ||
2188 | rc = hashtab_insert(p->range_tr, rt, r); | ||
2189 | if (rc) { | ||
2190 | kfree(rt); | ||
2191 | kfree(r); | ||
2159 | goto bad; | 2192 | goto bad; |
2160 | } | 2193 | } |
2161 | lrt = rt; | ||
2162 | } | 2194 | } |
2195 | rangetr_hash_eval(p->range_tr); | ||
2163 | } | 2196 | } |
2164 | 2197 | ||
2165 | p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); | 2198 | p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); |