diff options
| -rw-r--r-- | security/selinux/ss/mls.c | 18 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.c | 103 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.h | 6 |
3 files changed, 86 insertions, 41 deletions
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index e6654b543aed..443ae7370144 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c | |||
| @@ -513,7 +513,8 @@ int mls_compute_sid(struct context *scontext, | |||
| 513 | u32 specified, | 513 | u32 specified, |
| 514 | struct context *newcontext) | 514 | struct context *newcontext) |
| 515 | { | 515 | { |
| 516 | struct range_trans *rtr; | 516 | struct range_trans rtr; |
| 517 | struct mls_range *r; | ||
| 517 | 518 | ||
| 518 | if (!selinux_mls_enabled) | 519 | if (!selinux_mls_enabled) |
| 519 | return 0; | 520 | return 0; |
| @@ -521,15 +522,12 @@ int mls_compute_sid(struct context *scontext, | |||
| 521 | switch (specified) { | 522 | switch (specified) { |
| 522 | case AVTAB_TRANSITION: | 523 | case AVTAB_TRANSITION: |
| 523 | /* Look for a range transition rule. */ | 524 | /* Look for a range transition rule. */ |
| 524 | for (rtr = policydb.range_tr; rtr; rtr = rtr->next) { | 525 | rtr.source_type = scontext->type; |
| 525 | if (rtr->source_type == scontext->type && | 526 | rtr.target_type = tcontext->type; |
| 526 | rtr->target_type == tcontext->type && | 527 | rtr.target_class = tclass; |
| 527 | rtr->target_class == tclass) { | 528 | r = hashtab_search(policydb.range_tr, &rtr); |
| 528 | /* Set the range from the rule */ | 529 | if (r) |
| 529 | return mls_range_set(newcontext, | 530 | return mls_range_set(newcontext, r); |
| 530 | &rtr->target_range); | ||
| 531 | } | ||
| 532 | } | ||
| 533 | /* Fallthrough */ | 531 | /* Fallthrough */ |
| 534 | case AVTAB_CHANGE: | 532 | case AVTAB_CHANGE: |
| 535 | if (tclass == policydb.process_class) | 533 | if (tclass == policydb.process_class) |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index f03667213ea8..5b92c0219207 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
| @@ -177,6 +177,21 @@ out_free_role: | |||
| 177 | goto out; | 177 | goto out; |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | static u32 rangetr_hash(struct hashtab *h, const void *k) | ||
| 181 | { | ||
| 182 | const struct range_trans *key = k; | ||
| 183 | return (key->source_type + (key->target_type << 3) + | ||
| 184 | (key->target_class << 5)) & (h->size - 1); | ||
| 185 | } | ||
| 186 | |||
| 187 | static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2) | ||
| 188 | { | ||
| 189 | const struct range_trans *key1 = k1, *key2 = k2; | ||
| 190 | return (key1->source_type != key2->source_type || | ||
| 191 | key1->target_type != key2->target_type || | ||
| 192 | key1->target_class != key2->target_class); | ||
| 193 | } | ||
| 194 | |||
| 180 | /* | 195 | /* |
| 181 | * Initialize a policy database structure. | 196 | * Initialize a policy database structure. |
| 182 | */ | 197 | */ |
| @@ -204,6 +219,10 @@ static int policydb_init(struct policydb *p) | |||
| 204 | if (rc) | 219 | if (rc) |
| 205 | goto out_free_symtab; | 220 | goto out_free_symtab; |
| 206 | 221 | ||
| 222 | p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); | ||
| 223 | if (!p->range_tr) | ||
| 224 | goto out_free_symtab; | ||
| 225 | |||
| 207 | ebitmap_init(&p->policycaps); | 226 | ebitmap_init(&p->policycaps); |
| 208 | ebitmap_init(&p->permissive_map); | 227 | ebitmap_init(&p->permissive_map); |
| 209 | 228 | ||
| @@ -408,6 +427,20 @@ static void symtab_hash_eval(struct symtab *s) | |||
| 408 | info.slots_used, h->size, info.max_chain_len); | 427 | info.slots_used, h->size, info.max_chain_len); |
| 409 | } | 428 | } |
| 410 | } | 429 | } |
| 430 | |||
| 431 | static void rangetr_hash_eval(struct hashtab *h) | ||
| 432 | { | ||
| 433 | struct hashtab_info info; | ||
| 434 | |||
| 435 | hashtab_stat(h, &info); | ||
| 436 | printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, " | ||
| 437 | "longest chain length %d\n", h->nel, | ||
| 438 | info.slots_used, h->size, info.max_chain_len); | ||
| 439 | } | ||
| 440 | #else | ||
| 441 | static inline void rangetr_hash_eval(struct hashtab *h) | ||
| 442 | { | ||
| 443 | } | ||
| 411 | #endif | 444 | #endif |
| 412 | 445 | ||
| 413 | /* | 446 | /* |
| @@ -612,6 +645,17 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = | |||
| 612 | cat_destroy, | 645 | cat_destroy, |
| 613 | }; | 646 | }; |
| 614 | 647 | ||
| 648 | static int range_tr_destroy(void *key, void *datum, void *p) | ||
| 649 | { | ||
| 650 | struct mls_range *rt = datum; | ||
| 651 | kfree(key); | ||
| 652 | ebitmap_destroy(&rt->level[0].cat); | ||
| 653 | ebitmap_destroy(&rt->level[1].cat); | ||
| 654 | kfree(datum); | ||
| 655 | cond_resched(); | ||
| 656 | return 0; | ||
| 657 | } | ||
| 658 | |||
| 615 | static void ocontext_destroy(struct ocontext *c, int i) | 659 | static void ocontext_destroy(struct ocontext *c, int i) |
| 616 | { | 660 | { |
| 617 | context_destroy(&c->context[0]); | 661 | context_destroy(&c->context[0]); |
| @@ -632,7 +676,6 @@ void policydb_destroy(struct policydb *p) | |||
| 632 | int i; | 676 | int i; |
| 633 | struct role_allow *ra, *lra = NULL; | 677 | struct role_allow *ra, *lra = NULL; |
| 634 | struct role_trans *tr, *ltr = NULL; | 678 | struct role_trans *tr, *ltr = NULL; |
| 635 | struct range_trans *rt, *lrt = NULL; | ||
| 636 | 679 | ||
| 637 | for (i = 0; i < SYM_NUM; i++) { | 680 | for (i = 0; i < SYM_NUM; i++) { |
| 638 | cond_resched(); | 681 | cond_resched(); |
| @@ -693,20 +736,8 @@ void policydb_destroy(struct policydb *p) | |||
| 693 | } | 736 | } |
| 694 | kfree(lra); | 737 | kfree(lra); |
| 695 | 738 | ||
| 696 | for (rt = p->range_tr; rt; rt = rt->next) { | 739 | hashtab_map(p->range_tr, range_tr_destroy, NULL); |
| 697 | cond_resched(); | 740 | 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 | 741 | ||
| 711 | if (p->type_attr_map) { | 742 | if (p->type_attr_map) { |
| 712 | for (i = 0; i < p->p_types.nprim; i++) | 743 | for (i = 0; i < p->p_types.nprim; i++) |
| @@ -1689,7 +1720,8 @@ int policydb_read(struct policydb *p, void *fp) | |||
| 1689 | u32 len, len2, config, nprim, nel, nel2; | 1720 | u32 len, len2, config, nprim, nel, nel2; |
| 1690 | char *policydb_str; | 1721 | char *policydb_str; |
| 1691 | struct policydb_compat_info *info; | 1722 | struct policydb_compat_info *info; |
| 1692 | struct range_trans *rt, *lrt; | 1723 | struct range_trans *rt; |
| 1724 | struct mls_range *r; | ||
| 1693 | 1725 | ||
| 1694 | config = 0; | 1726 | config = 0; |
| 1695 | 1727 | ||
| @@ -2122,44 +2154,61 @@ int policydb_read(struct policydb *p, void *fp) | |||
| 2122 | if (rc < 0) | 2154 | if (rc < 0) |
| 2123 | goto bad; | 2155 | goto bad; |
| 2124 | nel = le32_to_cpu(buf[0]); | 2156 | nel = le32_to_cpu(buf[0]); |
| 2125 | lrt = NULL; | ||
| 2126 | for (i = 0; i < nel; i++) { | 2157 | for (i = 0; i < nel; i++) { |
| 2127 | rt = kzalloc(sizeof(*rt), GFP_KERNEL); | 2158 | rt = kzalloc(sizeof(*rt), GFP_KERNEL); |
| 2128 | if (!rt) { | 2159 | if (!rt) { |
| 2129 | rc = -ENOMEM; | 2160 | rc = -ENOMEM; |
| 2130 | goto bad; | 2161 | goto bad; |
| 2131 | } | 2162 | } |
| 2132 | if (lrt) | ||
| 2133 | lrt->next = rt; | ||
| 2134 | else | ||
| 2135 | p->range_tr = rt; | ||
| 2136 | rc = next_entry(buf, fp, (sizeof(u32) * 2)); | 2163 | rc = next_entry(buf, fp, (sizeof(u32) * 2)); |
| 2137 | if (rc < 0) | 2164 | if (rc < 0) { |
| 2165 | kfree(rt); | ||
| 2138 | goto bad; | 2166 | goto bad; |
| 2167 | } | ||
| 2139 | rt->source_type = le32_to_cpu(buf[0]); | 2168 | rt->source_type = le32_to_cpu(buf[0]); |
| 2140 | rt->target_type = le32_to_cpu(buf[1]); | 2169 | rt->target_type = le32_to_cpu(buf[1]); |
| 2141 | if (new_rangetr) { | 2170 | if (new_rangetr) { |
| 2142 | rc = next_entry(buf, fp, sizeof(u32)); | 2171 | rc = next_entry(buf, fp, sizeof(u32)); |
| 2143 | if (rc < 0) | 2172 | if (rc < 0) { |
| 2173 | kfree(rt); | ||
| 2144 | goto bad; | 2174 | goto bad; |
| 2175 | } | ||
| 2145 | rt->target_class = le32_to_cpu(buf[0]); | 2176 | rt->target_class = le32_to_cpu(buf[0]); |
| 2146 | } else | 2177 | } else |
| 2147 | rt->target_class = p->process_class; | 2178 | rt->target_class = p->process_class; |
| 2148 | if (!policydb_type_isvalid(p, rt->source_type) || | 2179 | if (!policydb_type_isvalid(p, rt->source_type) || |
| 2149 | !policydb_type_isvalid(p, rt->target_type) || | 2180 | !policydb_type_isvalid(p, rt->target_type) || |
| 2150 | !policydb_class_isvalid(p, rt->target_class)) { | 2181 | !policydb_class_isvalid(p, rt->target_class)) { |
| 2182 | kfree(rt); | ||
| 2151 | rc = -EINVAL; | 2183 | rc = -EINVAL; |
| 2152 | goto bad; | 2184 | goto bad; |
| 2153 | } | 2185 | } |
| 2154 | rc = mls_read_range_helper(&rt->target_range, fp); | 2186 | r = kzalloc(sizeof(*r), GFP_KERNEL); |
| 2155 | if (rc) | 2187 | if (!r) { |
| 2188 | kfree(rt); | ||
| 2189 | rc = -ENOMEM; | ||
| 2156 | goto bad; | 2190 | goto bad; |
| 2157 | if (!mls_range_isvalid(p, &rt->target_range)) { | 2191 | } |
| 2192 | rc = mls_read_range_helper(r, fp); | ||
| 2193 | if (rc) { | ||
| 2194 | kfree(rt); | ||
| 2195 | kfree(r); | ||
| 2196 | goto bad; | ||
| 2197 | } | ||
| 2198 | if (!mls_range_isvalid(p, r)) { | ||
| 2158 | printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); | 2199 | printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); |
| 2200 | kfree(rt); | ||
| 2201 | kfree(r); | ||
| 2202 | goto bad; | ||
| 2203 | } | ||
| 2204 | rc = hashtab_insert(p->range_tr, rt, r); | ||
| 2205 | if (rc) { | ||
| 2206 | kfree(rt); | ||
| 2207 | kfree(r); | ||
| 2159 | goto bad; | 2208 | goto bad; |
| 2160 | } | 2209 | } |
| 2161 | lrt = rt; | ||
| 2162 | } | 2210 | } |
| 2211 | rangetr_hash_eval(p->range_tr); | ||
| 2163 | } | 2212 | } |
| 2164 | 2213 | ||
| 2165 | p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); | 2214 | p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); |
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index cdcc5700946f..193736b64de8 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
| @@ -113,8 +113,6 @@ struct range_trans { | |||
| 113 | u32 source_type; | 113 | u32 source_type; |
| 114 | u32 target_type; | 114 | u32 target_type; |
| 115 | u32 target_class; | 115 | u32 target_class; |
| 116 | struct mls_range target_range; | ||
| 117 | struct range_trans *next; | ||
| 118 | }; | 116 | }; |
| 119 | 117 | ||
| 120 | /* Boolean data type */ | 118 | /* Boolean data type */ |
| @@ -240,8 +238,8 @@ struct policydb { | |||
| 240 | fixed labeling behavior. */ | 238 | fixed labeling behavior. */ |
| 241 | struct genfs *genfs; | 239 | struct genfs *genfs; |
| 242 | 240 | ||
| 243 | /* range transitions */ | 241 | /* range transitions table (range_trans_key -> mls_range) */ |
| 244 | struct range_trans *range_tr; | 242 | struct hashtab *range_tr; |
| 245 | 243 | ||
| 246 | /* type -> attribute reverse mapping */ | 244 | /* type -> attribute reverse mapping */ |
| 247 | struct ebitmap *type_attr_map; | 245 | struct ebitmap *type_attr_map; |
