diff options
Diffstat (limited to 'security/selinux/ss')
-rw-r--r-- | security/selinux/ss/avtab.c | 42 | ||||
-rw-r--r-- | security/selinux/ss/avtab.h | 2 | ||||
-rw-r--r-- | security/selinux/ss/conditional.c | 123 | ||||
-rw-r--r-- | security/selinux/ss/conditional.h | 2 | ||||
-rw-r--r-- | security/selinux/ss/ebitmap.c | 81 | ||||
-rw-r--r-- | security/selinux/ss/ebitmap.h | 1 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 841 | ||||
-rw-r--r-- | security/selinux/ss/policydb.h | 20 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 48 |
9 files changed, 1158 insertions, 2 deletions
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 77a917ccc045..a3dd9faa19c0 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c | |||
@@ -501,6 +501,48 @@ bad: | |||
501 | goto out; | 501 | goto out; |
502 | } | 502 | } |
503 | 503 | ||
504 | int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) | ||
505 | { | ||
506 | __le16 buf16[4]; | ||
507 | __le32 buf32[1]; | ||
508 | int rc; | ||
509 | |||
510 | buf16[0] = cpu_to_le16(cur->key.source_type); | ||
511 | buf16[1] = cpu_to_le16(cur->key.target_type); | ||
512 | buf16[2] = cpu_to_le16(cur->key.target_class); | ||
513 | buf16[3] = cpu_to_le16(cur->key.specified); | ||
514 | rc = put_entry(buf16, sizeof(u16), 4, fp); | ||
515 | if (rc) | ||
516 | return rc; | ||
517 | buf32[0] = cpu_to_le32(cur->datum.data); | ||
518 | rc = put_entry(buf32, sizeof(u32), 1, fp); | ||
519 | if (rc) | ||
520 | return rc; | ||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | int avtab_write(struct policydb *p, struct avtab *a, void *fp) | ||
525 | { | ||
526 | unsigned int i; | ||
527 | int rc = 0; | ||
528 | struct avtab_node *cur; | ||
529 | __le32 buf[1]; | ||
530 | |||
531 | buf[0] = cpu_to_le32(a->nel); | ||
532 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
533 | if (rc) | ||
534 | return rc; | ||
535 | |||
536 | for (i = 0; i < a->nslot; i++) { | ||
537 | for (cur = a->htable[i]; cur; cur = cur->next) { | ||
538 | rc = avtab_write_item(p, cur, fp); | ||
539 | if (rc) | ||
540 | return rc; | ||
541 | } | ||
542 | } | ||
543 | |||
544 | return rc; | ||
545 | } | ||
504 | void avtab_cache_init(void) | 546 | void avtab_cache_init(void) |
505 | { | 547 | { |
506 | avtab_node_cachep = kmem_cache_create("avtab_node", | 548 | avtab_node_cachep = kmem_cache_create("avtab_node", |
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index 32bd8b39f820..dff0c75345c1 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h | |||
@@ -71,6 +71,8 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, | |||
71 | void *p); | 71 | void *p); |
72 | 72 | ||
73 | int avtab_read(struct avtab *a, void *fp, struct policydb *pol); | 73 | int avtab_read(struct avtab *a, void *fp, struct policydb *pol); |
74 | int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp); | ||
75 | int avtab_write(struct policydb *p, struct avtab *a, void *fp); | ||
74 | 76 | ||
75 | struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, | 77 | struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, |
76 | struct avtab_datum *datum); | 78 | struct avtab_datum *datum); |
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index c91e150c3087..655fe1c6cc69 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c | |||
@@ -490,6 +490,129 @@ err: | |||
490 | return rc; | 490 | return rc; |
491 | } | 491 | } |
492 | 492 | ||
493 | int cond_write_bool(void *vkey, void *datum, void *ptr) | ||
494 | { | ||
495 | char *key = vkey; | ||
496 | struct cond_bool_datum *booldatum = datum; | ||
497 | struct policy_data *pd = ptr; | ||
498 | void *fp = pd->fp; | ||
499 | __le32 buf[3]; | ||
500 | u32 len; | ||
501 | int rc; | ||
502 | |||
503 | len = strlen(key); | ||
504 | buf[0] = cpu_to_le32(booldatum->value); | ||
505 | buf[1] = cpu_to_le32(booldatum->state); | ||
506 | buf[2] = cpu_to_le32(len); | ||
507 | rc = put_entry(buf, sizeof(u32), 3, fp); | ||
508 | if (rc) | ||
509 | return rc; | ||
510 | rc = put_entry(key, 1, len, fp); | ||
511 | if (rc) | ||
512 | return rc; | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | /* | ||
517 | * cond_write_cond_av_list doesn't write out the av_list nodes. | ||
518 | * Instead it writes out the key/value pairs from the avtab. This | ||
519 | * is necessary because there is no way to uniquely identifying rules | ||
520 | * in the avtab so it is not possible to associate individual rules | ||
521 | * in the avtab with a conditional without saving them as part of | ||
522 | * the conditional. This means that the avtab with the conditional | ||
523 | * rules will not be saved but will be rebuilt on policy load. | ||
524 | */ | ||
525 | static int cond_write_av_list(struct policydb *p, | ||
526 | struct cond_av_list *list, struct policy_file *fp) | ||
527 | { | ||
528 | __le32 buf[1]; | ||
529 | struct cond_av_list *cur_list; | ||
530 | u32 len; | ||
531 | int rc; | ||
532 | |||
533 | len = 0; | ||
534 | for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) | ||
535 | len++; | ||
536 | |||
537 | buf[0] = cpu_to_le32(len); | ||
538 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
539 | if (rc) | ||
540 | return rc; | ||
541 | |||
542 | if (len == 0) | ||
543 | return 0; | ||
544 | |||
545 | for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) { | ||
546 | rc = avtab_write_item(p, cur_list->node, fp); | ||
547 | if (rc) | ||
548 | return rc; | ||
549 | } | ||
550 | |||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | int cond_write_node(struct policydb *p, struct cond_node *node, | ||
555 | struct policy_file *fp) | ||
556 | { | ||
557 | struct cond_expr *cur_expr; | ||
558 | __le32 buf[2]; | ||
559 | int rc; | ||
560 | u32 len = 0; | ||
561 | |||
562 | buf[0] = cpu_to_le32(node->cur_state); | ||
563 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
564 | if (rc) | ||
565 | return rc; | ||
566 | |||
567 | for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) | ||
568 | len++; | ||
569 | |||
570 | buf[0] = cpu_to_le32(len); | ||
571 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
572 | if (rc) | ||
573 | return rc; | ||
574 | |||
575 | for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) { | ||
576 | buf[0] = cpu_to_le32(cur_expr->expr_type); | ||
577 | buf[1] = cpu_to_le32(cur_expr->bool); | ||
578 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
579 | if (rc) | ||
580 | return rc; | ||
581 | } | ||
582 | |||
583 | rc = cond_write_av_list(p, node->true_list, fp); | ||
584 | if (rc) | ||
585 | return rc; | ||
586 | rc = cond_write_av_list(p, node->false_list, fp); | ||
587 | if (rc) | ||
588 | return rc; | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | int cond_write_list(struct policydb *p, struct cond_node *list, void *fp) | ||
594 | { | ||
595 | struct cond_node *cur; | ||
596 | u32 len; | ||
597 | __le32 buf[1]; | ||
598 | int rc; | ||
599 | |||
600 | len = 0; | ||
601 | for (cur = list; cur != NULL; cur = cur->next) | ||
602 | len++; | ||
603 | buf[0] = cpu_to_le32(len); | ||
604 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
605 | if (rc) | ||
606 | return rc; | ||
607 | |||
608 | for (cur = list; cur != NULL; cur = cur->next) { | ||
609 | rc = cond_write_node(p, cur, fp); | ||
610 | if (rc) | ||
611 | return rc; | ||
612 | } | ||
613 | |||
614 | return 0; | ||
615 | } | ||
493 | /* Determine whether additional permissions are granted by the conditional | 616 | /* Determine whether additional permissions are granted by the conditional |
494 | * av table, and if so, add them to the result | 617 | * av table, and if so, add them to the result |
495 | */ | 618 | */ |
diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h index 53ddb013ae57..3f209c635295 100644 --- a/security/selinux/ss/conditional.h +++ b/security/selinux/ss/conditional.h | |||
@@ -69,6 +69,8 @@ int cond_index_bool(void *key, void *datum, void *datap); | |||
69 | 69 | ||
70 | int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp); | 70 | int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp); |
71 | int cond_read_list(struct policydb *p, void *fp); | 71 | int cond_read_list(struct policydb *p, void *fp); |
72 | int cond_write_bool(void *key, void *datum, void *ptr); | ||
73 | int cond_write_list(struct policydb *p, struct cond_node *list, void *fp); | ||
72 | 74 | ||
73 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd); | 75 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd); |
74 | 76 | ||
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 04b6145d767f..d42951fcbe87 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include "ebitmap.h" | 22 | #include "ebitmap.h" |
23 | #include "policydb.h" | 23 | #include "policydb.h" |
24 | 24 | ||
25 | #define BITS_PER_U64 (sizeof(u64) * 8) | ||
26 | |||
25 | int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) | 27 | int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) |
26 | { | 28 | { |
27 | struct ebitmap_node *n1, *n2; | 29 | struct ebitmap_node *n1, *n2; |
@@ -363,10 +365,10 @@ int ebitmap_read(struct ebitmap *e, void *fp) | |||
363 | e->highbit = le32_to_cpu(buf[1]); | 365 | e->highbit = le32_to_cpu(buf[1]); |
364 | count = le32_to_cpu(buf[2]); | 366 | count = le32_to_cpu(buf[2]); |
365 | 367 | ||
366 | if (mapunit != sizeof(u64) * 8) { | 368 | if (mapunit != BITS_PER_U64) { |
367 | printk(KERN_ERR "SELinux: ebitmap: map size %u does not " | 369 | printk(KERN_ERR "SELinux: ebitmap: map size %u does not " |
368 | "match my size %Zd (high bit was %d)\n", | 370 | "match my size %Zd (high bit was %d)\n", |
369 | mapunit, sizeof(u64) * 8, e->highbit); | 371 | mapunit, BITS_PER_U64, e->highbit); |
370 | goto bad; | 372 | goto bad; |
371 | } | 373 | } |
372 | 374 | ||
@@ -446,3 +448,78 @@ bad: | |||
446 | ebitmap_destroy(e); | 448 | ebitmap_destroy(e); |
447 | goto out; | 449 | goto out; |
448 | } | 450 | } |
451 | |||
452 | int ebitmap_write(struct ebitmap *e, void *fp) | ||
453 | { | ||
454 | struct ebitmap_node *n; | ||
455 | u32 count; | ||
456 | __le32 buf[3]; | ||
457 | u64 map; | ||
458 | int bit, last_bit, last_startbit, rc; | ||
459 | |||
460 | buf[0] = cpu_to_le32(BITS_PER_U64); | ||
461 | |||
462 | count = 0; | ||
463 | last_bit = 0; | ||
464 | last_startbit = -1; | ||
465 | ebitmap_for_each_positive_bit(e, n, bit) { | ||
466 | if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) { | ||
467 | count++; | ||
468 | last_startbit = rounddown(bit, BITS_PER_U64); | ||
469 | } | ||
470 | last_bit = roundup(bit + 1, BITS_PER_U64); | ||
471 | } | ||
472 | buf[1] = cpu_to_le32(last_bit); | ||
473 | buf[2] = cpu_to_le32(count); | ||
474 | |||
475 | rc = put_entry(buf, sizeof(u32), 3, fp); | ||
476 | if (rc) | ||
477 | return rc; | ||
478 | |||
479 | map = 0; | ||
480 | last_startbit = INT_MIN; | ||
481 | ebitmap_for_each_positive_bit(e, n, bit) { | ||
482 | if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) { | ||
483 | __le64 buf64[1]; | ||
484 | |||
485 | /* this is the very first bit */ | ||
486 | if (!map) { | ||
487 | last_startbit = rounddown(bit, BITS_PER_U64); | ||
488 | map = (u64)1 << (bit - last_startbit); | ||
489 | continue; | ||
490 | } | ||
491 | |||
492 | /* write the last node */ | ||
493 | buf[0] = cpu_to_le32(last_startbit); | ||
494 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
495 | if (rc) | ||
496 | return rc; | ||
497 | |||
498 | buf64[0] = cpu_to_le64(map); | ||
499 | rc = put_entry(buf64, sizeof(u64), 1, fp); | ||
500 | if (rc) | ||
501 | return rc; | ||
502 | |||
503 | /* set up for the next node */ | ||
504 | map = 0; | ||
505 | last_startbit = rounddown(bit, BITS_PER_U64); | ||
506 | } | ||
507 | map |= (u64)1 << (bit - last_startbit); | ||
508 | } | ||
509 | /* write the last node */ | ||
510 | if (map) { | ||
511 | __le64 buf64[1]; | ||
512 | |||
513 | /* write the last node */ | ||
514 | buf[0] = cpu_to_le32(last_startbit); | ||
515 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
516 | if (rc) | ||
517 | return rc; | ||
518 | |||
519 | buf64[0] = cpu_to_le64(map); | ||
520 | rc = put_entry(buf64, sizeof(u64), 1, fp); | ||
521 | if (rc) | ||
522 | return rc; | ||
523 | } | ||
524 | return 0; | ||
525 | } | ||
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index f283b4367f54..1f4e93c2ae86 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h | |||
@@ -123,6 +123,7 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit); | |||
123 | int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); | 123 | int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); |
124 | void ebitmap_destroy(struct ebitmap *e); | 124 | void ebitmap_destroy(struct ebitmap *e); |
125 | int ebitmap_read(struct ebitmap *e, void *fp); | 125 | int ebitmap_read(struct ebitmap *e, void *fp); |
126 | int ebitmap_write(struct ebitmap *e, void *fp); | ||
126 | 127 | ||
127 | #ifdef CONFIG_NETLABEL | 128 | #ifdef CONFIG_NETLABEL |
128 | int ebitmap_netlbl_export(struct ebitmap *ebmap, | 129 | int ebitmap_netlbl_export(struct ebitmap *ebmap, |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 97fb0cf0eb69..94f630d93a5c 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include "policydb.h" | 37 | #include "policydb.h" |
38 | #include "conditional.h" | 38 | #include "conditional.h" |
39 | #include "mls.h" | 39 | #include "mls.h" |
40 | #include "services.h" | ||
40 | 41 | ||
41 | #define _DEBUG_HASHES | 42 | #define _DEBUG_HASHES |
42 | 43 | ||
@@ -2316,3 +2317,843 @@ bad: | |||
2316 | policydb_destroy(p); | 2317 | policydb_destroy(p); |
2317 | goto out; | 2318 | goto out; |
2318 | } | 2319 | } |
2320 | |||
2321 | /* | ||
2322 | * Write a MLS level structure to a policydb binary | ||
2323 | * representation file. | ||
2324 | */ | ||
2325 | static int mls_write_level(struct mls_level *l, void *fp) | ||
2326 | { | ||
2327 | __le32 buf[1]; | ||
2328 | int rc; | ||
2329 | |||
2330 | buf[0] = cpu_to_le32(l->sens); | ||
2331 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2332 | if (rc) | ||
2333 | return rc; | ||
2334 | |||
2335 | rc = ebitmap_write(&l->cat, fp); | ||
2336 | if (rc) | ||
2337 | return rc; | ||
2338 | |||
2339 | return 0; | ||
2340 | } | ||
2341 | |||
2342 | /* | ||
2343 | * Write a MLS range structure to a policydb binary | ||
2344 | * representation file. | ||
2345 | */ | ||
2346 | static int mls_write_range_helper(struct mls_range *r, void *fp) | ||
2347 | { | ||
2348 | __le32 buf[3]; | ||
2349 | size_t items; | ||
2350 | int rc, eq; | ||
2351 | |||
2352 | eq = mls_level_eq(&r->level[1], &r->level[0]); | ||
2353 | |||
2354 | if (eq) | ||
2355 | items = 2; | ||
2356 | else | ||
2357 | items = 3; | ||
2358 | buf[0] = cpu_to_le32(items-1); | ||
2359 | buf[1] = cpu_to_le32(r->level[0].sens); | ||
2360 | if (!eq) | ||
2361 | buf[2] = cpu_to_le32(r->level[1].sens); | ||
2362 | |||
2363 | BUG_ON(items > (sizeof(buf)/sizeof(buf[0]))); | ||
2364 | |||
2365 | rc = put_entry(buf, sizeof(u32), items, fp); | ||
2366 | if (rc) | ||
2367 | return rc; | ||
2368 | |||
2369 | rc = ebitmap_write(&r->level[0].cat, fp); | ||
2370 | if (rc) | ||
2371 | return rc; | ||
2372 | if (!eq) { | ||
2373 | rc = ebitmap_write(&r->level[1].cat, fp); | ||
2374 | if (rc) | ||
2375 | return rc; | ||
2376 | } | ||
2377 | |||
2378 | return 0; | ||
2379 | } | ||
2380 | |||
2381 | static int sens_write(void *vkey, void *datum, void *ptr) | ||
2382 | { | ||
2383 | char *key = vkey; | ||
2384 | struct level_datum *levdatum = datum; | ||
2385 | struct policy_data *pd = ptr; | ||
2386 | void *fp = pd->fp; | ||
2387 | __le32 buf[2]; | ||
2388 | size_t len; | ||
2389 | int rc; | ||
2390 | |||
2391 | len = strlen(key); | ||
2392 | buf[0] = cpu_to_le32(len); | ||
2393 | buf[1] = cpu_to_le32(levdatum->isalias); | ||
2394 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
2395 | if (rc) | ||
2396 | return rc; | ||
2397 | |||
2398 | rc = put_entry(key, 1, len, fp); | ||
2399 | if (rc) | ||
2400 | return rc; | ||
2401 | |||
2402 | rc = mls_write_level(levdatum->level, fp); | ||
2403 | if (rc) | ||
2404 | return rc; | ||
2405 | |||
2406 | return 0; | ||
2407 | } | ||
2408 | |||
2409 | static int cat_write(void *vkey, void *datum, void *ptr) | ||
2410 | { | ||
2411 | char *key = vkey; | ||
2412 | struct cat_datum *catdatum = datum; | ||
2413 | struct policy_data *pd = ptr; | ||
2414 | void *fp = pd->fp; | ||
2415 | __le32 buf[3]; | ||
2416 | size_t len; | ||
2417 | int rc; | ||
2418 | |||
2419 | len = strlen(key); | ||
2420 | buf[0] = cpu_to_le32(len); | ||
2421 | buf[1] = cpu_to_le32(catdatum->value); | ||
2422 | buf[2] = cpu_to_le32(catdatum->isalias); | ||
2423 | rc = put_entry(buf, sizeof(u32), 3, fp); | ||
2424 | if (rc) | ||
2425 | return rc; | ||
2426 | |||
2427 | rc = put_entry(key, 1, len, fp); | ||
2428 | if (rc) | ||
2429 | return rc; | ||
2430 | |||
2431 | return 0; | ||
2432 | } | ||
2433 | |||
2434 | static int role_trans_write(struct role_trans *r, void *fp) | ||
2435 | { | ||
2436 | struct role_trans *tr; | ||
2437 | u32 buf[3]; | ||
2438 | size_t nel; | ||
2439 | int rc; | ||
2440 | |||
2441 | nel = 0; | ||
2442 | for (tr = r; tr; tr = tr->next) | ||
2443 | nel++; | ||
2444 | buf[0] = cpu_to_le32(nel); | ||
2445 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2446 | if (rc) | ||
2447 | return rc; | ||
2448 | for (tr = r; tr; tr = tr->next) { | ||
2449 | buf[0] = cpu_to_le32(tr->role); | ||
2450 | buf[1] = cpu_to_le32(tr->type); | ||
2451 | buf[2] = cpu_to_le32(tr->new_role); | ||
2452 | rc = put_entry(buf, sizeof(u32), 3, fp); | ||
2453 | if (rc) | ||
2454 | return rc; | ||
2455 | } | ||
2456 | |||
2457 | return 0; | ||
2458 | } | ||
2459 | |||
2460 | static int role_allow_write(struct role_allow *r, void *fp) | ||
2461 | { | ||
2462 | struct role_allow *ra; | ||
2463 | u32 buf[2]; | ||
2464 | size_t nel; | ||
2465 | int rc; | ||
2466 | |||
2467 | nel = 0; | ||
2468 | for (ra = r; ra; ra = ra->next) | ||
2469 | nel++; | ||
2470 | buf[0] = cpu_to_le32(nel); | ||
2471 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2472 | if (rc) | ||
2473 | return rc; | ||
2474 | for (ra = r; ra; ra = ra->next) { | ||
2475 | buf[0] = cpu_to_le32(ra->role); | ||
2476 | buf[1] = cpu_to_le32(ra->new_role); | ||
2477 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
2478 | if (rc) | ||
2479 | return rc; | ||
2480 | } | ||
2481 | return 0; | ||
2482 | } | ||
2483 | |||
2484 | /* | ||
2485 | * Write a security context structure | ||
2486 | * to a policydb binary representation file. | ||
2487 | */ | ||
2488 | static int context_write(struct policydb *p, struct context *c, | ||
2489 | void *fp) | ||
2490 | { | ||
2491 | int rc; | ||
2492 | __le32 buf[3]; | ||
2493 | |||
2494 | buf[0] = cpu_to_le32(c->user); | ||
2495 | buf[1] = cpu_to_le32(c->role); | ||
2496 | buf[2] = cpu_to_le32(c->type); | ||
2497 | |||
2498 | rc = put_entry(buf, sizeof(u32), 3, fp); | ||
2499 | if (rc) | ||
2500 | return rc; | ||
2501 | |||
2502 | rc = mls_write_range_helper(&c->range, fp); | ||
2503 | if (rc) | ||
2504 | return rc; | ||
2505 | |||
2506 | return 0; | ||
2507 | } | ||
2508 | |||
2509 | /* | ||
2510 | * The following *_write functions are used to | ||
2511 | * write the symbol data to a policy database | ||
2512 | * binary representation file. | ||
2513 | */ | ||
2514 | |||
2515 | static int perm_write(void *vkey, void *datum, void *fp) | ||
2516 | { | ||
2517 | char *key = vkey; | ||
2518 | struct perm_datum *perdatum = datum; | ||
2519 | __le32 buf[2]; | ||
2520 | size_t len; | ||
2521 | int rc; | ||
2522 | |||
2523 | len = strlen(key); | ||
2524 | buf[0] = cpu_to_le32(len); | ||
2525 | buf[1] = cpu_to_le32(perdatum->value); | ||
2526 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
2527 | if (rc) | ||
2528 | return rc; | ||
2529 | |||
2530 | rc = put_entry(key, 1, len, fp); | ||
2531 | if (rc) | ||
2532 | return rc; | ||
2533 | |||
2534 | return 0; | ||
2535 | } | ||
2536 | |||
2537 | static int common_write(void *vkey, void *datum, void *ptr) | ||
2538 | { | ||
2539 | char *key = vkey; | ||
2540 | struct common_datum *comdatum = datum; | ||
2541 | struct policy_data *pd = ptr; | ||
2542 | void *fp = pd->fp; | ||
2543 | __le32 buf[4]; | ||
2544 | size_t len; | ||
2545 | int rc; | ||
2546 | |||
2547 | len = strlen(key); | ||
2548 | buf[0] = cpu_to_le32(len); | ||
2549 | buf[1] = cpu_to_le32(comdatum->value); | ||
2550 | buf[2] = cpu_to_le32(comdatum->permissions.nprim); | ||
2551 | buf[3] = cpu_to_le32(comdatum->permissions.table->nel); | ||
2552 | rc = put_entry(buf, sizeof(u32), 4, fp); | ||
2553 | if (rc) | ||
2554 | return rc; | ||
2555 | |||
2556 | rc = put_entry(key, 1, len, fp); | ||
2557 | if (rc) | ||
2558 | return rc; | ||
2559 | |||
2560 | rc = hashtab_map(comdatum->permissions.table, perm_write, fp); | ||
2561 | if (rc) | ||
2562 | return rc; | ||
2563 | |||
2564 | return 0; | ||
2565 | } | ||
2566 | |||
2567 | static int write_cons_helper(struct policydb *p, struct constraint_node *node, | ||
2568 | void *fp) | ||
2569 | { | ||
2570 | struct constraint_node *c; | ||
2571 | struct constraint_expr *e; | ||
2572 | __le32 buf[3]; | ||
2573 | u32 nel; | ||
2574 | int rc; | ||
2575 | |||
2576 | for (c = node; c; c = c->next) { | ||
2577 | nel = 0; | ||
2578 | for (e = c->expr; e; e = e->next) | ||
2579 | nel++; | ||
2580 | buf[0] = cpu_to_le32(c->permissions); | ||
2581 | buf[1] = cpu_to_le32(nel); | ||
2582 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
2583 | if (rc) | ||
2584 | return rc; | ||
2585 | for (e = c->expr; e; e = e->next) { | ||
2586 | buf[0] = cpu_to_le32(e->expr_type); | ||
2587 | buf[1] = cpu_to_le32(e->attr); | ||
2588 | buf[2] = cpu_to_le32(e->op); | ||
2589 | rc = put_entry(buf, sizeof(u32), 3, fp); | ||
2590 | if (rc) | ||
2591 | return rc; | ||
2592 | |||
2593 | switch (e->expr_type) { | ||
2594 | case CEXPR_NAMES: | ||
2595 | rc = ebitmap_write(&e->names, fp); | ||
2596 | if (rc) | ||
2597 | return rc; | ||
2598 | break; | ||
2599 | default: | ||
2600 | break; | ||
2601 | } | ||
2602 | } | ||
2603 | } | ||
2604 | |||
2605 | return 0; | ||
2606 | } | ||
2607 | |||
2608 | static int class_write(void *vkey, void *datum, void *ptr) | ||
2609 | { | ||
2610 | char *key = vkey; | ||
2611 | struct class_datum *cladatum = datum; | ||
2612 | struct policy_data *pd = ptr; | ||
2613 | void *fp = pd->fp; | ||
2614 | struct policydb *p = pd->p; | ||
2615 | struct constraint_node *c; | ||
2616 | __le32 buf[6]; | ||
2617 | u32 ncons; | ||
2618 | size_t len, len2; | ||
2619 | int rc; | ||
2620 | |||
2621 | len = strlen(key); | ||
2622 | if (cladatum->comkey) | ||
2623 | len2 = strlen(cladatum->comkey); | ||
2624 | else | ||
2625 | len2 = 0; | ||
2626 | |||
2627 | ncons = 0; | ||
2628 | for (c = cladatum->constraints; c; c = c->next) | ||
2629 | ncons++; | ||
2630 | |||
2631 | buf[0] = cpu_to_le32(len); | ||
2632 | buf[1] = cpu_to_le32(len2); | ||
2633 | buf[2] = cpu_to_le32(cladatum->value); | ||
2634 | buf[3] = cpu_to_le32(cladatum->permissions.nprim); | ||
2635 | if (cladatum->permissions.table) | ||
2636 | buf[4] = cpu_to_le32(cladatum->permissions.table->nel); | ||
2637 | else | ||
2638 | buf[4] = 0; | ||
2639 | buf[5] = cpu_to_le32(ncons); | ||
2640 | rc = put_entry(buf, sizeof(u32), 6, fp); | ||
2641 | if (rc) | ||
2642 | return rc; | ||
2643 | |||
2644 | rc = put_entry(key, 1, len, fp); | ||
2645 | if (rc) | ||
2646 | return rc; | ||
2647 | |||
2648 | if (cladatum->comkey) { | ||
2649 | rc = put_entry(cladatum->comkey, 1, len2, fp); | ||
2650 | if (rc) | ||
2651 | return rc; | ||
2652 | } | ||
2653 | |||
2654 | rc = hashtab_map(cladatum->permissions.table, perm_write, fp); | ||
2655 | if (rc) | ||
2656 | return rc; | ||
2657 | |||
2658 | rc = write_cons_helper(p, cladatum->constraints, fp); | ||
2659 | if (rc) | ||
2660 | return rc; | ||
2661 | |||
2662 | /* write out the validatetrans rule */ | ||
2663 | ncons = 0; | ||
2664 | for (c = cladatum->validatetrans; c; c = c->next) | ||
2665 | ncons++; | ||
2666 | |||
2667 | buf[0] = cpu_to_le32(ncons); | ||
2668 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2669 | if (rc) | ||
2670 | return rc; | ||
2671 | |||
2672 | rc = write_cons_helper(p, cladatum->validatetrans, fp); | ||
2673 | if (rc) | ||
2674 | return rc; | ||
2675 | |||
2676 | return 0; | ||
2677 | } | ||
2678 | |||
2679 | static int role_write(void *vkey, void *datum, void *ptr) | ||
2680 | { | ||
2681 | char *key = vkey; | ||
2682 | struct role_datum *role = datum; | ||
2683 | struct policy_data *pd = ptr; | ||
2684 | void *fp = pd->fp; | ||
2685 | struct policydb *p = pd->p; | ||
2686 | __le32 buf[3]; | ||
2687 | size_t items, len; | ||
2688 | int rc; | ||
2689 | |||
2690 | len = strlen(key); | ||
2691 | items = 0; | ||
2692 | buf[items++] = cpu_to_le32(len); | ||
2693 | buf[items++] = cpu_to_le32(role->value); | ||
2694 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) | ||
2695 | buf[items++] = cpu_to_le32(role->bounds); | ||
2696 | |||
2697 | BUG_ON(items > (sizeof(buf)/sizeof(buf[0]))); | ||
2698 | |||
2699 | rc = put_entry(buf, sizeof(u32), items, fp); | ||
2700 | if (rc) | ||
2701 | return rc; | ||
2702 | |||
2703 | rc = put_entry(key, 1, len, fp); | ||
2704 | if (rc) | ||
2705 | return rc; | ||
2706 | |||
2707 | rc = ebitmap_write(&role->dominates, fp); | ||
2708 | if (rc) | ||
2709 | return rc; | ||
2710 | |||
2711 | rc = ebitmap_write(&role->types, fp); | ||
2712 | if (rc) | ||
2713 | return rc; | ||
2714 | |||
2715 | return 0; | ||
2716 | } | ||
2717 | |||
2718 | static int type_write(void *vkey, void *datum, void *ptr) | ||
2719 | { | ||
2720 | char *key = vkey; | ||
2721 | struct type_datum *typdatum = datum; | ||
2722 | struct policy_data *pd = ptr; | ||
2723 | struct policydb *p = pd->p; | ||
2724 | void *fp = pd->fp; | ||
2725 | __le32 buf[4]; | ||
2726 | int rc; | ||
2727 | size_t items, len; | ||
2728 | |||
2729 | len = strlen(key); | ||
2730 | items = 0; | ||
2731 | buf[items++] = cpu_to_le32(len); | ||
2732 | buf[items++] = cpu_to_le32(typdatum->value); | ||
2733 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) { | ||
2734 | u32 properties = 0; | ||
2735 | |||
2736 | if (typdatum->primary) | ||
2737 | properties |= TYPEDATUM_PROPERTY_PRIMARY; | ||
2738 | |||
2739 | if (typdatum->attribute) | ||
2740 | properties |= TYPEDATUM_PROPERTY_ATTRIBUTE; | ||
2741 | |||
2742 | buf[items++] = cpu_to_le32(properties); | ||
2743 | buf[items++] = cpu_to_le32(typdatum->bounds); | ||
2744 | } else { | ||
2745 | buf[items++] = cpu_to_le32(typdatum->primary); | ||
2746 | } | ||
2747 | BUG_ON(items > (sizeof(buf) / sizeof(buf[0]))); | ||
2748 | rc = put_entry(buf, sizeof(u32), items, fp); | ||
2749 | if (rc) | ||
2750 | return rc; | ||
2751 | |||
2752 | rc = put_entry(key, 1, len, fp); | ||
2753 | if (rc) | ||
2754 | return rc; | ||
2755 | |||
2756 | return 0; | ||
2757 | } | ||
2758 | |||
2759 | static int user_write(void *vkey, void *datum, void *ptr) | ||
2760 | { | ||
2761 | char *key = vkey; | ||
2762 | struct user_datum *usrdatum = datum; | ||
2763 | struct policy_data *pd = ptr; | ||
2764 | struct policydb *p = pd->p; | ||
2765 | void *fp = pd->fp; | ||
2766 | __le32 buf[3]; | ||
2767 | size_t items, len; | ||
2768 | int rc; | ||
2769 | |||
2770 | len = strlen(key); | ||
2771 | items = 0; | ||
2772 | buf[items++] = cpu_to_le32(len); | ||
2773 | buf[items++] = cpu_to_le32(usrdatum->value); | ||
2774 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) | ||
2775 | buf[items++] = cpu_to_le32(usrdatum->bounds); | ||
2776 | BUG_ON(items > (sizeof(buf) / sizeof(buf[0]))); | ||
2777 | rc = put_entry(buf, sizeof(u32), items, fp); | ||
2778 | if (rc) | ||
2779 | return rc; | ||
2780 | |||
2781 | rc = put_entry(key, 1, len, fp); | ||
2782 | if (rc) | ||
2783 | return rc; | ||
2784 | |||
2785 | rc = ebitmap_write(&usrdatum->roles, fp); | ||
2786 | if (rc) | ||
2787 | return rc; | ||
2788 | |||
2789 | rc = mls_write_range_helper(&usrdatum->range, fp); | ||
2790 | if (rc) | ||
2791 | return rc; | ||
2792 | |||
2793 | rc = mls_write_level(&usrdatum->dfltlevel, fp); | ||
2794 | if (rc) | ||
2795 | return rc; | ||
2796 | |||
2797 | return 0; | ||
2798 | } | ||
2799 | |||
2800 | static int (*write_f[SYM_NUM]) (void *key, void *datum, | ||
2801 | void *datap) = | ||
2802 | { | ||
2803 | common_write, | ||
2804 | class_write, | ||
2805 | role_write, | ||
2806 | type_write, | ||
2807 | user_write, | ||
2808 | cond_write_bool, | ||
2809 | sens_write, | ||
2810 | cat_write, | ||
2811 | }; | ||
2812 | |||
2813 | static int ocontext_write(struct policydb *p, struct policydb_compat_info *info, | ||
2814 | void *fp) | ||
2815 | { | ||
2816 | unsigned int i, j, rc; | ||
2817 | size_t nel, len; | ||
2818 | __le32 buf[3]; | ||
2819 | u32 nodebuf[8]; | ||
2820 | struct ocontext *c; | ||
2821 | for (i = 0; i < info->ocon_num; i++) { | ||
2822 | nel = 0; | ||
2823 | for (c = p->ocontexts[i]; c; c = c->next) | ||
2824 | nel++; | ||
2825 | buf[0] = cpu_to_le32(nel); | ||
2826 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2827 | if (rc) | ||
2828 | return rc; | ||
2829 | for (c = p->ocontexts[i]; c; c = c->next) { | ||
2830 | switch (i) { | ||
2831 | case OCON_ISID: | ||
2832 | buf[0] = cpu_to_le32(c->sid[0]); | ||
2833 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2834 | if (rc) | ||
2835 | return rc; | ||
2836 | rc = context_write(p, &c->context[0], fp); | ||
2837 | if (rc) | ||
2838 | return rc; | ||
2839 | break; | ||
2840 | case OCON_FS: | ||
2841 | case OCON_NETIF: | ||
2842 | len = strlen(c->u.name); | ||
2843 | buf[0] = cpu_to_le32(len); | ||
2844 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2845 | if (rc) | ||
2846 | return rc; | ||
2847 | rc = put_entry(c->u.name, 1, len, fp); | ||
2848 | if (rc) | ||
2849 | return rc; | ||
2850 | rc = context_write(p, &c->context[0], fp); | ||
2851 | if (rc) | ||
2852 | return rc; | ||
2853 | rc = context_write(p, &c->context[1], fp); | ||
2854 | if (rc) | ||
2855 | return rc; | ||
2856 | break; | ||
2857 | case OCON_PORT: | ||
2858 | buf[0] = cpu_to_le32(c->u.port.protocol); | ||
2859 | buf[1] = cpu_to_le32(c->u.port.low_port); | ||
2860 | buf[2] = cpu_to_le32(c->u.port.high_port); | ||
2861 | rc = put_entry(buf, sizeof(u32), 3, fp); | ||
2862 | if (rc) | ||
2863 | return rc; | ||
2864 | rc = context_write(p, &c->context[0], fp); | ||
2865 | if (rc) | ||
2866 | return rc; | ||
2867 | break; | ||
2868 | case OCON_NODE: | ||
2869 | nodebuf[0] = c->u.node.addr; /* network order */ | ||
2870 | nodebuf[1] = c->u.node.mask; /* network order */ | ||
2871 | rc = put_entry(nodebuf, sizeof(u32), 2, fp); | ||
2872 | if (rc) | ||
2873 | return rc; | ||
2874 | rc = context_write(p, &c->context[0], fp); | ||
2875 | if (rc) | ||
2876 | return rc; | ||
2877 | break; | ||
2878 | case OCON_FSUSE: | ||
2879 | buf[0] = cpu_to_le32(c->v.behavior); | ||
2880 | len = strlen(c->u.name); | ||
2881 | buf[1] = cpu_to_le32(len); | ||
2882 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
2883 | if (rc) | ||
2884 | return rc; | ||
2885 | rc = put_entry(c->u.name, 1, len, fp); | ||
2886 | if (rc) | ||
2887 | return rc; | ||
2888 | rc = context_write(p, &c->context[0], fp); | ||
2889 | if (rc) | ||
2890 | return rc; | ||
2891 | break; | ||
2892 | case OCON_NODE6: | ||
2893 | for (j = 0; j < 4; j++) | ||
2894 | nodebuf[j] = c->u.node6.addr[j]; /* network order */ | ||
2895 | for (j = 0; j < 4; j++) | ||
2896 | nodebuf[j + 4] = c->u.node6.mask[j]; /* network order */ | ||
2897 | rc = put_entry(nodebuf, sizeof(u32), 8, fp); | ||
2898 | if (rc) | ||
2899 | return rc; | ||
2900 | rc = context_write(p, &c->context[0], fp); | ||
2901 | if (rc) | ||
2902 | return rc; | ||
2903 | break; | ||
2904 | } | ||
2905 | } | ||
2906 | } | ||
2907 | return 0; | ||
2908 | } | ||
2909 | |||
2910 | static int genfs_write(struct policydb *p, void *fp) | ||
2911 | { | ||
2912 | struct genfs *genfs; | ||
2913 | struct ocontext *c; | ||
2914 | size_t len; | ||
2915 | __le32 buf[1]; | ||
2916 | int rc; | ||
2917 | |||
2918 | len = 0; | ||
2919 | for (genfs = p->genfs; genfs; genfs = genfs->next) | ||
2920 | len++; | ||
2921 | buf[0] = cpu_to_le32(len); | ||
2922 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2923 | if (rc) | ||
2924 | return rc; | ||
2925 | for (genfs = p->genfs; genfs; genfs = genfs->next) { | ||
2926 | len = strlen(genfs->fstype); | ||
2927 | buf[0] = cpu_to_le32(len); | ||
2928 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2929 | if (rc) | ||
2930 | return rc; | ||
2931 | rc = put_entry(genfs->fstype, 1, len, fp); | ||
2932 | if (rc) | ||
2933 | return rc; | ||
2934 | len = 0; | ||
2935 | for (c = genfs->head; c; c = c->next) | ||
2936 | len++; | ||
2937 | buf[0] = cpu_to_le32(len); | ||
2938 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2939 | if (rc) | ||
2940 | return rc; | ||
2941 | for (c = genfs->head; c; c = c->next) { | ||
2942 | len = strlen(c->u.name); | ||
2943 | buf[0] = cpu_to_le32(len); | ||
2944 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2945 | if (rc) | ||
2946 | return rc; | ||
2947 | rc = put_entry(c->u.name, 1, len, fp); | ||
2948 | if (rc) | ||
2949 | return rc; | ||
2950 | buf[0] = cpu_to_le32(c->v.sclass); | ||
2951 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2952 | if (rc) | ||
2953 | return rc; | ||
2954 | rc = context_write(p, &c->context[0], fp); | ||
2955 | if (rc) | ||
2956 | return rc; | ||
2957 | } | ||
2958 | } | ||
2959 | return 0; | ||
2960 | } | ||
2961 | |||
2962 | static int range_count(void *key, void *data, void *ptr) | ||
2963 | { | ||
2964 | int *cnt = ptr; | ||
2965 | *cnt = *cnt + 1; | ||
2966 | |||
2967 | return 0; | ||
2968 | } | ||
2969 | |||
2970 | static int range_write_helper(void *key, void *data, void *ptr) | ||
2971 | { | ||
2972 | __le32 buf[2]; | ||
2973 | struct range_trans *rt = key; | ||
2974 | struct mls_range *r = data; | ||
2975 | struct policy_data *pd = ptr; | ||
2976 | void *fp = pd->fp; | ||
2977 | struct policydb *p = pd->p; | ||
2978 | int rc; | ||
2979 | |||
2980 | buf[0] = cpu_to_le32(rt->source_type); | ||
2981 | buf[1] = cpu_to_le32(rt->target_type); | ||
2982 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
2983 | if (rc) | ||
2984 | return rc; | ||
2985 | if (p->policyvers >= POLICYDB_VERSION_RANGETRANS) { | ||
2986 | buf[0] = cpu_to_le32(rt->target_class); | ||
2987 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2988 | if (rc) | ||
2989 | return rc; | ||
2990 | } | ||
2991 | rc = mls_write_range_helper(r, fp); | ||
2992 | if (rc) | ||
2993 | return rc; | ||
2994 | |||
2995 | return 0; | ||
2996 | } | ||
2997 | |||
2998 | static int range_write(struct policydb *p, void *fp) | ||
2999 | { | ||
3000 | size_t nel; | ||
3001 | __le32 buf[1]; | ||
3002 | int rc; | ||
3003 | struct policy_data pd; | ||
3004 | |||
3005 | pd.p = p; | ||
3006 | pd.fp = fp; | ||
3007 | |||
3008 | /* count the number of entries in the hashtab */ | ||
3009 | nel = 0; | ||
3010 | rc = hashtab_map(p->range_tr, range_count, &nel); | ||
3011 | if (rc) | ||
3012 | return rc; | ||
3013 | |||
3014 | buf[0] = cpu_to_le32(nel); | ||
3015 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
3016 | if (rc) | ||
3017 | return rc; | ||
3018 | |||
3019 | /* actually write all of the entries */ | ||
3020 | rc = hashtab_map(p->range_tr, range_write_helper, &pd); | ||
3021 | if (rc) | ||
3022 | return rc; | ||
3023 | |||
3024 | return 0; | ||
3025 | } | ||
3026 | |||
3027 | /* | ||
3028 | * Write the configuration data in a policy database | ||
3029 | * structure to a policy database binary representation | ||
3030 | * file. | ||
3031 | */ | ||
3032 | int policydb_write(struct policydb *p, void *fp) | ||
3033 | { | ||
3034 | unsigned int i, num_syms; | ||
3035 | int rc; | ||
3036 | __le32 buf[4]; | ||
3037 | u32 config; | ||
3038 | size_t len; | ||
3039 | struct policydb_compat_info *info; | ||
3040 | |||
3041 | /* | ||
3042 | * refuse to write policy older than compressed avtab | ||
3043 | * to simplify the writer. There are other tests dropped | ||
3044 | * since we assume this throughout the writer code. Be | ||
3045 | * careful if you ever try to remove this restriction | ||
3046 | */ | ||
3047 | if (p->policyvers < POLICYDB_VERSION_AVTAB) { | ||
3048 | printk(KERN_ERR "SELinux: refusing to write policy version %d." | ||
3049 | " Because it is less than version %d\n", p->policyvers, | ||
3050 | POLICYDB_VERSION_AVTAB); | ||
3051 | return -EINVAL; | ||
3052 | } | ||
3053 | |||
3054 | config = 0; | ||
3055 | if (p->mls_enabled) | ||
3056 | config |= POLICYDB_CONFIG_MLS; | ||
3057 | |||
3058 | if (p->reject_unknown) | ||
3059 | config |= REJECT_UNKNOWN; | ||
3060 | if (p->allow_unknown) | ||
3061 | config |= ALLOW_UNKNOWN; | ||
3062 | |||
3063 | /* Write the magic number and string identifiers. */ | ||
3064 | buf[0] = cpu_to_le32(POLICYDB_MAGIC); | ||
3065 | len = strlen(POLICYDB_STRING); | ||
3066 | buf[1] = cpu_to_le32(len); | ||
3067 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
3068 | if (rc) | ||
3069 | return rc; | ||
3070 | rc = put_entry(POLICYDB_STRING, 1, len, fp); | ||
3071 | if (rc) | ||
3072 | return rc; | ||
3073 | |||
3074 | /* Write the version, config, and table sizes. */ | ||
3075 | info = policydb_lookup_compat(p->policyvers); | ||
3076 | if (!info) { | ||
3077 | printk(KERN_ERR "SELinux: compatibility lookup failed for policy " | ||
3078 | "version %d", p->policyvers); | ||
3079 | return rc; | ||
3080 | } | ||
3081 | |||
3082 | buf[0] = cpu_to_le32(p->policyvers); | ||
3083 | buf[1] = cpu_to_le32(config); | ||
3084 | buf[2] = cpu_to_le32(info->sym_num); | ||
3085 | buf[3] = cpu_to_le32(info->ocon_num); | ||
3086 | |||
3087 | rc = put_entry(buf, sizeof(u32), 4, fp); | ||
3088 | if (rc) | ||
3089 | return rc; | ||
3090 | |||
3091 | if (p->policyvers >= POLICYDB_VERSION_POLCAP) { | ||
3092 | rc = ebitmap_write(&p->policycaps, fp); | ||
3093 | if (rc) | ||
3094 | return rc; | ||
3095 | } | ||
3096 | |||
3097 | if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE) { | ||
3098 | rc = ebitmap_write(&p->permissive_map, fp); | ||
3099 | if (rc) | ||
3100 | return rc; | ||
3101 | } | ||
3102 | |||
3103 | num_syms = info->sym_num; | ||
3104 | for (i = 0; i < num_syms; i++) { | ||
3105 | struct policy_data pd; | ||
3106 | |||
3107 | pd.fp = fp; | ||
3108 | pd.p = p; | ||
3109 | |||
3110 | buf[0] = cpu_to_le32(p->symtab[i].nprim); | ||
3111 | buf[1] = cpu_to_le32(p->symtab[i].table->nel); | ||
3112 | |||
3113 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
3114 | if (rc) | ||
3115 | return rc; | ||
3116 | rc = hashtab_map(p->symtab[i].table, write_f[i], &pd); | ||
3117 | if (rc) | ||
3118 | return rc; | ||
3119 | } | ||
3120 | |||
3121 | rc = avtab_write(p, &p->te_avtab, fp); | ||
3122 | if (rc) | ||
3123 | return rc; | ||
3124 | |||
3125 | rc = cond_write_list(p, p->cond_list, fp); | ||
3126 | if (rc) | ||
3127 | return rc; | ||
3128 | |||
3129 | rc = role_trans_write(p->role_tr, fp); | ||
3130 | if (rc) | ||
3131 | return rc; | ||
3132 | |||
3133 | rc = role_allow_write(p->role_allow, fp); | ||
3134 | if (rc) | ||
3135 | return rc; | ||
3136 | |||
3137 | rc = ocontext_write(p, info, fp); | ||
3138 | if (rc) | ||
3139 | return rc; | ||
3140 | |||
3141 | rc = genfs_write(p, fp); | ||
3142 | if (rc) | ||
3143 | return rc; | ||
3144 | |||
3145 | rc = range_write(p, fp); | ||
3146 | if (rc) | ||
3147 | return rc; | ||
3148 | |||
3149 | for (i = 0; i < p->p_types.nprim; i++) { | ||
3150 | struct ebitmap *e = flex_array_get(p->type_attr_map_array, i); | ||
3151 | |||
3152 | BUG_ON(!e); | ||
3153 | rc = ebitmap_write(e, fp); | ||
3154 | if (rc) | ||
3155 | return rc; | ||
3156 | } | ||
3157 | |||
3158 | return 0; | ||
3159 | } | ||
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 310e94442cb8..95d3d7de361e 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
@@ -254,6 +254,9 @@ struct policydb { | |||
254 | 254 | ||
255 | struct ebitmap permissive_map; | 255 | struct ebitmap permissive_map; |
256 | 256 | ||
257 | /* length of this policy when it was loaded */ | ||
258 | size_t len; | ||
259 | |||
257 | unsigned int policyvers; | 260 | unsigned int policyvers; |
258 | 261 | ||
259 | unsigned int reject_unknown : 1; | 262 | unsigned int reject_unknown : 1; |
@@ -270,6 +273,7 @@ extern int policydb_class_isvalid(struct policydb *p, unsigned int class); | |||
270 | extern int policydb_type_isvalid(struct policydb *p, unsigned int type); | 273 | extern int policydb_type_isvalid(struct policydb *p, unsigned int type); |
271 | extern int policydb_role_isvalid(struct policydb *p, unsigned int role); | 274 | extern int policydb_role_isvalid(struct policydb *p, unsigned int role); |
272 | extern int policydb_read(struct policydb *p, void *fp); | 275 | extern int policydb_read(struct policydb *p, void *fp); |
276 | extern int policydb_write(struct policydb *p, void *fp); | ||
273 | 277 | ||
274 | #define PERM_SYMTAB_SIZE 32 | 278 | #define PERM_SYMTAB_SIZE 32 |
275 | 279 | ||
@@ -290,6 +294,11 @@ struct policy_file { | |||
290 | size_t len; | 294 | size_t len; |
291 | }; | 295 | }; |
292 | 296 | ||
297 | struct policy_data { | ||
298 | struct policydb *p; | ||
299 | void *fp; | ||
300 | }; | ||
301 | |||
293 | static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes) | 302 | static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes) |
294 | { | 303 | { |
295 | if (bytes > fp->len) | 304 | if (bytes > fp->len) |
@@ -301,6 +310,17 @@ static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes) | |||
301 | return 0; | 310 | return 0; |
302 | } | 311 | } |
303 | 312 | ||
313 | static inline int put_entry(void *buf, size_t bytes, int num, struct policy_file *fp) | ||
314 | { | ||
315 | size_t len = bytes * num; | ||
316 | |||
317 | memcpy(fp->data, buf, len); | ||
318 | fp->data += len; | ||
319 | fp->len -= len; | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
304 | extern u16 string_to_security_class(struct policydb *p, const char *name); | 324 | extern u16 string_to_security_class(struct policydb *p, const char *name); |
305 | extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name); | 325 | extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name); |
306 | 326 | ||
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 60964d79e5eb..7565d16aac31 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -1776,6 +1776,7 @@ int security_load_policy(void *data, size_t len) | |||
1776 | return rc; | 1776 | return rc; |
1777 | } | 1777 | } |
1778 | 1778 | ||
1779 | policydb.len = len; | ||
1779 | rc = selinux_set_mapping(&policydb, secclass_map, | 1780 | rc = selinux_set_mapping(&policydb, secclass_map, |
1780 | ¤t_mapping, | 1781 | ¤t_mapping, |
1781 | ¤t_mapping_size); | 1782 | ¤t_mapping_size); |
@@ -1812,6 +1813,7 @@ int security_load_policy(void *data, size_t len) | |||
1812 | if (rc) | 1813 | if (rc) |
1813 | return rc; | 1814 | return rc; |
1814 | 1815 | ||
1816 | newpolicydb.len = len; | ||
1815 | /* If switching between different policy types, log MLS status */ | 1817 | /* If switching between different policy types, log MLS status */ |
1816 | if (policydb.mls_enabled && !newpolicydb.mls_enabled) | 1818 | if (policydb.mls_enabled && !newpolicydb.mls_enabled) |
1817 | printk(KERN_INFO "SELinux: Disabling MLS support...\n"); | 1819 | printk(KERN_INFO "SELinux: Disabling MLS support...\n"); |
@@ -1892,6 +1894,17 @@ err: | |||
1892 | 1894 | ||
1893 | } | 1895 | } |
1894 | 1896 | ||
1897 | size_t security_policydb_len(void) | ||
1898 | { | ||
1899 | size_t len; | ||
1900 | |||
1901 | read_lock(&policy_rwlock); | ||
1902 | len = policydb.len; | ||
1903 | read_unlock(&policy_rwlock); | ||
1904 | |||
1905 | return len; | ||
1906 | } | ||
1907 | |||
1895 | /** | 1908 | /** |
1896 | * security_port_sid - Obtain the SID for a port. | 1909 | * security_port_sid - Obtain the SID for a port. |
1897 | * @protocol: protocol number | 1910 | * @protocol: protocol number |
@@ -3139,3 +3152,38 @@ netlbl_sid_to_secattr_failure: | |||
3139 | return rc; | 3152 | return rc; |
3140 | } | 3153 | } |
3141 | #endif /* CONFIG_NETLABEL */ | 3154 | #endif /* CONFIG_NETLABEL */ |
3155 | |||
3156 | /** | ||
3157 | * security_read_policy - read the policy. | ||
3158 | * @data: binary policy data | ||
3159 | * @len: length of data in bytes | ||
3160 | * | ||
3161 | */ | ||
3162 | int security_read_policy(void **data, ssize_t *len) | ||
3163 | { | ||
3164 | int rc; | ||
3165 | struct policy_file fp; | ||
3166 | |||
3167 | if (!ss_initialized) | ||
3168 | return -EINVAL; | ||
3169 | |||
3170 | *len = security_policydb_len(); | ||
3171 | |||
3172 | *data = vmalloc(*len); | ||
3173 | if (!*data) | ||
3174 | return -ENOMEM; | ||
3175 | |||
3176 | fp.data = *data; | ||
3177 | fp.len = *len; | ||
3178 | |||
3179 | read_lock(&policy_rwlock); | ||
3180 | rc = policydb_write(&policydb, &fp); | ||
3181 | read_unlock(&policy_rwlock); | ||
3182 | |||
3183 | if (rc) | ||
3184 | return rc; | ||
3185 | |||
3186 | *len = (unsigned long)fp.data - (unsigned long)*data; | ||
3187 | return 0; | ||
3188 | |||
3189 | } | ||