aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/ss/conditional.c
diff options
context:
space:
mode:
authorStephen Smalley <sds@tycho.nsa.gov>2005-09-03 18:55:16 -0400
committerLinus Torvalds <torvalds@evo.osdl.org>2005-09-05 03:05:50 -0400
commit782ebb992ec20b5afdd5786ee8c2f1b58b631f24 (patch)
treeadf0af44fa591d803ec6b9ab7541ff3e5745dd93 /security/selinux/ss/conditional.c
parent720d6c29e146e96cca858057469951e91e0e6850 (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.c205
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
255static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, 255struct 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
263static 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
347err: 336err:
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
342static 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
353static int expr_isvalid(struct policydb *p, struct cond_expr *expr) 375static 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;
453err: 475err:
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}