aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--security/selinux/ss/mls.c18
-rw-r--r--security/selinux/ss/policydb.c103
-rw-r--r--security/selinux/ss/policydb.h6
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
180static 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
187static 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
431static 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
441static 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
648static 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
615static void ocontext_destroy(struct ocontext *c, int i) 659static 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;