diff options
author | Eric Paris <eparis@redhat.com> | 2011-04-28 15:11:21 -0400 |
---|---|---|
committer | Eric Paris <eparis@redhat.com> | 2011-04-28 15:15:53 -0400 |
commit | 2463c26d50adc282d19317013ba0ff473823ca47 (patch) | |
tree | e92438150bb380c0dc0867b00f1ae89f73646b2a /security/selinux/ss | |
parent | 3f058ef7787e1b48720622346de9a5317aeb749a (diff) |
SELinux: put name based create rules in a hashtable
To shorten the list we need to run if filename trans rules exist for the type
of the given parent directory I put them in a hashtable. Given the policy we
are expecting to use in Fedora this takes the worst case list run from about
5,000 entries to 17.
Signed-off-by: Eric Paris <eparis@redhat.com>
Reviewed-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/selinux/ss')
-rw-r--r-- | security/selinux/ss/policydb.c | 167 | ||||
-rw-r--r-- | security/selinux/ss/policydb.h | 9 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 20 |
3 files changed, 135 insertions, 61 deletions
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index ca7a7231b5a2..549120c56edd 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -184,6 +184,43 @@ out: | |||
184 | return rc; | 184 | return rc; |
185 | } | 185 | } |
186 | 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 | |||
187 | static u32 rangetr_hash(struct hashtab *h, const void *k) | 224 | static u32 rangetr_hash(struct hashtab *h, const void *k) |
188 | { | 225 | { |
189 | const struct range_trans *key = k; | 226 | const struct range_trans *key = k; |
@@ -236,6 +273,10 @@ static int policydb_init(struct policydb *p) | |||
236 | if (rc) | 273 | if (rc) |
237 | goto out; | 274 | goto out; |
238 | 275 | ||
276 | p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10)); | ||
277 | if (!p->filename_trans) | ||
278 | goto out; | ||
279 | |||
239 | p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); | 280 | p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); |
240 | if (!p->range_tr) | 281 | if (!p->range_tr) |
241 | goto out; | 282 | goto out; |
@@ -246,6 +287,8 @@ static int policydb_init(struct policydb *p) | |||
246 | 287 | ||
247 | return 0; | 288 | return 0; |
248 | out: | 289 | out: |
290 | hashtab_destroy(p->filename_trans); | ||
291 | hashtab_destroy(p->range_tr); | ||
249 | for (i = 0; i < SYM_NUM; i++) | 292 | for (i = 0; i < SYM_NUM; i++) |
250 | hashtab_destroy(p->symtab[i].table); | 293 | hashtab_destroy(p->symtab[i].table); |
251 | return rc; | 294 | return rc; |
@@ -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,6 @@ 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; | ||
792 | while (ft) { | ||
793 | nft = ft->next; | ||
794 | kfree(ft->name); | ||
795 | kfree(ft); | ||
796 | ft = nft; | ||
797 | } | ||
798 | |||
799 | ebitmap_destroy(&p->filename_trans_ttypes); | 846 | ebitmap_destroy(&p->filename_trans_ttypes); |
800 | ebitmap_destroy(&p->policycaps); | 847 | ebitmap_destroy(&p->policycaps); |
801 | ebitmap_destroy(&p->permissive_map); | 848 | ebitmap_destroy(&p->permissive_map); |
@@ -1806,9 +1853,10 @@ out: | |||
1806 | 1853 | ||
1807 | static int filename_trans_read(struct policydb *p, void *fp) | 1854 | static int filename_trans_read(struct policydb *p, void *fp) |
1808 | { | 1855 | { |
1809 | struct filename_trans *ft, *last; | 1856 | struct filename_trans *ft; |
1810 | u32 nel, len; | 1857 | struct filename_trans_datum *otype; |
1811 | char *name; | 1858 | char *name; |
1859 | u32 nel, len; | ||
1812 | __le32 buf[4]; | 1860 | __le32 buf[4]; |
1813 | int rc, i; | 1861 | int rc, i; |
1814 | 1862 | ||
@@ -1817,25 +1865,23 @@ static int filename_trans_read(struct policydb *p, void *fp) | |||
1817 | 1865 | ||
1818 | rc = next_entry(buf, fp, sizeof(u32)); | 1866 | rc = next_entry(buf, fp, sizeof(u32)); |
1819 | if (rc) | 1867 | if (rc) |
1820 | goto out; | 1868 | return rc; |
1821 | nel = le32_to_cpu(buf[0]); | 1869 | nel = le32_to_cpu(buf[0]); |
1822 | 1870 | ||
1823 | last = p->filename_trans; | ||
1824 | while (last && last->next) | ||
1825 | last = last->next; | ||
1826 | |||
1827 | for (i = 0; i < nel; i++) { | 1871 | for (i = 0; i < nel; i++) { |
1872 | ft = NULL; | ||
1873 | otype = NULL; | ||
1874 | name = NULL; | ||
1875 | |||
1828 | rc = -ENOMEM; | 1876 | rc = -ENOMEM; |
1829 | ft = kzalloc(sizeof(*ft), GFP_KERNEL); | 1877 | ft = kzalloc(sizeof(*ft), GFP_KERNEL); |
1830 | if (!ft) | 1878 | if (!ft) |
1831 | goto out; | 1879 | goto out; |
1832 | 1880 | ||
1833 | /* add it to the tail of the list */ | 1881 | rc = -ENOMEM; |
1834 | if (!last) | 1882 | otype = kmalloc(sizeof(*otype), GFP_KERNEL); |
1835 | p->filename_trans = ft; | 1883 | if (!otype) |
1836 | else | 1884 | goto out; |
1837 | last->next = ft; | ||
1838 | last = ft; | ||
1839 | 1885 | ||
1840 | /* length of the path component string */ | 1886 | /* length of the path component string */ |
1841 | rc = next_entry(buf, fp, sizeof(u32)); | 1887 | rc = next_entry(buf, fp, sizeof(u32)); |
@@ -1863,14 +1909,22 @@ static int filename_trans_read(struct policydb *p, void *fp) | |||
1863 | ft->stype = le32_to_cpu(buf[0]); | 1909 | ft->stype = le32_to_cpu(buf[0]); |
1864 | ft->ttype = le32_to_cpu(buf[1]); | 1910 | ft->ttype = le32_to_cpu(buf[1]); |
1865 | ft->tclass = le32_to_cpu(buf[2]); | 1911 | ft->tclass = le32_to_cpu(buf[2]); |
1866 | ft->otype = le32_to_cpu(buf[3]); | 1912 | |
1913 | otype->otype = le32_to_cpu(buf[3]); | ||
1867 | 1914 | ||
1868 | rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1); | 1915 | rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1); |
1869 | if (rc) | 1916 | if (rc) |
1870 | goto out; | 1917 | goto out; |
1918 | |||
1919 | hashtab_insert(p->filename_trans, ft, otype); | ||
1871 | } | 1920 | } |
1872 | rc = 0; | 1921 | hash_eval(p->filename_trans, "filenametr"); |
1922 | return 0; | ||
1873 | out: | 1923 | out: |
1924 | kfree(ft); | ||
1925 | kfree(name); | ||
1926 | kfree(otype); | ||
1927 | |||
1874 | return rc; | 1928 | return rc; |
1875 | } | 1929 | } |
1876 | 1930 | ||
@@ -3131,43 +3185,60 @@ static int range_write(struct policydb *p, void *fp) | |||
3131 | return 0; | 3185 | return 0; |
3132 | } | 3186 | } |
3133 | 3187 | ||
3134 | static int filename_trans_write(struct policydb *p, void *fp) | 3188 | static int filename_write_helper(void *key, void *data, void *ptr) |
3135 | { | 3189 | { |
3136 | struct filename_trans *ft; | ||
3137 | u32 len, nel = 0; | ||
3138 | __le32 buf[4]; | 3190 | __le32 buf[4]; |
3191 | struct filename_trans *ft = key; | ||
3192 | struct filename_trans_datum *otype = data; | ||
3193 | void *fp = ptr; | ||
3139 | int rc; | 3194 | int rc; |
3195 | u32 len; | ||
3140 | 3196 | ||
3141 | for (ft = p->filename_trans; ft; ft = ft->next) | 3197 | len = strlen(ft->name); |
3142 | nel++; | 3198 | buf[0] = cpu_to_le32(len); |
3143 | |||
3144 | buf[0] = cpu_to_le32(nel); | ||
3145 | rc = put_entry(buf, sizeof(u32), 1, fp); | 3199 | rc = put_entry(buf, sizeof(u32), 1, fp); |
3146 | if (rc) | 3200 | if (rc) |
3147 | return rc; | 3201 | return rc; |
3148 | 3202 | ||
3149 | for (ft = p->filename_trans; ft; ft = ft->next) { | 3203 | rc = put_entry(ft->name, sizeof(char), len, fp); |
3150 | len = strlen(ft->name); | 3204 | if (rc) |
3151 | buf[0] = cpu_to_le32(len); | 3205 | return rc; |
3152 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
3153 | if (rc) | ||
3154 | return rc; | ||
3155 | 3206 | ||
3156 | rc = put_entry(ft->name, sizeof(char), len, fp); | 3207 | buf[0] = ft->stype; |
3157 | if (rc) | 3208 | buf[1] = ft->ttype; |
3158 | return rc; | 3209 | buf[2] = ft->tclass; |
3210 | buf[3] = otype->otype; | ||
3159 | 3211 | ||
3160 | buf[0] = ft->stype; | 3212 | rc = put_entry(buf, sizeof(u32), 4, fp); |
3161 | buf[1] = ft->ttype; | 3213 | if (rc) |
3162 | buf[2] = ft->tclass; | 3214 | return rc; |
3163 | buf[3] = ft->otype; | ||
3164 | 3215 | ||
3165 | rc = put_entry(buf, sizeof(u32), 4, fp); | ||
3166 | if (rc) | ||
3167 | return rc; | ||
3168 | } | ||
3169 | return 0; | 3216 | return 0; |
3170 | } | 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 | |||
3171 | /* | 3242 | /* |
3172 | * Write the configuration data in a policy database | 3243 | * Write the configuration data in a policy database |
3173 | * structure to a policy database binary representation | 3244 | * structure to a policy database binary representation |
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index f054a9d4d114..b846c0387180 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
@@ -79,11 +79,13 @@ struct role_trans { | |||
79 | }; | 79 | }; |
80 | 80 | ||
81 | struct filename_trans { | 81 | struct filename_trans { |
82 | struct filename_trans *next; | ||
83 | u32 stype; /* current process */ | 82 | u32 stype; /* current process */ |
84 | u32 ttype; /* parent dir context */ | 83 | u32 ttype; /* parent dir context */ |
85 | u16 tclass; /* class of new object */ | 84 | u16 tclass; /* class of new object */ |
86 | const char *name; /* last path component */ | 85 | const char *name; /* last path component */ |
86 | }; | ||
87 | |||
88 | struct filename_trans_datum { | ||
87 | u32 otype; /* expected of new object */ | 89 | u32 otype; /* expected of new object */ |
88 | }; | 90 | }; |
89 | 91 | ||
@@ -227,10 +229,11 @@ struct policydb { | |||
227 | /* role transitions */ | 229 | /* role transitions */ |
228 | struct role_trans *role_tr; | 230 | struct role_trans *role_tr; |
229 | 231 | ||
232 | /* file transitions with the last path component */ | ||
230 | /* quickly exclude lookups when parent ttype has no rules */ | 233 | /* quickly exclude lookups when parent ttype has no rules */ |
231 | struct ebitmap filename_trans_ttypes; | 234 | struct ebitmap filename_trans_ttypes; |
232 | /* file transitions with the last path component */ | 235 | /* actual set of filename_trans rules */ |
233 | struct filename_trans *filename_trans; | 236 | struct hashtab *filename_trans; |
234 | 237 | ||
235 | /* bools indexed by (value - 1) */ | 238 | /* bools indexed by (value - 1) */ |
236 | struct cond_bool_datum **bool_val_to_struct; | 239 | struct cond_bool_datum **bool_val_to_struct; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 6a22eaebf3b7..e11b4b038f4a 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -1362,7 +1362,8 @@ static void filename_compute_type(struct policydb *p, struct context *newcontext | |||
1362 | u32 stype, u32 ttype, u16 tclass, | 1362 | u32 stype, u32 ttype, u16 tclass, |
1363 | const char *objname) | 1363 | const char *objname) |
1364 | { | 1364 | { |
1365 | struct filename_trans *ft; | 1365 | struct filename_trans ft; |
1366 | struct filename_trans_datum *otype; | ||
1366 | 1367 | ||
1367 | /* | 1368 | /* |
1368 | * Most filename trans rules are going to live in specific directories | 1369 | * Most filename trans rules are going to live in specific directories |
@@ -1372,15 +1373,14 @@ static void filename_compute_type(struct policydb *p, struct context *newcontext | |||
1372 | if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype)) | 1373 | if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype)) |
1373 | return; | 1374 | return; |
1374 | 1375 | ||
1375 | for (ft = p->filename_trans; ft; ft = ft->next) { | 1376 | ft.stype = stype; |
1376 | if (ft->stype == stype && | 1377 | ft.ttype = ttype; |
1377 | ft->ttype == ttype && | 1378 | ft.tclass = tclass; |
1378 | ft->tclass == tclass && | 1379 | ft.name = objname; |
1379 | !strcmp(ft->name, objname)) { | 1380 | |
1380 | newcontext->type = ft->otype; | 1381 | otype = hashtab_search(p->filename_trans, &ft); |
1381 | return; | 1382 | if (otype) |
1382 | } | 1383 | newcontext->type = otype->otype; |
1383 | } | ||
1384 | } | 1384 | } |
1385 | 1385 | ||
1386 | static int security_compute_sid(u32 ssid, | 1386 | static int security_compute_sid(u32 ssid, |