diff options
| author | Eric Paris <eparis@redhat.com> | 2010-07-29 23:02:34 -0400 |
|---|---|---|
| committer | James Morris <jmorris@namei.org> | 2010-08-02 01:38:39 -0400 |
| commit | 6371dcd36f649d9d07823f31400618155a20dde1 (patch) | |
| tree | a08c4ed2ec77225abbfcc099e78ae8d643429787 | |
| parent | 016d825fe02cd20fd8803ca37a1e6d428fe878f6 (diff) | |
selinux: convert the policy type_attr_map to flex_array
Current selinux policy can have over 3000 types. The type_attr_map in
policy is an array sized by the number of types times sizeof(struct ebitmap)
(12 on x86_64). Basic math tells us the array is going to be of length
3000 x 12 = 36,000 bytes. The largest 'safe' allocation on a long running
system is 16k. Most of the time a 32k allocation will work. But on long
running systems a 64k allocation (what we need) can fail quite regularly.
In order to deal with this I am converting the type_attr_map to use
flex_arrays. Let the library code deal with breaking this into PAGE_SIZE
pieces.
-v2
rework some of the if(!obj) BUG() to be BUG_ON(!obj)
drop flex_array_put() calls and just use a _get() object directly
-v3
make apply to James' tree (drop the policydb_write changes)
Signed-off-by: Eric Paris <eparis@redhat.com>
Acked-by: Stephen D. Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
| -rw-r--r-- | security/selinux/ss/policydb.c | 41 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.h | 4 | ||||
| -rw-r--r-- | security/selinux/ss/services.c | 7 |
3 files changed, 39 insertions, 13 deletions
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 674ddfe0ba03..3a29704be8ce 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <linux/string.h> | 31 | #include <linux/string.h> |
| 32 | #include <linux/errno.h> | 32 | #include <linux/errno.h> |
| 33 | #include <linux/audit.h> | 33 | #include <linux/audit.h> |
| 34 | #include <linux/flex_array.h> | ||
| 34 | #include "security.h" | 35 | #include "security.h" |
| 35 | 36 | ||
| 36 | #include "policydb.h" | 37 | #include "policydb.h" |
| @@ -739,11 +740,17 @@ void policydb_destroy(struct policydb *p) | |||
| 739 | hashtab_map(p->range_tr, range_tr_destroy, NULL); | 740 | hashtab_map(p->range_tr, range_tr_destroy, NULL); |
| 740 | hashtab_destroy(p->range_tr); | 741 | hashtab_destroy(p->range_tr); |
| 741 | 742 | ||
| 742 | if (p->type_attr_map) { | 743 | if (p->type_attr_map_array) { |
| 743 | for (i = 0; i < p->p_types.nprim; i++) | 744 | for (i = 0; i < p->p_types.nprim; i++) { |
| 744 | ebitmap_destroy(&p->type_attr_map[i]); | 745 | struct ebitmap *e; |
| 746 | |||
| 747 | e = flex_array_get(p->type_attr_map_array, i); | ||
| 748 | if (!e) | ||
| 749 | continue; | ||
| 750 | ebitmap_destroy(e); | ||
| 751 | } | ||
| 752 | flex_array_free(p->type_attr_map_array); | ||
| 745 | } | 753 | } |
| 746 | kfree(p->type_attr_map); | ||
| 747 | ebitmap_destroy(&p->policycaps); | 754 | ebitmap_destroy(&p->policycaps); |
| 748 | ebitmap_destroy(&p->permissive_map); | 755 | ebitmap_destroy(&p->permissive_map); |
| 749 | 756 | ||
| @@ -2257,19 +2264,33 @@ int policydb_read(struct policydb *p, void *fp) | |||
| 2257 | if (rc) | 2264 | if (rc) |
| 2258 | goto bad; | 2265 | goto bad; |
| 2259 | 2266 | ||
| 2260 | p->type_attr_map = kmalloc(p->p_types.nprim * sizeof(struct ebitmap), GFP_KERNEL); | 2267 | rc = -ENOMEM; |
| 2261 | if (!p->type_attr_map) | 2268 | p->type_attr_map_array = flex_array_alloc(sizeof(struct ebitmap), |
| 2269 | p->p_types.nprim, | ||
| 2270 | GFP_KERNEL | __GFP_ZERO); | ||
| 2271 | if (!p->type_attr_map_array) | ||
| 2272 | goto bad; | ||
| 2273 | |||
| 2274 | /* preallocate so we don't have to worry about the put ever failing */ | ||
| 2275 | rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim - 1, | ||
| 2276 | GFP_KERNEL | __GFP_ZERO); | ||
| 2277 | if (rc) | ||
| 2262 | goto bad; | 2278 | goto bad; |
| 2263 | 2279 | ||
| 2264 | for (i = 0; i < p->p_types.nprim; i++) { | 2280 | for (i = 0; i < p->p_types.nprim; i++) { |
| 2265 | ebitmap_init(&p->type_attr_map[i]); | 2281 | struct ebitmap *e = flex_array_get(p->type_attr_map_array, i); |
| 2282 | |||
| 2283 | BUG_ON(!e); | ||
| 2284 | ebitmap_init(e); | ||
| 2266 | if (p->policyvers >= POLICYDB_VERSION_AVTAB) { | 2285 | if (p->policyvers >= POLICYDB_VERSION_AVTAB) { |
| 2267 | if (ebitmap_read(&p->type_attr_map[i], fp)) | 2286 | rc = ebitmap_read(e, fp); |
| 2287 | if (rc) | ||
| 2268 | goto bad; | 2288 | goto bad; |
| 2269 | } | 2289 | } |
| 2270 | /* add the type itself as the degenerate case */ | 2290 | /* add the type itself as the degenerate case */ |
| 2271 | if (ebitmap_set_bit(&p->type_attr_map[i], i, 1)) | 2291 | rc = ebitmap_set_bit(e, i, 1); |
| 2272 | goto bad; | 2292 | if (rc) |
| 2293 | goto bad; | ||
| 2273 | } | 2294 | } |
| 2274 | 2295 | ||
| 2275 | rc = policydb_bounds_sanity_check(p); | 2296 | rc = policydb_bounds_sanity_check(p); |
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 26d9adf8542b..310e94442cb8 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
| @@ -24,6 +24,8 @@ | |||
| 24 | #ifndef _SS_POLICYDB_H_ | 24 | #ifndef _SS_POLICYDB_H_ |
| 25 | #define _SS_POLICYDB_H_ | 25 | #define _SS_POLICYDB_H_ |
| 26 | 26 | ||
| 27 | #include <linux/flex_array.h> | ||
| 28 | |||
| 27 | #include "symtab.h" | 29 | #include "symtab.h" |
| 28 | #include "avtab.h" | 30 | #include "avtab.h" |
| 29 | #include "sidtab.h" | 31 | #include "sidtab.h" |
| @@ -246,7 +248,7 @@ struct policydb { | |||
| 246 | struct hashtab *range_tr; | 248 | struct hashtab *range_tr; |
| 247 | 249 | ||
| 248 | /* type -> attribute reverse mapping */ | 250 | /* type -> attribute reverse mapping */ |
| 249 | struct ebitmap *type_attr_map; | 251 | struct flex_array *type_attr_map_array; |
| 250 | 252 | ||
| 251 | struct ebitmap policycaps; | 253 | struct ebitmap policycaps; |
| 252 | 254 | ||
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 1de60ce90d9a..9ea2feca3cd4 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | #include <linux/audit.h> | 50 | #include <linux/audit.h> |
| 51 | #include <linux/mutex.h> | 51 | #include <linux/mutex.h> |
| 52 | #include <linux/selinux.h> | 52 | #include <linux/selinux.h> |
| 53 | #include <linux/flex_array.h> | ||
| 53 | #include <net/netlabel.h> | 54 | #include <net/netlabel.h> |
| 54 | 55 | ||
| 55 | #include "flask.h" | 56 | #include "flask.h" |
| @@ -626,8 +627,10 @@ static void context_struct_compute_av(struct context *scontext, | |||
| 626 | */ | 627 | */ |
| 627 | avkey.target_class = tclass; | 628 | avkey.target_class = tclass; |
| 628 | avkey.specified = AVTAB_AV; | 629 | avkey.specified = AVTAB_AV; |
| 629 | sattr = &policydb.type_attr_map[scontext->type - 1]; | 630 | sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); |
| 630 | tattr = &policydb.type_attr_map[tcontext->type - 1]; | 631 | BUG_ON(!sattr); |
| 632 | tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1); | ||
| 633 | BUG_ON(!tattr); | ||
| 631 | ebitmap_for_each_positive_bit(sattr, snode, i) { | 634 | ebitmap_for_each_positive_bit(sattr, snode, i) { |
| 632 | ebitmap_for_each_positive_bit(tattr, tnode, j) { | 635 | ebitmap_for_each_positive_bit(tattr, tnode, j) { |
| 633 | avkey.source_type = i + 1; | 636 | avkey.source_type = i + 1; |
