diff options
author | Stephen Smalley <sds@tycho.nsa.gov> | 2005-09-03 18:55:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@evo.osdl.org> | 2005-09-05 03:05:50 -0400 |
commit | 782ebb992ec20b5afdd5786ee8c2f1b58b631f24 (patch) | |
tree | adf0af44fa591d803ec6b9ab7541ff3e5745dd93 /security/selinux/ss/conditional.c | |
parent | 720d6c29e146e96cca858057469951e91e0e6850 (diff) |
[PATCH] selinux: Reduce memory use by avtab
This patch improves memory use by SELinux by both reducing the avtab node
size and reducing the number of avtab nodes. The memory savings are
substantial, e.g. on a 64-bit system after boot, James Morris reported the
following data for the targeted and strict policies:
#objs objsize kernmem
Targeted:
Before: 237888 40 9.1MB
After: 19968 24 468KB
Strict:
Before: 571680 40 21.81MB
After: 221052 24 5.06MB
The improvement in memory use comes at a cost in the speed of security
server computations of access vectors, but these computations are only
required on AVC cache misses, and performance measurements by James Morris
using a number of benchmarks have shown that the change does not cause any
significant degradation.
Note that a rebuilt policy via an updated policy toolchain
(libsepol/checkpolicy) is required in order to gain the full benefits of
this patch, although some memory savings benefits are immediately applied
even to older policies (in particular, the reduction in avtab node size).
Sources for the updated toolchain are presently available from the
sourceforge CVS tree (http://sourceforge.net/cvs/?group_id=21266), and
tarballs are available from http://www.flux.utah.edu/~sds.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'security/selinux/ss/conditional.c')
-rw-r--r-- | security/selinux/ss/conditional.c | 205 |
1 files changed, 114 insertions, 91 deletions
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index e2057f5a411a..b81cd6688978 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c | |||
@@ -100,18 +100,18 @@ int evaluate_cond_node(struct policydb *p, struct cond_node *node) | |||
100 | /* turn the rules on or off */ | 100 | /* turn the rules on or off */ |
101 | for (cur = node->true_list; cur != NULL; cur = cur->next) { | 101 | for (cur = node->true_list; cur != NULL; cur = cur->next) { |
102 | if (new_state <= 0) { | 102 | if (new_state <= 0) { |
103 | cur->node->datum.specified &= ~AVTAB_ENABLED; | 103 | cur->node->key.specified &= ~AVTAB_ENABLED; |
104 | } else { | 104 | } else { |
105 | cur->node->datum.specified |= AVTAB_ENABLED; | 105 | cur->node->key.specified |= AVTAB_ENABLED; |
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | for (cur = node->false_list; cur != NULL; cur = cur->next) { | 109 | for (cur = node->false_list; cur != NULL; cur = cur->next) { |
110 | /* -1 or 1 */ | 110 | /* -1 or 1 */ |
111 | if (new_state) { | 111 | if (new_state) { |
112 | cur->node->datum.specified &= ~AVTAB_ENABLED; | 112 | cur->node->key.specified &= ~AVTAB_ENABLED; |
113 | } else { | 113 | } else { |
114 | cur->node->datum.specified |= AVTAB_ENABLED; | 114 | cur->node->key.specified |= AVTAB_ENABLED; |
115 | } | 115 | } |
116 | } | 116 | } |
117 | } | 117 | } |
@@ -252,104 +252,126 @@ err: | |||
252 | return -1; | 252 | return -1; |
253 | } | 253 | } |
254 | 254 | ||
255 | static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, | 255 | struct cond_insertf_data |
256 | struct cond_av_list *other) | ||
257 | { | 256 | { |
258 | struct cond_av_list *list, *last = NULL, *cur; | 257 | struct policydb *p; |
259 | struct avtab_key key; | 258 | struct cond_av_list *other; |
260 | struct avtab_datum datum; | 259 | struct cond_av_list *head; |
260 | struct cond_av_list *tail; | ||
261 | }; | ||
262 | |||
263 | static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr) | ||
264 | { | ||
265 | struct cond_insertf_data *data = ptr; | ||
266 | struct policydb *p = data->p; | ||
267 | struct cond_av_list *other = data->other, *list, *cur; | ||
261 | struct avtab_node *node_ptr; | 268 | struct avtab_node *node_ptr; |
262 | int rc; | ||
263 | u32 buf[1], i, len; | ||
264 | u8 found; | 269 | u8 found; |
265 | 270 | ||
266 | *ret_list = NULL; | ||
267 | |||
268 | len = 0; | ||
269 | rc = next_entry(buf, fp, sizeof buf); | ||
270 | if (rc < 0) | ||
271 | return -1; | ||
272 | |||
273 | len = le32_to_cpu(buf[0]); | ||
274 | if (len == 0) { | ||
275 | return 0; | ||
276 | } | ||
277 | 271 | ||
278 | for (i = 0; i < len; i++) { | 272 | /* |
279 | if (avtab_read_item(fp, &datum, &key)) | 273 | * For type rules we have to make certain there aren't any |
274 | * conflicting rules by searching the te_avtab and the | ||
275 | * cond_te_avtab. | ||
276 | */ | ||
277 | if (k->specified & AVTAB_TYPE) { | ||
278 | if (avtab_search(&p->te_avtab, k)) { | ||
279 | printk("security: type rule already exists outside of a conditional."); | ||
280 | goto err; | 280 | goto err; |
281 | 281 | } | |
282 | /* | 282 | /* |
283 | * For type rules we have to make certain there aren't any | 283 | * If we are reading the false list other will be a pointer to |
284 | * conflicting rules by searching the te_avtab and the | 284 | * the true list. We can have duplicate entries if there is only |
285 | * cond_te_avtab. | 285 | * 1 other entry and it is in our true list. |
286 | * | ||
287 | * If we are reading the true list (other == NULL) there shouldn't | ||
288 | * be any other entries. | ||
286 | */ | 289 | */ |
287 | if (datum.specified & AVTAB_TYPE) { | 290 | if (other) { |
288 | if (avtab_search(&p->te_avtab, &key, AVTAB_TYPE)) { | 291 | node_ptr = avtab_search_node(&p->te_cond_avtab, k); |
289 | printk("security: type rule already exists outside of a conditional."); | 292 | if (node_ptr) { |
290 | goto err; | 293 | if (avtab_search_node_next(node_ptr, k->specified)) { |
291 | } | 294 | printk("security: too many conflicting type rules."); |
292 | /* | 295 | goto err; |
293 | * If we are reading the false list other will be a pointer to | 296 | } |
294 | * the true list. We can have duplicate entries if there is only | 297 | found = 0; |
295 | * 1 other entry and it is in our true list. | 298 | for (cur = other; cur != NULL; cur = cur->next) { |
296 | * | 299 | if (cur->node == node_ptr) { |
297 | * If we are reading the true list (other == NULL) there shouldn't | 300 | found = 1; |
298 | * be any other entries. | 301 | break; |
299 | */ | ||
300 | if (other) { | ||
301 | node_ptr = avtab_search_node(&p->te_cond_avtab, &key, AVTAB_TYPE); | ||
302 | if (node_ptr) { | ||
303 | if (avtab_search_node_next(node_ptr, AVTAB_TYPE)) { | ||
304 | printk("security: too many conflicting type rules."); | ||
305 | goto err; | ||
306 | } | ||
307 | found = 0; | ||
308 | for (cur = other; cur != NULL; cur = cur->next) { | ||
309 | if (cur->node == node_ptr) { | ||
310 | found = 1; | ||
311 | break; | ||
312 | } | ||
313 | } | ||
314 | if (!found) { | ||
315 | printk("security: conflicting type rules."); | ||
316 | goto err; | ||
317 | } | 302 | } |
318 | } | 303 | } |
319 | } else { | 304 | if (!found) { |
320 | if (avtab_search(&p->te_cond_avtab, &key, AVTAB_TYPE)) { | 305 | printk("security: conflicting type rules.\n"); |
321 | printk("security: conflicting type rules when adding type rule for true."); | ||
322 | goto err; | 306 | goto err; |
323 | } | 307 | } |
324 | } | 308 | } |
309 | } else { | ||
310 | if (avtab_search(&p->te_cond_avtab, k)) { | ||
311 | printk("security: conflicting type rules when adding type rule for true.\n"); | ||
312 | goto err; | ||
313 | } | ||
325 | } | 314 | } |
326 | node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, &key, &datum); | 315 | } |
327 | if (!node_ptr) { | ||
328 | printk("security: could not insert rule."); | ||
329 | goto err; | ||
330 | } | ||
331 | |||
332 | list = kmalloc(sizeof(struct cond_av_list), GFP_KERNEL); | ||
333 | if (!list) | ||
334 | goto err; | ||
335 | memset(list, 0, sizeof(struct cond_av_list)); | ||
336 | |||
337 | list->node = node_ptr; | ||
338 | if (i == 0) | ||
339 | *ret_list = list; | ||
340 | else | ||
341 | last->next = list; | ||
342 | last = list; | ||
343 | 316 | ||
317 | node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d); | ||
318 | if (!node_ptr) { | ||
319 | printk("security: could not insert rule."); | ||
320 | goto err; | ||
344 | } | 321 | } |
345 | 322 | ||
323 | list = kmalloc(sizeof(struct cond_av_list), GFP_KERNEL); | ||
324 | if (!list) | ||
325 | goto err; | ||
326 | memset(list, 0, sizeof(*list)); | ||
327 | |||
328 | list->node = node_ptr; | ||
329 | if (!data->head) | ||
330 | data->head = list; | ||
331 | else | ||
332 | data->tail->next = list; | ||
333 | data->tail = list; | ||
346 | return 0; | 334 | return 0; |
335 | |||
347 | err: | 336 | err: |
348 | cond_av_list_destroy(*ret_list); | 337 | cond_av_list_destroy(data->head); |
349 | *ret_list = NULL; | 338 | data->head = NULL; |
350 | return -1; | 339 | return -1; |
351 | } | 340 | } |
352 | 341 | ||
342 | static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other) | ||
343 | { | ||
344 | int i, rc; | ||
345 | u32 buf[1], len; | ||
346 | struct cond_insertf_data data; | ||
347 | |||
348 | *ret_list = NULL; | ||
349 | |||
350 | len = 0; | ||
351 | rc = next_entry(buf, fp, sizeof(u32)); | ||
352 | if (rc < 0) | ||
353 | return -1; | ||
354 | |||
355 | len = le32_to_cpu(buf[0]); | ||
356 | if (len == 0) { | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | data.p = p; | ||
361 | data.other = other; | ||
362 | data.head = NULL; | ||
363 | data.tail = NULL; | ||
364 | for (i = 0; i < len; i++) { | ||
365 | rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab, cond_insertf, &data); | ||
366 | if (rc) | ||
367 | return rc; | ||
368 | |||
369 | } | ||
370 | |||
371 | *ret_list = data.head; | ||
372 | return 0; | ||
373 | } | ||
374 | |||
353 | static int expr_isvalid(struct policydb *p, struct cond_expr *expr) | 375 | static int expr_isvalid(struct policydb *p, struct cond_expr *expr) |
354 | { | 376 | { |
355 | if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) { | 377 | if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) { |
@@ -452,6 +474,7 @@ int cond_read_list(struct policydb *p, void *fp) | |||
452 | return 0; | 474 | return 0; |
453 | err: | 475 | err: |
454 | cond_list_destroy(p->cond_list); | 476 | cond_list_destroy(p->cond_list); |
477 | p->cond_list = NULL; | ||
455 | return -1; | 478 | return -1; |
456 | } | 479 | } |
457 | 480 | ||
@@ -465,22 +488,22 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decisi | |||
465 | if(!ctab || !key || !avd) | 488 | if(!ctab || !key || !avd) |
466 | return; | 489 | return; |
467 | 490 | ||
468 | for(node = avtab_search_node(ctab, key, AVTAB_AV); node != NULL; | 491 | for(node = avtab_search_node(ctab, key); node != NULL; |
469 | node = avtab_search_node_next(node, AVTAB_AV)) { | 492 | node = avtab_search_node_next(node, key->specified)) { |
470 | if ( (__u32) (AVTAB_ALLOWED|AVTAB_ENABLED) == | 493 | if ( (u16) (AVTAB_ALLOWED|AVTAB_ENABLED) == |
471 | (node->datum.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) | 494 | (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) |
472 | avd->allowed |= avtab_allowed(&node->datum); | 495 | avd->allowed |= node->datum.data; |
473 | if ( (__u32) (AVTAB_AUDITDENY|AVTAB_ENABLED) == | 496 | if ( (u16) (AVTAB_AUDITDENY|AVTAB_ENABLED) == |
474 | (node->datum.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) | 497 | (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) |
475 | /* Since a '0' in an auditdeny mask represents a | 498 | /* Since a '0' in an auditdeny mask represents a |
476 | * permission we do NOT want to audit (dontaudit), we use | 499 | * permission we do NOT want to audit (dontaudit), we use |
477 | * the '&' operand to ensure that all '0's in the mask | 500 | * the '&' operand to ensure that all '0's in the mask |
478 | * are retained (much unlike the allow and auditallow cases). | 501 | * are retained (much unlike the allow and auditallow cases). |
479 | */ | 502 | */ |
480 | avd->auditdeny &= avtab_auditdeny(&node->datum); | 503 | avd->auditdeny &= node->datum.data; |
481 | if ( (__u32) (AVTAB_AUDITALLOW|AVTAB_ENABLED) == | 504 | if ( (u16) (AVTAB_AUDITALLOW|AVTAB_ENABLED) == |
482 | (node->datum.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) | 505 | (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) |
483 | avd->auditallow |= avtab_auditallow(&node->datum); | 506 | avd->auditallow |= node->datum.data; |
484 | } | 507 | } |
485 | return; | 508 | return; |
486 | } | 509 | } |