diff options
Diffstat (limited to 'security')
| -rw-r--r-- | security/selinux/ss/avtab.c | 91 | ||||
| -rw-r--r-- | security/selinux/ss/avtab.h | 16 | ||||
| -rw-r--r-- | security/selinux/ss/conditional.c | 4 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.c | 7 |
4 files changed, 82 insertions, 36 deletions
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 85705eb289..7551af1f78 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c | |||
| @@ -12,24 +12,25 @@ | |||
| 12 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
| 13 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
| 14 | * the Free Software Foundation, version 2. | 14 | * the Free Software Foundation, version 2. |
| 15 | * | ||
| 16 | * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp> | ||
| 17 | * Tuned number of hash slots for avtab to reduce memory usage | ||
| 15 | */ | 18 | */ |
| 16 | 19 | ||
| 17 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
| 18 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
| 19 | #include <linux/vmalloc.h> | ||
| 20 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
| 21 | |||
| 22 | #include "avtab.h" | 23 | #include "avtab.h" |
| 23 | #include "policydb.h" | 24 | #include "policydb.h" |
| 24 | 25 | ||
| 25 | #define AVTAB_HASH(keyp) \ | ||
| 26 | ((keyp->target_class + \ | ||
| 27 | (keyp->target_type << 2) + \ | ||
| 28 | (keyp->source_type << 9)) & \ | ||
| 29 | AVTAB_HASH_MASK) | ||
| 30 | |||
| 31 | static struct kmem_cache *avtab_node_cachep; | 26 | static struct kmem_cache *avtab_node_cachep; |
| 32 | 27 | ||
| 28 | static inline int avtab_hash(struct avtab_key *keyp, u16 mask) | ||
| 29 | { | ||
| 30 | return ((keyp->target_class + (keyp->target_type << 2) + | ||
| 31 | (keyp->source_type << 9)) & mask); | ||
| 32 | } | ||
| 33 | |||
| 33 | static struct avtab_node* | 34 | static struct avtab_node* |
| 34 | avtab_insert_node(struct avtab *h, int hvalue, | 35 | avtab_insert_node(struct avtab *h, int hvalue, |
| 35 | struct avtab_node * prev, struct avtab_node * cur, | 36 | struct avtab_node * prev, struct avtab_node * cur, |
| @@ -59,10 +60,10 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat | |||
| 59 | struct avtab_node *prev, *cur, *newnode; | 60 | struct avtab_node *prev, *cur, *newnode; |
| 60 | u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); | 61 | u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); |
| 61 | 62 | ||
| 62 | if (!h) | 63 | if (!h || !h->htable) |
| 63 | return -EINVAL; | 64 | return -EINVAL; |
| 64 | 65 | ||
| 65 | hvalue = AVTAB_HASH(key); | 66 | hvalue = avtab_hash(key, h->mask); |
| 66 | for (prev = NULL, cur = h->htable[hvalue]; | 67 | for (prev = NULL, cur = h->htable[hvalue]; |
| 67 | cur; | 68 | cur; |
| 68 | prev = cur, cur = cur->next) { | 69 | prev = cur, cur = cur->next) { |
| @@ -100,9 +101,9 @@ avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_da | |||
| 100 | struct avtab_node *prev, *cur, *newnode; | 101 | struct avtab_node *prev, *cur, *newnode; |
| 101 | u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); | 102 | u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); |
| 102 | 103 | ||
| 103 | if (!h) | 104 | if (!h || !h->htable) |
| 104 | return NULL; | 105 | return NULL; |
| 105 | hvalue = AVTAB_HASH(key); | 106 | hvalue = avtab_hash(key, h->mask); |
| 106 | for (prev = NULL, cur = h->htable[hvalue]; | 107 | for (prev = NULL, cur = h->htable[hvalue]; |
| 107 | cur; | 108 | cur; |
| 108 | prev = cur, cur = cur->next) { | 109 | prev = cur, cur = cur->next) { |
| @@ -132,10 +133,10 @@ struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key) | |||
| 132 | struct avtab_node *cur; | 133 | struct avtab_node *cur; |
| 133 | u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); | 134 | u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); |
| 134 | 135 | ||
| 135 | if (!h) | 136 | if (!h || !h->htable) |
| 136 | return NULL; | 137 | return NULL; |
| 137 | 138 | ||
| 138 | hvalue = AVTAB_HASH(key); | 139 | hvalue = avtab_hash(key, h->mask); |
| 139 | for (cur = h->htable[hvalue]; cur; cur = cur->next) { | 140 | for (cur = h->htable[hvalue]; cur; cur = cur->next) { |
| 140 | if (key->source_type == cur->key.source_type && | 141 | if (key->source_type == cur->key.source_type && |
| 141 | key->target_type == cur->key.target_type && | 142 | key->target_type == cur->key.target_type && |
| @@ -167,10 +168,10 @@ avtab_search_node(struct avtab *h, struct avtab_key *key) | |||
| 167 | struct avtab_node *cur; | 168 | struct avtab_node *cur; |
| 168 | u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); | 169 | u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); |
| 169 | 170 | ||
| 170 | if (!h) | 171 | if (!h || !h->htable) |
| 171 | return NULL; | 172 | return NULL; |
| 172 | 173 | ||
| 173 | hvalue = AVTAB_HASH(key); | 174 | hvalue = avtab_hash(key, h->mask); |
| 174 | for (cur = h->htable[hvalue]; cur; cur = cur->next) { | 175 | for (cur = h->htable[hvalue]; cur; cur = cur->next) { |
| 175 | if (key->source_type == cur->key.source_type && | 176 | if (key->source_type == cur->key.source_type && |
| 176 | key->target_type == cur->key.target_type && | 177 | key->target_type == cur->key.target_type && |
| @@ -228,7 +229,7 @@ void avtab_destroy(struct avtab *h) | |||
| 228 | if (!h || !h->htable) | 229 | if (!h || !h->htable) |
| 229 | return; | 230 | return; |
| 230 | 231 | ||
| 231 | for (i = 0; i < AVTAB_SIZE; i++) { | 232 | for (i = 0; i < h->nslot; i++) { |
| 232 | cur = h->htable[i]; | 233 | cur = h->htable[i]; |
| 233 | while (cur != NULL) { | 234 | while (cur != NULL) { |
| 234 | temp = cur; | 235 | temp = cur; |
| @@ -237,32 +238,63 @@ void avtab_destroy(struct avtab *h) | |||
| 237 | } | 238 | } |
| 238 | h->htable[i] = NULL; | 239 | h->htable[i] = NULL; |
| 239 | } | 240 | } |
| 240 | vfree(h->htable); | 241 | kfree(h->htable); |
| 241 | h->htable = NULL; | 242 | h->htable = NULL; |
| 243 | h->nslot = 0; | ||
| 244 | h->mask = 0; | ||
| 242 | } | 245 | } |
| 243 | 246 | ||
| 244 | |||
| 245 | int avtab_init(struct avtab *h) | 247 | int avtab_init(struct avtab *h) |
| 246 | { | 248 | { |
| 247 | int i; | 249 | h->htable = NULL; |
| 250 | h->nel = 0; | ||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | |||
| 254 | int avtab_alloc(struct avtab *h, u32 nrules) | ||
| 255 | { | ||
| 256 | u16 mask = 0; | ||
| 257 | u32 shift = 0; | ||
| 258 | u32 work = nrules; | ||
| 259 | u32 nslot = 0; | ||
| 260 | |||
| 261 | if (nrules == 0) | ||
| 262 | goto avtab_alloc_out; | ||
| 248 | 263 | ||
| 249 | h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE); | 264 | while (work) { |
| 265 | work = work >> 1; | ||
| 266 | shift++; | ||
| 267 | } | ||
| 268 | if (shift > 2) | ||
| 269 | shift = shift - 2; | ||
| 270 | nslot = 1 << shift; | ||
| 271 | if (nslot > MAX_AVTAB_SIZE) | ||
| 272 | nslot = MAX_AVTAB_SIZE; | ||
| 273 | mask = nslot - 1; | ||
| 274 | |||
| 275 | h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL); | ||
| 250 | if (!h->htable) | 276 | if (!h->htable) |
| 251 | return -ENOMEM; | 277 | return -ENOMEM; |
| 252 | for (i = 0; i < AVTAB_SIZE; i++) | 278 | |
| 253 | h->htable[i] = NULL; | 279 | avtab_alloc_out: |
| 254 | h->nel = 0; | 280 | h->nel = 0; |
| 281 | h->nslot = nslot; | ||
| 282 | h->mask = mask; | ||
| 283 | printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated." | ||
| 284 | "Num of rules:%d\n", h->nslot, nrules); | ||
| 255 | return 0; | 285 | return 0; |
| 256 | } | 286 | } |
| 257 | 287 | ||
| 258 | void avtab_hash_eval(struct avtab *h, char *tag) | 288 | void avtab_hash_eval(struct avtab *h, char *tag) |
| 259 | { | 289 | { |
| 260 | int i, chain_len, slots_used, max_chain_len; | 290 | int i, chain_len, slots_used, max_chain_len; |
| 291 | unsigned long long chain2_len_sum; | ||
| 261 | struct avtab_node *cur; | 292 | struct avtab_node *cur; |
| 262 | 293 | ||
| 263 | slots_used = 0; | 294 | slots_used = 0; |
| 264 | max_chain_len = 0; | 295 | max_chain_len = 0; |
| 265 | for (i = 0; i < AVTAB_SIZE; i++) { | 296 | chain2_len_sum = 0; |
| 297 | for (i = 0; i < h->nslot; i++) { | ||
| 266 | cur = h->htable[i]; | 298 | cur = h->htable[i]; |
| 267 | if (cur) { | 299 | if (cur) { |
| 268 | slots_used++; | 300 | slots_used++; |
| @@ -274,12 +306,14 @@ void avtab_hash_eval(struct avtab *h, char *tag) | |||
| 274 | 306 | ||
| 275 | if (chain_len > max_chain_len) | 307 | if (chain_len > max_chain_len) |
| 276 | max_chain_len = chain_len; | 308 | max_chain_len = chain_len; |
| 309 | chain2_len_sum += chain_len * chain_len; | ||
| 277 | } | 310 | } |
| 278 | } | 311 | } |
| 279 | 312 | ||
| 280 | printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest " | 313 | printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest " |
| 281 | "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE, | 314 | "chain length %d sum of chain length^2 %Lu\n", |
| 282 | max_chain_len); | 315 | tag, h->nel, slots_used, h->nslot, max_chain_len, |
| 316 | chain2_len_sum); | ||
| 283 | } | 317 | } |
| 284 | 318 | ||
| 285 | static uint16_t spec_order[] = { | 319 | static uint16_t spec_order[] = { |
| @@ -419,6 +453,11 @@ int avtab_read(struct avtab *a, void *fp, u32 vers) | |||
| 419 | rc = -EINVAL; | 453 | rc = -EINVAL; |
| 420 | goto bad; | 454 | goto bad; |
| 421 | } | 455 | } |
| 456 | |||
| 457 | rc = avtab_alloc(a, nel); | ||
| 458 | if (rc) | ||
| 459 | goto bad; | ||
| 460 | |||
| 422 | for (i = 0; i < nel; i++) { | 461 | for (i = 0; i < nel; i++) { |
| 423 | rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL); | 462 | rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL); |
| 424 | if (rc) { | 463 | if (rc) { |
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index 0a90d939af..d8edf8ca56 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h | |||
| @@ -16,6 +16,9 @@ | |||
| 16 | * This program is free software; you can redistribute it and/or modify | 16 | * This program is free software; you can redistribute it and/or modify |
| 17 | * it under the terms of the GNU General Public License as published by | 17 | * it under the terms of the GNU General Public License as published by |
| 18 | * the Free Software Foundation, version 2. | 18 | * the Free Software Foundation, version 2. |
| 19 | * | ||
| 20 | * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp> | ||
| 21 | * Tuned number of hash slots for avtab to reduce memory usage | ||
| 19 | */ | 22 | */ |
| 20 | #ifndef _SS_AVTAB_H_ | 23 | #ifndef _SS_AVTAB_H_ |
| 21 | #define _SS_AVTAB_H_ | 24 | #define _SS_AVTAB_H_ |
| @@ -50,9 +53,13 @@ struct avtab_node { | |||
| 50 | struct avtab { | 53 | struct avtab { |
| 51 | struct avtab_node **htable; | 54 | struct avtab_node **htable; |
| 52 | u32 nel; /* number of elements */ | 55 | u32 nel; /* number of elements */ |
| 56 | u32 nslot; /* number of hash slots */ | ||
| 57 | u16 mask; /* mask to compute hash func */ | ||
| 58 | |||
| 53 | }; | 59 | }; |
| 54 | 60 | ||
| 55 | int avtab_init(struct avtab *); | 61 | int avtab_init(struct avtab *); |
| 62 | int avtab_alloc(struct avtab *, u32); | ||
| 56 | struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k); | 63 | struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k); |
| 57 | void avtab_destroy(struct avtab *h); | 64 | void avtab_destroy(struct avtab *h); |
| 58 | void avtab_hash_eval(struct avtab *h, char *tag); | 65 | void avtab_hash_eval(struct avtab *h, char *tag); |
| @@ -74,11 +81,10 @@ struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified | |||
| 74 | void avtab_cache_init(void); | 81 | void avtab_cache_init(void); |
| 75 | void avtab_cache_destroy(void); | 82 | void avtab_cache_destroy(void); |
| 76 | 83 | ||
| 77 | #define AVTAB_HASH_BITS 15 | 84 | #define MAX_AVTAB_HASH_BITS 13 |
| 78 | #define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS) | 85 | #define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) |
| 79 | #define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1) | 86 | #define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) |
| 80 | 87 | #define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS | |
| 81 | #define AVTAB_SIZE AVTAB_HASH_BUCKETS | ||
| 82 | 88 | ||
| 83 | #endif /* _SS_AVTAB_H_ */ | 89 | #endif /* _SS_AVTAB_H_ */ |
| 84 | 90 | ||
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index d2737edba5..45b93a827c 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c | |||
| @@ -456,6 +456,10 @@ int cond_read_list(struct policydb *p, void *fp) | |||
| 456 | 456 | ||
| 457 | len = le32_to_cpu(buf[0]); | 457 | len = le32_to_cpu(buf[0]); |
| 458 | 458 | ||
| 459 | rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel); | ||
| 460 | if (rc) | ||
| 461 | goto err; | ||
| 462 | |||
| 459 | for (i = 0; i < len; i++) { | 463 | for (i = 0; i < len; i++) { |
| 460 | node = kzalloc(sizeof(struct cond_node), GFP_KERNEL); | 464 | node = kzalloc(sizeof(struct cond_node), GFP_KERNEL); |
| 461 | if (!node) | 465 | if (!node) |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index f05f97a2bc..5ecbad7d8b 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
| @@ -177,18 +177,15 @@ static int policydb_init(struct policydb *p) | |||
| 177 | 177 | ||
| 178 | rc = roles_init(p); | 178 | rc = roles_init(p); |
| 179 | if (rc) | 179 | if (rc) |
| 180 | goto out_free_avtab; | 180 | goto out_free_symtab; |
| 181 | 181 | ||
| 182 | rc = cond_policydb_init(p); | 182 | rc = cond_policydb_init(p); |
| 183 | if (rc) | 183 | if (rc) |
| 184 | goto out_free_avtab; | 184 | goto out_free_symtab; |
| 185 | 185 | ||
| 186 | out: | 186 | out: |
| 187 | return rc; | 187 | return rc; |
| 188 | 188 | ||
| 189 | out_free_avtab: | ||
| 190 | avtab_destroy(&p->te_avtab); | ||
| 191 | |||
| 192 | out_free_symtab: | 189 | out_free_symtab: |
| 193 | for (i = 0; i < SYM_NUM; i++) | 190 | for (i = 0; i < SYM_NUM; i++) |
| 194 | hashtab_destroy(p->symtab[i].table); | 191 | hashtab_destroy(p->symtab[i].table); |
