diff options
Diffstat (limited to 'security/selinux/ss/policydb.c')
-rw-r--r-- | security/selinux/ss/policydb.c | 244 |
1 files changed, 168 insertions, 76 deletions
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 7102457661d6..102e9ec1b77a 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -128,6 +128,11 @@ static struct policydb_compat_info policydb_compat[] = { | |||
128 | .sym_num = SYM_NUM, | 128 | .sym_num = SYM_NUM, |
129 | .ocon_num = OCON_NUM, | 129 | .ocon_num = OCON_NUM, |
130 | }, | 130 | }, |
131 | { | ||
132 | .version = POLICYDB_VERSION_ROLETRANS, | ||
133 | .sym_num = SYM_NUM, | ||
134 | .ocon_num = OCON_NUM, | ||
135 | }, | ||
131 | }; | 136 | }; |
132 | 137 | ||
133 | static struct policydb_compat_info *policydb_lookup_compat(int version) | 138 | static struct policydb_compat_info *policydb_lookup_compat(int version) |
@@ -179,6 +184,43 @@ out: | |||
179 | return rc; | 184 | return rc; |
180 | } | 185 | } |
181 | 186 | ||
187 | static u32 filenametr_hash(struct hashtab *h, const void *k) | ||
188 | { | ||
189 | const struct filename_trans *ft = k; | ||
190 | unsigned long hash; | ||
191 | unsigned int byte_num; | ||
192 | unsigned char focus; | ||
193 | |||
194 | hash = ft->stype ^ ft->ttype ^ ft->tclass; | ||
195 | |||
196 | byte_num = 0; | ||
197 | while ((focus = ft->name[byte_num++])) | ||
198 | hash = partial_name_hash(focus, hash); | ||
199 | return hash & (h->size - 1); | ||
200 | } | ||
201 | |||
202 | static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2) | ||
203 | { | ||
204 | const struct filename_trans *ft1 = k1; | ||
205 | const struct filename_trans *ft2 = k2; | ||
206 | int v; | ||
207 | |||
208 | v = ft1->stype - ft2->stype; | ||
209 | if (v) | ||
210 | return v; | ||
211 | |||
212 | v = ft1->ttype - ft2->ttype; | ||
213 | if (v) | ||
214 | return v; | ||
215 | |||
216 | v = ft1->tclass - ft2->tclass; | ||
217 | if (v) | ||
218 | return v; | ||
219 | |||
220 | return strcmp(ft1->name, ft2->name); | ||
221 | |||
222 | } | ||
223 | |||
182 | static u32 rangetr_hash(struct hashtab *h, const void *k) | 224 | static u32 rangetr_hash(struct hashtab *h, const void *k) |
183 | { | 225 | { |
184 | const struct range_trans *key = k; | 226 | const struct range_trans *key = k; |
@@ -231,15 +273,22 @@ static int policydb_init(struct policydb *p) | |||
231 | if (rc) | 273 | if (rc) |
232 | goto out; | 274 | goto out; |
233 | 275 | ||
276 | p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10)); | ||
277 | if (!p->filename_trans) | ||
278 | goto out; | ||
279 | |||
234 | p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); | 280 | p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); |
235 | if (!p->range_tr) | 281 | if (!p->range_tr) |
236 | goto out; | 282 | goto out; |
237 | 283 | ||
284 | ebitmap_init(&p->filename_trans_ttypes); | ||
238 | ebitmap_init(&p->policycaps); | 285 | ebitmap_init(&p->policycaps); |
239 | ebitmap_init(&p->permissive_map); | 286 | ebitmap_init(&p->permissive_map); |
240 | 287 | ||
241 | return 0; | 288 | return 0; |
242 | out: | 289 | out: |
290 | hashtab_destroy(p->filename_trans); | ||
291 | hashtab_destroy(p->range_tr); | ||
243 | for (i = 0; i < SYM_NUM; i++) | 292 | for (i = 0; i < SYM_NUM; i++) |
244 | hashtab_destroy(p->symtab[i].table); | 293 | hashtab_destroy(p->symtab[i].table); |
245 | return rc; | 294 | return rc; |
@@ -417,32 +466,26 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) = | |||
417 | }; | 466 | }; |
418 | 467 | ||
419 | #ifdef DEBUG_HASHES | 468 | #ifdef DEBUG_HASHES |
420 | static void symtab_hash_eval(struct symtab *s) | 469 | static void hash_eval(struct hashtab *h, const char *hash_name) |
421 | { | 470 | { |
422 | int i; | 471 | struct hashtab_info info; |
423 | |||
424 | for (i = 0; i < SYM_NUM; i++) { | ||
425 | struct hashtab *h = s[i].table; | ||
426 | struct hashtab_info info; | ||
427 | 472 | ||
428 | hashtab_stat(h, &info); | 473 | hashtab_stat(h, &info); |
429 | printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, " | 474 | printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, " |
430 | "longest chain length %d\n", symtab_name[i], h->nel, | 475 | "longest chain length %d\n", hash_name, h->nel, |
431 | info.slots_used, h->size, info.max_chain_len); | 476 | info.slots_used, h->size, info.max_chain_len); |
432 | } | ||
433 | } | 477 | } |
434 | 478 | ||
435 | static void rangetr_hash_eval(struct hashtab *h) | 479 | static void symtab_hash_eval(struct symtab *s) |
436 | { | 480 | { |
437 | struct hashtab_info info; | 481 | int i; |
438 | 482 | ||
439 | hashtab_stat(h, &info); | 483 | for (i = 0; i < SYM_NUM; i++) |
440 | printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, " | 484 | hash_eval(s[i].table, symtab_name[i]); |
441 | "longest chain length %d\n", h->nel, | ||
442 | info.slots_used, h->size, info.max_chain_len); | ||
443 | } | 485 | } |
486 | |||
444 | #else | 487 | #else |
445 | static inline void rangetr_hash_eval(struct hashtab *h) | 488 | static inline void hash_eval(struct hashtab *h, char *hash_name) |
446 | { | 489 | { |
447 | } | 490 | } |
448 | #endif | 491 | #endif |
@@ -675,6 +718,16 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = | |||
675 | cat_destroy, | 718 | cat_destroy, |
676 | }; | 719 | }; |
677 | 720 | ||
721 | static int filenametr_destroy(void *key, void *datum, void *p) | ||
722 | { | ||
723 | struct filename_trans *ft = key; | ||
724 | kfree(ft->name); | ||
725 | kfree(key); | ||
726 | kfree(datum); | ||
727 | cond_resched(); | ||
728 | return 0; | ||
729 | } | ||
730 | |||
678 | static int range_tr_destroy(void *key, void *datum, void *p) | 731 | static int range_tr_destroy(void *key, void *datum, void *p) |
679 | { | 732 | { |
680 | struct mls_range *rt = datum; | 733 | struct mls_range *rt = datum; |
@@ -709,7 +762,6 @@ void policydb_destroy(struct policydb *p) | |||
709 | int i; | 762 | int i; |
710 | struct role_allow *ra, *lra = NULL; | 763 | struct role_allow *ra, *lra = NULL; |
711 | struct role_trans *tr, *ltr = NULL; | 764 | struct role_trans *tr, *ltr = NULL; |
712 | struct filename_trans *ft, *nft; | ||
713 | 765 | ||
714 | for (i = 0; i < SYM_NUM; i++) { | 766 | for (i = 0; i < SYM_NUM; i++) { |
715 | cond_resched(); | 767 | cond_resched(); |
@@ -773,6 +825,9 @@ void policydb_destroy(struct policydb *p) | |||
773 | } | 825 | } |
774 | kfree(lra); | 826 | kfree(lra); |
775 | 827 | ||
828 | hashtab_map(p->filename_trans, filenametr_destroy, NULL); | ||
829 | hashtab_destroy(p->filename_trans); | ||
830 | |||
776 | hashtab_map(p->range_tr, range_tr_destroy, NULL); | 831 | hashtab_map(p->range_tr, range_tr_destroy, NULL); |
777 | hashtab_destroy(p->range_tr); | 832 | hashtab_destroy(p->range_tr); |
778 | 833 | ||
@@ -788,14 +843,7 @@ void policydb_destroy(struct policydb *p) | |||
788 | flex_array_free(p->type_attr_map_array); | 843 | flex_array_free(p->type_attr_map_array); |
789 | } | 844 | } |
790 | 845 | ||
791 | ft = p->filename_trans; | 846 | ebitmap_destroy(&p->filename_trans_ttypes); |
792 | while (ft) { | ||
793 | nft = ft->next; | ||
794 | kfree(ft->name); | ||
795 | kfree(ft); | ||
796 | ft = nft; | ||
797 | } | ||
798 | |||
799 | ebitmap_destroy(&p->policycaps); | 847 | ebitmap_destroy(&p->policycaps); |
800 | ebitmap_destroy(&p->permissive_map); | 848 | ebitmap_destroy(&p->permissive_map); |
801 | 849 | ||
@@ -1795,7 +1843,7 @@ static int range_read(struct policydb *p, void *fp) | |||
1795 | rt = NULL; | 1843 | rt = NULL; |
1796 | r = NULL; | 1844 | r = NULL; |
1797 | } | 1845 | } |
1798 | rangetr_hash_eval(p->range_tr); | 1846 | hash_eval(p->range_tr, "rangetr"); |
1799 | rc = 0; | 1847 | rc = 0; |
1800 | out: | 1848 | out: |
1801 | kfree(rt); | 1849 | kfree(rt); |
@@ -1805,9 +1853,10 @@ out: | |||
1805 | 1853 | ||
1806 | static int filename_trans_read(struct policydb *p, void *fp) | 1854 | static int filename_trans_read(struct policydb *p, void *fp) |
1807 | { | 1855 | { |
1808 | struct filename_trans *ft, *last; | 1856 | struct filename_trans *ft; |
1809 | u32 nel, len; | 1857 | struct filename_trans_datum *otype; |
1810 | char *name; | 1858 | char *name; |
1859 | u32 nel, len; | ||
1811 | __le32 buf[4]; | 1860 | __le32 buf[4]; |
1812 | int rc, i; | 1861 | int rc, i; |
1813 | 1862 | ||
@@ -1816,25 +1865,23 @@ static int filename_trans_read(struct policydb *p, void *fp) | |||
1816 | 1865 | ||
1817 | rc = next_entry(buf, fp, sizeof(u32)); | 1866 | rc = next_entry(buf, fp, sizeof(u32)); |
1818 | if (rc) | 1867 | if (rc) |
1819 | goto out; | 1868 | return rc; |
1820 | nel = le32_to_cpu(buf[0]); | 1869 | nel = le32_to_cpu(buf[0]); |
1821 | 1870 | ||
1822 | last = p->filename_trans; | ||
1823 | while (last && last->next) | ||
1824 | last = last->next; | ||
1825 | |||
1826 | for (i = 0; i < nel; i++) { | 1871 | for (i = 0; i < nel; i++) { |
1872 | ft = NULL; | ||
1873 | otype = NULL; | ||
1874 | name = NULL; | ||
1875 | |||
1827 | rc = -ENOMEM; | 1876 | rc = -ENOMEM; |
1828 | ft = kzalloc(sizeof(*ft), GFP_KERNEL); | 1877 | ft = kzalloc(sizeof(*ft), GFP_KERNEL); |
1829 | if (!ft) | 1878 | if (!ft) |
1830 | goto out; | 1879 | goto out; |
1831 | 1880 | ||
1832 | /* add it to the tail of the list */ | 1881 | rc = -ENOMEM; |
1833 | if (!last) | 1882 | otype = kmalloc(sizeof(*otype), GFP_KERNEL); |
1834 | p->filename_trans = ft; | 1883 | if (!otype) |
1835 | else | 1884 | goto out; |
1836 | last->next = ft; | ||
1837 | last = ft; | ||
1838 | 1885 | ||
1839 | /* length of the path component string */ | 1886 | /* length of the path component string */ |
1840 | rc = next_entry(buf, fp, sizeof(u32)); | 1887 | rc = next_entry(buf, fp, sizeof(u32)); |
@@ -1862,10 +1909,22 @@ static int filename_trans_read(struct policydb *p, void *fp) | |||
1862 | ft->stype = le32_to_cpu(buf[0]); | 1909 | ft->stype = le32_to_cpu(buf[0]); |
1863 | ft->ttype = le32_to_cpu(buf[1]); | 1910 | ft->ttype = le32_to_cpu(buf[1]); |
1864 | ft->tclass = le32_to_cpu(buf[2]); | 1911 | ft->tclass = le32_to_cpu(buf[2]); |
1865 | ft->otype = le32_to_cpu(buf[3]); | 1912 | |
1913 | otype->otype = le32_to_cpu(buf[3]); | ||
1914 | |||
1915 | rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1); | ||
1916 | if (rc) | ||
1917 | goto out; | ||
1918 | |||
1919 | hashtab_insert(p->filename_trans, ft, otype); | ||
1866 | } | 1920 | } |
1867 | rc = 0; | 1921 | hash_eval(p->filename_trans, "filenametr"); |
1922 | return 0; | ||
1868 | out: | 1923 | out: |
1924 | kfree(ft); | ||
1925 | kfree(name); | ||
1926 | kfree(otype); | ||
1927 | |||
1869 | return rc; | 1928 | return rc; |
1870 | } | 1929 | } |
1871 | 1930 | ||
@@ -2266,6 +2325,11 @@ int policydb_read(struct policydb *p, void *fp) | |||
2266 | p->symtab[i].nprim = nprim; | 2325 | p->symtab[i].nprim = nprim; |
2267 | } | 2326 | } |
2268 | 2327 | ||
2328 | rc = -EINVAL; | ||
2329 | p->process_class = string_to_security_class(p, "process"); | ||
2330 | if (!p->process_class) | ||
2331 | goto bad; | ||
2332 | |||
2269 | rc = avtab_read(&p->te_avtab, fp, p); | 2333 | rc = avtab_read(&p->te_avtab, fp, p); |
2270 | if (rc) | 2334 | if (rc) |
2271 | goto bad; | 2335 | goto bad; |
@@ -2298,8 +2362,17 @@ int policydb_read(struct policydb *p, void *fp) | |||
2298 | tr->role = le32_to_cpu(buf[0]); | 2362 | tr->role = le32_to_cpu(buf[0]); |
2299 | tr->type = le32_to_cpu(buf[1]); | 2363 | tr->type = le32_to_cpu(buf[1]); |
2300 | tr->new_role = le32_to_cpu(buf[2]); | 2364 | tr->new_role = le32_to_cpu(buf[2]); |
2365 | if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) { | ||
2366 | rc = next_entry(buf, fp, sizeof(u32)); | ||
2367 | if (rc) | ||
2368 | goto bad; | ||
2369 | tr->tclass = le32_to_cpu(buf[0]); | ||
2370 | } else | ||
2371 | tr->tclass = p->process_class; | ||
2372 | |||
2301 | if (!policydb_role_isvalid(p, tr->role) || | 2373 | if (!policydb_role_isvalid(p, tr->role) || |
2302 | !policydb_type_isvalid(p, tr->type) || | 2374 | !policydb_type_isvalid(p, tr->type) || |
2375 | !policydb_class_isvalid(p, tr->tclass) || | ||
2303 | !policydb_role_isvalid(p, tr->new_role)) | 2376 | !policydb_role_isvalid(p, tr->new_role)) |
2304 | goto bad; | 2377 | goto bad; |
2305 | ltr = tr; | 2378 | ltr = tr; |
@@ -2341,11 +2414,6 @@ int policydb_read(struct policydb *p, void *fp) | |||
2341 | goto bad; | 2414 | goto bad; |
2342 | 2415 | ||
2343 | rc = -EINVAL; | 2416 | rc = -EINVAL; |
2344 | p->process_class = string_to_security_class(p, "process"); | ||
2345 | if (!p->process_class) | ||
2346 | goto bad; | ||
2347 | |||
2348 | rc = -EINVAL; | ||
2349 | p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition"); | 2417 | p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition"); |
2350 | p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition"); | 2418 | p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition"); |
2351 | if (!p->process_trans_perms) | 2419 | if (!p->process_trans_perms) |
@@ -2517,8 +2585,9 @@ static int cat_write(void *vkey, void *datum, void *ptr) | |||
2517 | return 0; | 2585 | return 0; |
2518 | } | 2586 | } |
2519 | 2587 | ||
2520 | static int role_trans_write(struct role_trans *r, void *fp) | 2588 | static int role_trans_write(struct policydb *p, void *fp) |
2521 | { | 2589 | { |
2590 | struct role_trans *r = p->role_tr; | ||
2522 | struct role_trans *tr; | 2591 | struct role_trans *tr; |
2523 | u32 buf[3]; | 2592 | u32 buf[3]; |
2524 | size_t nel; | 2593 | size_t nel; |
@@ -2538,6 +2607,12 @@ static int role_trans_write(struct role_trans *r, void *fp) | |||
2538 | rc = put_entry(buf, sizeof(u32), 3, fp); | 2607 | rc = put_entry(buf, sizeof(u32), 3, fp); |
2539 | if (rc) | 2608 | if (rc) |
2540 | return rc; | 2609 | return rc; |
2610 | if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) { | ||
2611 | buf[0] = cpu_to_le32(tr->tclass); | ||
2612 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2613 | if (rc) | ||
2614 | return rc; | ||
2615 | } | ||
2541 | } | 2616 | } |
2542 | 2617 | ||
2543 | return 0; | 2618 | return 0; |
@@ -3045,7 +3120,7 @@ static int genfs_write(struct policydb *p, void *fp) | |||
3045 | return 0; | 3120 | return 0; |
3046 | } | 3121 | } |
3047 | 3122 | ||
3048 | static int range_count(void *key, void *data, void *ptr) | 3123 | static int hashtab_cnt(void *key, void *data, void *ptr) |
3049 | { | 3124 | { |
3050 | int *cnt = ptr; | 3125 | int *cnt = ptr; |
3051 | *cnt = *cnt + 1; | 3126 | *cnt = *cnt + 1; |
@@ -3093,7 +3168,7 @@ static int range_write(struct policydb *p, void *fp) | |||
3093 | 3168 | ||
3094 | /* count the number of entries in the hashtab */ | 3169 | /* count the number of entries in the hashtab */ |
3095 | nel = 0; | 3170 | nel = 0; |
3096 | rc = hashtab_map(p->range_tr, range_count, &nel); | 3171 | rc = hashtab_map(p->range_tr, hashtab_cnt, &nel); |
3097 | if (rc) | 3172 | if (rc) |
3098 | return rc; | 3173 | return rc; |
3099 | 3174 | ||
@@ -3110,43 +3185,60 @@ static int range_write(struct policydb *p, void *fp) | |||
3110 | return 0; | 3185 | return 0; |
3111 | } | 3186 | } |
3112 | 3187 | ||
3113 | static int filename_trans_write(struct policydb *p, void *fp) | 3188 | static int filename_write_helper(void *key, void *data, void *ptr) |
3114 | { | 3189 | { |
3115 | struct filename_trans *ft; | ||
3116 | u32 len, nel = 0; | ||
3117 | __le32 buf[4]; | 3190 | __le32 buf[4]; |
3191 | struct filename_trans *ft = key; | ||
3192 | struct filename_trans_datum *otype = data; | ||
3193 | void *fp = ptr; | ||
3118 | int rc; | 3194 | int rc; |
3195 | u32 len; | ||
3119 | 3196 | ||
3120 | for (ft = p->filename_trans; ft; ft = ft->next) | 3197 | len = strlen(ft->name); |
3121 | nel++; | 3198 | buf[0] = cpu_to_le32(len); |
3122 | |||
3123 | buf[0] = cpu_to_le32(nel); | ||
3124 | rc = put_entry(buf, sizeof(u32), 1, fp); | 3199 | rc = put_entry(buf, sizeof(u32), 1, fp); |
3125 | if (rc) | 3200 | if (rc) |
3126 | return rc; | 3201 | return rc; |
3127 | 3202 | ||
3128 | for (ft = p->filename_trans; ft; ft = ft->next) { | 3203 | rc = put_entry(ft->name, sizeof(char), len, fp); |
3129 | len = strlen(ft->name); | 3204 | if (rc) |
3130 | buf[0] = cpu_to_le32(len); | 3205 | return rc; |
3131 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
3132 | if (rc) | ||
3133 | return rc; | ||
3134 | 3206 | ||
3135 | rc = put_entry(ft->name, sizeof(char), len, fp); | 3207 | buf[0] = ft->stype; |
3136 | if (rc) | 3208 | buf[1] = ft->ttype; |
3137 | return rc; | 3209 | buf[2] = ft->tclass; |
3210 | buf[3] = otype->otype; | ||
3138 | 3211 | ||
3139 | buf[0] = ft->stype; | 3212 | rc = put_entry(buf, sizeof(u32), 4, fp); |
3140 | buf[1] = ft->ttype; | 3213 | if (rc) |
3141 | buf[2] = ft->tclass; | 3214 | return rc; |
3142 | buf[3] = ft->otype; | ||
3143 | 3215 | ||
3144 | rc = put_entry(buf, sizeof(u32), 4, fp); | ||
3145 | if (rc) | ||
3146 | return rc; | ||
3147 | } | ||
3148 | return 0; | 3216 | return 0; |
3149 | } | 3217 | } |
3218 | |||
3219 | static int filename_trans_write(struct policydb *p, void *fp) | ||
3220 | { | ||
3221 | u32 nel; | ||
3222 | __le32 buf[1]; | ||
3223 | int rc; | ||
3224 | |||
3225 | nel = 0; | ||
3226 | rc = hashtab_map(p->filename_trans, hashtab_cnt, &nel); | ||
3227 | if (rc) | ||
3228 | return rc; | ||
3229 | |||
3230 | buf[0] = cpu_to_le32(nel); | ||
3231 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
3232 | if (rc) | ||
3233 | return rc; | ||
3234 | |||
3235 | rc = hashtab_map(p->filename_trans, filename_write_helper, fp); | ||
3236 | if (rc) | ||
3237 | return rc; | ||
3238 | |||
3239 | return 0; | ||
3240 | } | ||
3241 | |||
3150 | /* | 3242 | /* |
3151 | * Write the configuration data in a policy database | 3243 | * Write the configuration data in a policy database |
3152 | * structure to a policy database binary representation | 3244 | * structure to a policy database binary representation |
@@ -3249,7 +3341,7 @@ int policydb_write(struct policydb *p, void *fp) | |||
3249 | if (rc) | 3341 | if (rc) |
3250 | return rc; | 3342 | return rc; |
3251 | 3343 | ||
3252 | rc = role_trans_write(p->role_tr, fp); | 3344 | rc = role_trans_write(p, fp); |
3253 | if (rc) | 3345 | if (rc) |
3254 | return rc; | 3346 | return rc; |
3255 | 3347 | ||