diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /security/selinux/ss/policydb.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'security/selinux/ss/policydb.c')
-rw-r--r-- | security/selinux/ss/policydb.c | 174 |
1 files changed, 125 insertions, 49 deletions
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 72e4a54973aa..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,27 +734,14 @@ 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++) |
713 | ebitmap_destroy(&p->type_attr_map[i]); | 742 | ebitmap_destroy(&p->type_attr_map[i]); |
714 | } | 743 | } |
715 | kfree(p->type_attr_map); | 744 | kfree(p->type_attr_map); |
716 | kfree(p->undefined_perms); | ||
717 | ebitmap_destroy(&p->policycaps); | 745 | ebitmap_destroy(&p->policycaps); |
718 | ebitmap_destroy(&p->permissive_map); | 746 | ebitmap_destroy(&p->permissive_map); |
719 | 747 | ||
@@ -1640,6 +1668,40 @@ static int policydb_bounds_sanity_check(struct policydb *p) | |||
1640 | 1668 | ||
1641 | extern int ss_initialized; | 1669 | extern int ss_initialized; |
1642 | 1670 | ||
1671 | u16 string_to_security_class(struct policydb *p, const char *name) | ||
1672 | { | ||
1673 | struct class_datum *cladatum; | ||
1674 | |||
1675 | cladatum = hashtab_search(p->p_classes.table, name); | ||
1676 | if (!cladatum) | ||
1677 | return 0; | ||
1678 | |||
1679 | return cladatum->value; | ||
1680 | } | ||
1681 | |||
1682 | u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name) | ||
1683 | { | ||
1684 | struct class_datum *cladatum; | ||
1685 | struct perm_datum *perdatum = NULL; | ||
1686 | struct common_datum *comdatum; | ||
1687 | |||
1688 | if (!tclass || tclass > p->p_classes.nprim) | ||
1689 | return 0; | ||
1690 | |||
1691 | cladatum = p->class_val_to_struct[tclass-1]; | ||
1692 | comdatum = cladatum->comdatum; | ||
1693 | if (comdatum) | ||
1694 | perdatum = hashtab_search(comdatum->permissions.table, | ||
1695 | name); | ||
1696 | if (!perdatum) | ||
1697 | perdatum = hashtab_search(cladatum->permissions.table, | ||
1698 | name); | ||
1699 | if (!perdatum) | ||
1700 | return 0; | ||
1701 | |||
1702 | return 1U << (perdatum->value-1); | ||
1703 | } | ||
1704 | |||
1643 | /* | 1705 | /* |
1644 | * Read the configuration data from a policy database binary | 1706 | * Read the configuration data from a policy database binary |
1645 | * representation file into a policy database structure. | 1707 | * representation file into a policy database structure. |
@@ -1653,12 +1715,11 @@ int policydb_read(struct policydb *p, void *fp) | |||
1653 | int i, j, rc; | 1715 | int i, j, rc; |
1654 | __le32 buf[4]; | 1716 | __le32 buf[4]; |
1655 | u32 nodebuf[8]; | 1717 | u32 nodebuf[8]; |
1656 | u32 len, len2, config, nprim, nel, nel2; | 1718 | u32 len, len2, nprim, nel, nel2; |
1657 | char *policydb_str; | 1719 | char *policydb_str; |
1658 | struct policydb_compat_info *info; | 1720 | struct policydb_compat_info *info; |
1659 | struct range_trans *rt, *lrt; | 1721 | struct range_trans *rt; |
1660 | 1722 | struct mls_range *r; | |
1661 | config = 0; | ||
1662 | 1723 | ||
1663 | rc = policydb_init(p); | 1724 | rc = policydb_init(p); |
1664 | if (rc) | 1725 | if (rc) |
@@ -1707,7 +1768,7 @@ int policydb_read(struct policydb *p, void *fp) | |||
1707 | kfree(policydb_str); | 1768 | kfree(policydb_str); |
1708 | policydb_str = NULL; | 1769 | policydb_str = NULL; |
1709 | 1770 | ||
1710 | /* Read the version, config, and table sizes. */ | 1771 | /* Read the version and table sizes. */ |
1711 | rc = next_entry(buf, fp, sizeof(u32)*4); | 1772 | rc = next_entry(buf, fp, sizeof(u32)*4); |
1712 | if (rc < 0) | 1773 | if (rc < 0) |
1713 | goto bad; | 1774 | goto bad; |
@@ -1722,13 +1783,7 @@ int policydb_read(struct policydb *p, void *fp) | |||
1722 | } | 1783 | } |
1723 | 1784 | ||
1724 | if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) { | 1785 | if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) { |
1725 | if (ss_initialized && !selinux_mls_enabled) { | 1786 | p->mls_enabled = 1; |
1726 | printk(KERN_ERR "SELinux: Cannot switch between non-MLS" | ||
1727 | " and MLS policies\n"); | ||
1728 | goto bad; | ||
1729 | } | ||
1730 | selinux_mls_enabled = 1; | ||
1731 | config |= POLICYDB_CONFIG_MLS; | ||
1732 | 1787 | ||
1733 | if (p->policyvers < POLICYDB_VERSION_MLS) { | 1788 | if (p->policyvers < POLICYDB_VERSION_MLS) { |
1734 | printk(KERN_ERR "SELinux: security policydb version %d " | 1789 | printk(KERN_ERR "SELinux: security policydb version %d " |
@@ -1736,12 +1791,6 @@ int policydb_read(struct policydb *p, void *fp) | |||
1736 | p->policyvers); | 1791 | p->policyvers); |
1737 | goto bad; | 1792 | goto bad; |
1738 | } | 1793 | } |
1739 | } else { | ||
1740 | if (ss_initialized && selinux_mls_enabled) { | ||
1741 | printk(KERN_ERR "SELinux: Cannot switch between MLS and" | ||
1742 | " non-MLS policies\n"); | ||
1743 | goto bad; | ||
1744 | } | ||
1745 | } | 1794 | } |
1746 | p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); | 1795 | p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); |
1747 | p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); | 1796 | p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); |
@@ -1861,6 +1910,16 @@ int policydb_read(struct policydb *p, void *fp) | |||
1861 | if (rc) | 1910 | if (rc) |
1862 | goto bad; | 1911 | goto bad; |
1863 | 1912 | ||
1913 | p->process_class = string_to_security_class(p, "process"); | ||
1914 | if (!p->process_class) | ||
1915 | goto bad; | ||
1916 | p->process_trans_perms = string_to_av_perm(p, p->process_class, | ||
1917 | "transition"); | ||
1918 | p->process_trans_perms |= string_to_av_perm(p, p->process_class, | ||
1919 | "dyntransition"); | ||
1920 | if (!p->process_trans_perms) | ||
1921 | goto bad; | ||
1922 | |||
1864 | for (i = 0; i < info->ocon_num; i++) { | 1923 | for (i = 0; i < info->ocon_num; i++) { |
1865 | rc = next_entry(buf, fp, sizeof(u32)); | 1924 | rc = next_entry(buf, fp, sizeof(u32)); |
1866 | if (rc < 0) | 1925 | if (rc < 0) |
@@ -2079,44 +2138,61 @@ int policydb_read(struct policydb *p, void *fp) | |||
2079 | if (rc < 0) | 2138 | if (rc < 0) |
2080 | goto bad; | 2139 | goto bad; |
2081 | nel = le32_to_cpu(buf[0]); | 2140 | nel = le32_to_cpu(buf[0]); |
2082 | lrt = NULL; | ||
2083 | for (i = 0; i < nel; i++) { | 2141 | for (i = 0; i < nel; i++) { |
2084 | rt = kzalloc(sizeof(*rt), GFP_KERNEL); | 2142 | rt = kzalloc(sizeof(*rt), GFP_KERNEL); |
2085 | if (!rt) { | 2143 | if (!rt) { |
2086 | rc = -ENOMEM; | 2144 | rc = -ENOMEM; |
2087 | goto bad; | 2145 | goto bad; |
2088 | } | 2146 | } |
2089 | if (lrt) | ||
2090 | lrt->next = rt; | ||
2091 | else | ||
2092 | p->range_tr = rt; | ||
2093 | rc = next_entry(buf, fp, (sizeof(u32) * 2)); | 2147 | rc = next_entry(buf, fp, (sizeof(u32) * 2)); |
2094 | if (rc < 0) | 2148 | if (rc < 0) { |
2149 | kfree(rt); | ||
2095 | goto bad; | 2150 | goto bad; |
2151 | } | ||
2096 | rt->source_type = le32_to_cpu(buf[0]); | 2152 | rt->source_type = le32_to_cpu(buf[0]); |
2097 | rt->target_type = le32_to_cpu(buf[1]); | 2153 | rt->target_type = le32_to_cpu(buf[1]); |
2098 | if (new_rangetr) { | 2154 | if (new_rangetr) { |
2099 | rc = next_entry(buf, fp, sizeof(u32)); | 2155 | rc = next_entry(buf, fp, sizeof(u32)); |
2100 | if (rc < 0) | 2156 | if (rc < 0) { |
2157 | kfree(rt); | ||
2101 | goto bad; | 2158 | goto bad; |
2159 | } | ||
2102 | rt->target_class = le32_to_cpu(buf[0]); | 2160 | rt->target_class = le32_to_cpu(buf[0]); |
2103 | } else | 2161 | } else |
2104 | rt->target_class = SECCLASS_PROCESS; | 2162 | rt->target_class = p->process_class; |
2105 | if (!policydb_type_isvalid(p, rt->source_type) || | 2163 | if (!policydb_type_isvalid(p, rt->source_type) || |
2106 | !policydb_type_isvalid(p, rt->target_type) || | 2164 | !policydb_type_isvalid(p, rt->target_type) || |
2107 | !policydb_class_isvalid(p, rt->target_class)) { | 2165 | !policydb_class_isvalid(p, rt->target_class)) { |
2166 | kfree(rt); | ||
2108 | rc = -EINVAL; | 2167 | rc = -EINVAL; |
2109 | goto bad; | 2168 | goto bad; |
2110 | } | 2169 | } |
2111 | rc = mls_read_range_helper(&rt->target_range, fp); | 2170 | r = kzalloc(sizeof(*r), GFP_KERNEL); |
2112 | if (rc) | 2171 | if (!r) { |
2172 | kfree(rt); | ||
2173 | rc = -ENOMEM; | ||
2174 | goto bad; | ||
2175 | } | ||
2176 | rc = mls_read_range_helper(r, fp); | ||
2177 | if (rc) { | ||
2178 | kfree(rt); | ||
2179 | kfree(r); | ||
2113 | goto bad; | 2180 | goto bad; |
2114 | if (!mls_range_isvalid(p, &rt->target_range)) { | 2181 | } |
2182 | if (!mls_range_isvalid(p, r)) { | ||
2115 | 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); | ||
2116 | goto bad; | 2192 | goto bad; |
2117 | } | 2193 | } |
2118 | lrt = rt; | ||
2119 | } | 2194 | } |
2195 | rangetr_hash_eval(p->range_tr); | ||
2120 | } | 2196 | } |
2121 | 2197 | ||
2122 | 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); |