aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/ss/policydb.c
diff options
context:
space:
mode:
authorStephen Smalley <sds@tycho.nsa.gov>2010-01-07 15:55:16 -0500
committerJames Morris <jmorris@namei.org>2010-01-24 16:29:05 -0500
commit2f3e82d694d3d7a2db019db1bb63385fbc1066f3 (patch)
tree9d99a883eb2ab097a3ff1ee4e1c9bf2fa851d832 /security/selinux/ss/policydb.c
parent2457552d1e6f3183cd93f81c49a8da5fe8bb0e42 (diff)
selinux: convert range transition list to a hashtab
Per https://bugzilla.redhat.com/show_bug.cgi?id=548145 there are sufficient range transition rules in modern (Fedora) policy to make mls_compute_sid a significant factor on the shmem file setup path due to the length of the range_tr list. Replace the simple range_tr list with a hashtab inside the security server to help mitigate this problem. Signed-off-by: Stephen D. Smalley <sds@tycho.nsa.gov> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/selinux/ss/policydb.c')
-rw-r--r--security/selinux/ss/policydb.c103
1 files changed, 76 insertions, 27 deletions
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);