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 | |
| 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')
| -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, |
