diff options
Diffstat (limited to 'security/selinux/ss')
-rw-r--r-- | security/selinux/ss/avtab.c | 104 | ||||
-rw-r--r-- | security/selinux/ss/avtab.h | 33 | ||||
-rw-r--r-- | security/selinux/ss/conditional.c | 32 | ||||
-rw-r--r-- | security/selinux/ss/conditional.h | 6 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 5 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 213 | ||||
-rw-r--r-- | security/selinux/ss/services.h | 6 |
7 files changed, 357 insertions, 42 deletions
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index b64f2772b030..3628d3a868b6 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "policydb.h" | 24 | #include "policydb.h" |
25 | 25 | ||
26 | static struct kmem_cache *avtab_node_cachep; | 26 | static struct kmem_cache *avtab_node_cachep; |
27 | static struct kmem_cache *avtab_xperms_cachep; | ||
27 | 28 | ||
28 | /* Based on MurmurHash3, written by Austin Appleby and placed in the | 29 | /* Based on MurmurHash3, written by Austin Appleby and placed in the |
29 | * public domain. | 30 | * public domain. |
@@ -70,11 +71,24 @@ avtab_insert_node(struct avtab *h, int hvalue, | |||
70 | struct avtab_key *key, struct avtab_datum *datum) | 71 | struct avtab_key *key, struct avtab_datum *datum) |
71 | { | 72 | { |
72 | struct avtab_node *newnode; | 73 | struct avtab_node *newnode; |
74 | struct avtab_extended_perms *xperms; | ||
73 | newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL); | 75 | newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL); |
74 | if (newnode == NULL) | 76 | if (newnode == NULL) |
75 | return NULL; | 77 | return NULL; |
76 | newnode->key = *key; | 78 | newnode->key = *key; |
77 | newnode->datum = *datum; | 79 | |
80 | if (key->specified & AVTAB_XPERMS) { | ||
81 | xperms = kmem_cache_zalloc(avtab_xperms_cachep, GFP_KERNEL); | ||
82 | if (xperms == NULL) { | ||
83 | kmem_cache_free(avtab_node_cachep, newnode); | ||
84 | return NULL; | ||
85 | } | ||
86 | *xperms = *(datum->u.xperms); | ||
87 | newnode->datum.u.xperms = xperms; | ||
88 | } else { | ||
89 | newnode->datum.u.data = datum->u.data; | ||
90 | } | ||
91 | |||
78 | if (prev) { | 92 | if (prev) { |
79 | newnode->next = prev->next; | 93 | newnode->next = prev->next; |
80 | prev->next = newnode; | 94 | prev->next = newnode; |
@@ -107,8 +121,12 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat | |||
107 | if (key->source_type == cur->key.source_type && | 121 | if (key->source_type == cur->key.source_type && |
108 | key->target_type == cur->key.target_type && | 122 | key->target_type == cur->key.target_type && |
109 | key->target_class == cur->key.target_class && | 123 | key->target_class == cur->key.target_class && |
110 | (specified & cur->key.specified)) | 124 | (specified & cur->key.specified)) { |
125 | /* extended perms may not be unique */ | ||
126 | if (specified & AVTAB_XPERMS) | ||
127 | break; | ||
111 | return -EEXIST; | 128 | return -EEXIST; |
129 | } | ||
112 | if (key->source_type < cur->key.source_type) | 130 | if (key->source_type < cur->key.source_type) |
113 | break; | 131 | break; |
114 | if (key->source_type == cur->key.source_type && | 132 | if (key->source_type == cur->key.source_type && |
@@ -271,6 +289,9 @@ void avtab_destroy(struct avtab *h) | |||
271 | while (cur) { | 289 | while (cur) { |
272 | temp = cur; | 290 | temp = cur; |
273 | cur = cur->next; | 291 | cur = cur->next; |
292 | if (temp->key.specified & AVTAB_XPERMS) | ||
293 | kmem_cache_free(avtab_xperms_cachep, | ||
294 | temp->datum.u.xperms); | ||
274 | kmem_cache_free(avtab_node_cachep, temp); | 295 | kmem_cache_free(avtab_node_cachep, temp); |
275 | } | 296 | } |
276 | } | 297 | } |
@@ -359,7 +380,10 @@ static uint16_t spec_order[] = { | |||
359 | AVTAB_AUDITALLOW, | 380 | AVTAB_AUDITALLOW, |
360 | AVTAB_TRANSITION, | 381 | AVTAB_TRANSITION, |
361 | AVTAB_CHANGE, | 382 | AVTAB_CHANGE, |
362 | AVTAB_MEMBER | 383 | AVTAB_MEMBER, |
384 | AVTAB_XPERMS_ALLOWED, | ||
385 | AVTAB_XPERMS_AUDITALLOW, | ||
386 | AVTAB_XPERMS_DONTAUDIT | ||
363 | }; | 387 | }; |
364 | 388 | ||
365 | int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, | 389 | int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, |
@@ -369,10 +393,11 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, | |||
369 | { | 393 | { |
370 | __le16 buf16[4]; | 394 | __le16 buf16[4]; |
371 | u16 enabled; | 395 | u16 enabled; |
372 | __le32 buf32[7]; | ||
373 | u32 items, items2, val, vers = pol->policyvers; | 396 | u32 items, items2, val, vers = pol->policyvers; |
374 | struct avtab_key key; | 397 | struct avtab_key key; |
375 | struct avtab_datum datum; | 398 | struct avtab_datum datum; |
399 | struct avtab_extended_perms xperms; | ||
400 | __le32 buf32[ARRAY_SIZE(xperms.perms.p)]; | ||
376 | int i, rc; | 401 | int i, rc; |
377 | unsigned set; | 402 | unsigned set; |
378 | 403 | ||
@@ -429,11 +454,15 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, | |||
429 | printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n"); | 454 | printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n"); |
430 | return -EINVAL; | 455 | return -EINVAL; |
431 | } | 456 | } |
457 | if (val & AVTAB_XPERMS) { | ||
458 | printk(KERN_ERR "SELinux: avtab: entry has extended permissions\n"); | ||
459 | return -EINVAL; | ||
460 | } | ||
432 | 461 | ||
433 | for (i = 0; i < ARRAY_SIZE(spec_order); i++) { | 462 | for (i = 0; i < ARRAY_SIZE(spec_order); i++) { |
434 | if (val & spec_order[i]) { | 463 | if (val & spec_order[i]) { |
435 | key.specified = spec_order[i] | enabled; | 464 | key.specified = spec_order[i] | enabled; |
436 | datum.data = le32_to_cpu(buf32[items++]); | 465 | datum.u.data = le32_to_cpu(buf32[items++]); |
437 | rc = insertf(a, &key, &datum, p); | 466 | rc = insertf(a, &key, &datum, p); |
438 | if (rc) | 467 | if (rc) |
439 | return rc; | 468 | return rc; |
@@ -476,14 +505,42 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, | |||
476 | return -EINVAL; | 505 | return -EINVAL; |
477 | } | 506 | } |
478 | 507 | ||
479 | rc = next_entry(buf32, fp, sizeof(u32)); | 508 | if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) && |
480 | if (rc) { | 509 | (key.specified & AVTAB_XPERMS)) { |
481 | printk(KERN_ERR "SELinux: avtab: truncated entry\n"); | 510 | printk(KERN_ERR "SELinux: avtab: policy version %u does not " |
482 | return rc; | 511 | "support extended permissions rules and one " |
512 | "was specified\n", vers); | ||
513 | return -EINVAL; | ||
514 | } else if (key.specified & AVTAB_XPERMS) { | ||
515 | memset(&xperms, 0, sizeof(struct avtab_extended_perms)); | ||
516 | rc = next_entry(&xperms.specified, fp, sizeof(u8)); | ||
517 | if (rc) { | ||
518 | printk(KERN_ERR "SELinux: avtab: truncated entry\n"); | ||
519 | return rc; | ||
520 | } | ||
521 | rc = next_entry(&xperms.driver, fp, sizeof(u8)); | ||
522 | if (rc) { | ||
523 | printk(KERN_ERR "SELinux: avtab: truncated entry\n"); | ||
524 | return rc; | ||
525 | } | ||
526 | rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(xperms.perms.p)); | ||
527 | if (rc) { | ||
528 | printk(KERN_ERR "SELinux: avtab: truncated entry\n"); | ||
529 | return rc; | ||
530 | } | ||
531 | for (i = 0; i < ARRAY_SIZE(xperms.perms.p); i++) | ||
532 | xperms.perms.p[i] = le32_to_cpu(buf32[i]); | ||
533 | datum.u.xperms = &xperms; | ||
534 | } else { | ||
535 | rc = next_entry(buf32, fp, sizeof(u32)); | ||
536 | if (rc) { | ||
537 | printk(KERN_ERR "SELinux: avtab: truncated entry\n"); | ||
538 | return rc; | ||
539 | } | ||
540 | datum.u.data = le32_to_cpu(*buf32); | ||
483 | } | 541 | } |
484 | datum.data = le32_to_cpu(*buf32); | ||
485 | if ((key.specified & AVTAB_TYPE) && | 542 | if ((key.specified & AVTAB_TYPE) && |
486 | !policydb_type_isvalid(pol, datum.data)) { | 543 | !policydb_type_isvalid(pol, datum.u.data)) { |
487 | printk(KERN_ERR "SELinux: avtab: invalid type\n"); | 544 | printk(KERN_ERR "SELinux: avtab: invalid type\n"); |
488 | return -EINVAL; | 545 | return -EINVAL; |
489 | } | 546 | } |
@@ -543,8 +600,9 @@ bad: | |||
543 | int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) | 600 | int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) |
544 | { | 601 | { |
545 | __le16 buf16[4]; | 602 | __le16 buf16[4]; |
546 | __le32 buf32[1]; | 603 | __le32 buf32[ARRAY_SIZE(cur->datum.u.xperms->perms.p)]; |
547 | int rc; | 604 | int rc; |
605 | unsigned int i; | ||
548 | 606 | ||
549 | buf16[0] = cpu_to_le16(cur->key.source_type); | 607 | buf16[0] = cpu_to_le16(cur->key.source_type); |
550 | buf16[1] = cpu_to_le16(cur->key.target_type); | 608 | buf16[1] = cpu_to_le16(cur->key.target_type); |
@@ -553,8 +611,22 @@ int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) | |||
553 | rc = put_entry(buf16, sizeof(u16), 4, fp); | 611 | rc = put_entry(buf16, sizeof(u16), 4, fp); |
554 | if (rc) | 612 | if (rc) |
555 | return rc; | 613 | return rc; |
556 | buf32[0] = cpu_to_le32(cur->datum.data); | 614 | |
557 | rc = put_entry(buf32, sizeof(u32), 1, fp); | 615 | if (cur->key.specified & AVTAB_XPERMS) { |
616 | rc = put_entry(&cur->datum.u.xperms->specified, sizeof(u8), 1, fp); | ||
617 | if (rc) | ||
618 | return rc; | ||
619 | rc = put_entry(&cur->datum.u.xperms->driver, sizeof(u8), 1, fp); | ||
620 | if (rc) | ||
621 | return rc; | ||
622 | for (i = 0; i < ARRAY_SIZE(cur->datum.u.xperms->perms.p); i++) | ||
623 | buf32[i] = cpu_to_le32(cur->datum.u.xperms->perms.p[i]); | ||
624 | rc = put_entry(buf32, sizeof(u32), | ||
625 | ARRAY_SIZE(cur->datum.u.xperms->perms.p), fp); | ||
626 | } else { | ||
627 | buf32[0] = cpu_to_le32(cur->datum.u.data); | ||
628 | rc = put_entry(buf32, sizeof(u32), 1, fp); | ||
629 | } | ||
558 | if (rc) | 630 | if (rc) |
559 | return rc; | 631 | return rc; |
560 | return 0; | 632 | return 0; |
@@ -588,9 +660,13 @@ void avtab_cache_init(void) | |||
588 | avtab_node_cachep = kmem_cache_create("avtab_node", | 660 | avtab_node_cachep = kmem_cache_create("avtab_node", |
589 | sizeof(struct avtab_node), | 661 | sizeof(struct avtab_node), |
590 | 0, SLAB_PANIC, NULL); | 662 | 0, SLAB_PANIC, NULL); |
663 | avtab_xperms_cachep = kmem_cache_create("avtab_extended_perms", | ||
664 | sizeof(struct avtab_extended_perms), | ||
665 | 0, SLAB_PANIC, NULL); | ||
591 | } | 666 | } |
592 | 667 | ||
593 | void avtab_cache_destroy(void) | 668 | void avtab_cache_destroy(void) |
594 | { | 669 | { |
595 | kmem_cache_destroy(avtab_node_cachep); | 670 | kmem_cache_destroy(avtab_node_cachep); |
671 | kmem_cache_destroy(avtab_xperms_cachep); | ||
596 | } | 672 | } |
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index adb451cd44f9..d946c9dc3c9c 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #ifndef _SS_AVTAB_H_ | 23 | #ifndef _SS_AVTAB_H_ |
24 | #define _SS_AVTAB_H_ | 24 | #define _SS_AVTAB_H_ |
25 | 25 | ||
26 | #include "security.h" | ||
26 | #include <linux/flex_array.h> | 27 | #include <linux/flex_array.h> |
27 | 28 | ||
28 | struct avtab_key { | 29 | struct avtab_key { |
@@ -37,13 +38,43 @@ struct avtab_key { | |||
37 | #define AVTAB_MEMBER 0x0020 | 38 | #define AVTAB_MEMBER 0x0020 |
38 | #define AVTAB_CHANGE 0x0040 | 39 | #define AVTAB_CHANGE 0x0040 |
39 | #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) | 40 | #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) |
41 | /* extended permissions */ | ||
42 | #define AVTAB_XPERMS_ALLOWED 0x0100 | ||
43 | #define AVTAB_XPERMS_AUDITALLOW 0x0200 | ||
44 | #define AVTAB_XPERMS_DONTAUDIT 0x0400 | ||
45 | #define AVTAB_XPERMS (AVTAB_XPERMS_ALLOWED | \ | ||
46 | AVTAB_XPERMS_AUDITALLOW | \ | ||
47 | AVTAB_XPERMS_DONTAUDIT) | ||
40 | #define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ | 48 | #define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ |
41 | #define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ | 49 | #define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ |
42 | u16 specified; /* what field is specified */ | 50 | u16 specified; /* what field is specified */ |
43 | }; | 51 | }; |
44 | 52 | ||
53 | /* | ||
54 | * For operations that require more than the 32 permissions provided by the avc | ||
55 | * extended permissions may be used to provide 256 bits of permissions. | ||
56 | */ | ||
57 | struct avtab_extended_perms { | ||
58 | /* These are not flags. All 256 values may be used */ | ||
59 | #define AVTAB_XPERMS_IOCTLFUNCTION 0x01 | ||
60 | #define AVTAB_XPERMS_IOCTLDRIVER 0x02 | ||
61 | /* extension of the avtab_key specified */ | ||
62 | u8 specified; /* ioctl, netfilter, ... */ | ||
63 | /* | ||
64 | * if 256 bits is not adequate as is often the case with ioctls, then | ||
65 | * multiple extended perms may be used and the driver field | ||
66 | * specifies which permissions are included. | ||
67 | */ | ||
68 | u8 driver; | ||
69 | /* 256 bits of permissions */ | ||
70 | struct extended_perms_data perms; | ||
71 | }; | ||
72 | |||
45 | struct avtab_datum { | 73 | struct avtab_datum { |
46 | u32 data; /* access vector or type value */ | 74 | union { |
75 | u32 data; /* access vector or type value */ | ||
76 | struct avtab_extended_perms *xperms; | ||
77 | } u; | ||
47 | }; | 78 | }; |
48 | 79 | ||
49 | struct avtab_node { | 80 | struct avtab_node { |
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 62c6773be0b7..18643bf9894d 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c | |||
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | #include "security.h" | 16 | #include "security.h" |
17 | #include "conditional.h" | 17 | #include "conditional.h" |
18 | #include "services.h" | ||
18 | 19 | ||
19 | /* | 20 | /* |
20 | * cond_evaluate_expr evaluates a conditional expr | 21 | * cond_evaluate_expr evaluates a conditional expr |
@@ -612,21 +613,39 @@ int cond_write_list(struct policydb *p, struct cond_node *list, void *fp) | |||
612 | 613 | ||
613 | return 0; | 614 | return 0; |
614 | } | 615 | } |
616 | |||
617 | void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, | ||
618 | struct extended_perms_decision *xpermd) | ||
619 | { | ||
620 | struct avtab_node *node; | ||
621 | |||
622 | if (!ctab || !key || !xpermd) | ||
623 | return; | ||
624 | |||
625 | for (node = avtab_search_node(ctab, key); node; | ||
626 | node = avtab_search_node_next(node, key->specified)) { | ||
627 | if (node->key.specified & AVTAB_ENABLED) | ||
628 | services_compute_xperms_decision(xpermd, node); | ||
629 | } | ||
630 | return; | ||
631 | |||
632 | } | ||
615 | /* Determine whether additional permissions are granted by the conditional | 633 | /* Determine whether additional permissions are granted by the conditional |
616 | * av table, and if so, add them to the result | 634 | * av table, and if so, add them to the result |
617 | */ | 635 | */ |
618 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd) | 636 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, |
637 | struct av_decision *avd, struct extended_perms *xperms) | ||
619 | { | 638 | { |
620 | struct avtab_node *node; | 639 | struct avtab_node *node; |
621 | 640 | ||
622 | if (!ctab || !key || !avd) | 641 | if (!ctab || !key || !avd || !xperms) |
623 | return; | 642 | return; |
624 | 643 | ||
625 | for (node = avtab_search_node(ctab, key); node; | 644 | for (node = avtab_search_node(ctab, key); node; |
626 | node = avtab_search_node_next(node, key->specified)) { | 645 | node = avtab_search_node_next(node, key->specified)) { |
627 | if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == | 646 | if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == |
628 | (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) | 647 | (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) |
629 | avd->allowed |= node->datum.data; | 648 | avd->allowed |= node->datum.u.data; |
630 | if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) == | 649 | if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) == |
631 | (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) | 650 | (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) |
632 | /* Since a '0' in an auditdeny mask represents a | 651 | /* Since a '0' in an auditdeny mask represents a |
@@ -634,10 +653,13 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decisi | |||
634 | * the '&' operand to ensure that all '0's in the mask | 653 | * the '&' operand to ensure that all '0's in the mask |
635 | * are retained (much unlike the allow and auditallow cases). | 654 | * are retained (much unlike the allow and auditallow cases). |
636 | */ | 655 | */ |
637 | avd->auditdeny &= node->datum.data; | 656 | avd->auditdeny &= node->datum.u.data; |
638 | if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) == | 657 | if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) == |
639 | (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) | 658 | (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) |
640 | avd->auditallow |= node->datum.data; | 659 | avd->auditallow |= node->datum.u.data; |
660 | if ((node->key.specified & AVTAB_ENABLED) && | ||
661 | (node->key.specified & AVTAB_XPERMS)) | ||
662 | services_compute_xperms_drivers(xperms, node); | ||
641 | } | 663 | } |
642 | return; | 664 | return; |
643 | } | 665 | } |
diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h index 4d1f87466508..ddb43e7e1c75 100644 --- a/security/selinux/ss/conditional.h +++ b/security/selinux/ss/conditional.h | |||
@@ -73,8 +73,10 @@ int cond_read_list(struct policydb *p, void *fp); | |||
73 | int cond_write_bool(void *key, void *datum, void *ptr); | 73 | int cond_write_bool(void *key, void *datum, void *ptr); |
74 | int cond_write_list(struct policydb *p, struct cond_node *list, void *fp); | 74 | int cond_write_list(struct policydb *p, struct cond_node *list, void *fp); |
75 | 75 | ||
76 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd); | 76 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, |
77 | 77 | struct av_decision *avd, struct extended_perms *xperms); | |
78 | void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, | ||
79 | struct extended_perms_decision *xpermd); | ||
78 | int evaluate_cond_node(struct policydb *p, struct cond_node *node); | 80 | int evaluate_cond_node(struct policydb *p, struct cond_node *node); |
79 | 81 | ||
80 | #endif /* _CONDITIONAL_H_ */ | 82 | #endif /* _CONDITIONAL_H_ */ |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 74aa224267c1..992a31530825 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -148,6 +148,11 @@ static struct policydb_compat_info policydb_compat[] = { | |||
148 | .sym_num = SYM_NUM, | 148 | .sym_num = SYM_NUM, |
149 | .ocon_num = OCON_NUM, | 149 | .ocon_num = OCON_NUM, |
150 | }, | 150 | }, |
151 | { | ||
152 | .version = POLICYDB_VERSION_XPERMS_IOCTL, | ||
153 | .sym_num = SYM_NUM, | ||
154 | .ocon_num = OCON_NUM, | ||
155 | }, | ||
151 | }; | 156 | }; |
152 | 157 | ||
153 | static struct policydb_compat_info *policydb_lookup_compat(int version) | 158 | static struct policydb_compat_info *policydb_lookup_compat(int version) |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 9e2d82070915..b7df12ba61d8 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -93,9 +93,10 @@ static int context_struct_to_string(struct context *context, char **scontext, | |||
93 | u32 *scontext_len); | 93 | u32 *scontext_len); |
94 | 94 | ||
95 | static void context_struct_compute_av(struct context *scontext, | 95 | static void context_struct_compute_av(struct context *scontext, |
96 | struct context *tcontext, | 96 | struct context *tcontext, |
97 | u16 tclass, | 97 | u16 tclass, |
98 | struct av_decision *avd); | 98 | struct av_decision *avd, |
99 | struct extended_perms *xperms); | ||
99 | 100 | ||
100 | struct selinux_mapping { | 101 | struct selinux_mapping { |
101 | u16 value; /* policy value */ | 102 | u16 value; /* policy value */ |
@@ -565,7 +566,8 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
565 | context_struct_compute_av(&lo_scontext, | 566 | context_struct_compute_av(&lo_scontext, |
566 | tcontext, | 567 | tcontext, |
567 | tclass, | 568 | tclass, |
568 | &lo_avd); | 569 | &lo_avd, |
570 | NULL); | ||
569 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 571 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
570 | return; /* no masked permission */ | 572 | return; /* no masked permission */ |
571 | masked = ~lo_avd.allowed & avd->allowed; | 573 | masked = ~lo_avd.allowed & avd->allowed; |
@@ -580,7 +582,8 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
580 | context_struct_compute_av(scontext, | 582 | context_struct_compute_av(scontext, |
581 | &lo_tcontext, | 583 | &lo_tcontext, |
582 | tclass, | 584 | tclass, |
583 | &lo_avd); | 585 | &lo_avd, |
586 | NULL); | ||
584 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 587 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
585 | return; /* no masked permission */ | 588 | return; /* no masked permission */ |
586 | masked = ~lo_avd.allowed & avd->allowed; | 589 | masked = ~lo_avd.allowed & avd->allowed; |
@@ -596,7 +599,8 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
596 | context_struct_compute_av(&lo_scontext, | 599 | context_struct_compute_av(&lo_scontext, |
597 | &lo_tcontext, | 600 | &lo_tcontext, |
598 | tclass, | 601 | tclass, |
599 | &lo_avd); | 602 | &lo_avd, |
603 | NULL); | ||
600 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 604 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
601 | return; /* no masked permission */ | 605 | return; /* no masked permission */ |
602 | masked = ~lo_avd.allowed & avd->allowed; | 606 | masked = ~lo_avd.allowed & avd->allowed; |
@@ -613,13 +617,39 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
613 | } | 617 | } |
614 | 618 | ||
615 | /* | 619 | /* |
616 | * Compute access vectors based on a context structure pair for | 620 | * flag which drivers have permissions |
617 | * the permissions in a particular class. | 621 | * only looking for ioctl based extended permssions |
622 | */ | ||
623 | void services_compute_xperms_drivers( | ||
624 | struct extended_perms *xperms, | ||
625 | struct avtab_node *node) | ||
626 | { | ||
627 | unsigned int i; | ||
628 | |||
629 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { | ||
630 | /* if one or more driver has all permissions allowed */ | ||
631 | for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++) | ||
632 | xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i]; | ||
633 | } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { | ||
634 | /* if allowing permissions within a driver */ | ||
635 | security_xperm_set(xperms->drivers.p, | ||
636 | node->datum.u.xperms->driver); | ||
637 | } | ||
638 | |||
639 | /* If no ioctl commands are allowed, ignore auditallow and auditdeny */ | ||
640 | if (node->key.specified & AVTAB_XPERMS_ALLOWED) | ||
641 | xperms->len = 1; | ||
642 | } | ||
643 | |||
644 | /* | ||
645 | * Compute access vectors and extended permissions based on a context | ||
646 | * structure pair for the permissions in a particular class. | ||
618 | */ | 647 | */ |
619 | static void context_struct_compute_av(struct context *scontext, | 648 | static void context_struct_compute_av(struct context *scontext, |
620 | struct context *tcontext, | 649 | struct context *tcontext, |
621 | u16 tclass, | 650 | u16 tclass, |
622 | struct av_decision *avd) | 651 | struct av_decision *avd, |
652 | struct extended_perms *xperms) | ||
623 | { | 653 | { |
624 | struct constraint_node *constraint; | 654 | struct constraint_node *constraint; |
625 | struct role_allow *ra; | 655 | struct role_allow *ra; |
@@ -633,6 +663,10 @@ static void context_struct_compute_av(struct context *scontext, | |||
633 | avd->allowed = 0; | 663 | avd->allowed = 0; |
634 | avd->auditallow = 0; | 664 | avd->auditallow = 0; |
635 | avd->auditdeny = 0xffffffff; | 665 | avd->auditdeny = 0xffffffff; |
666 | if (xperms) { | ||
667 | memset(&xperms->drivers, 0, sizeof(xperms->drivers)); | ||
668 | xperms->len = 0; | ||
669 | } | ||
636 | 670 | ||
637 | if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { | 671 | if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { |
638 | if (printk_ratelimit()) | 672 | if (printk_ratelimit()) |
@@ -647,7 +681,7 @@ static void context_struct_compute_av(struct context *scontext, | |||
647 | * this permission check, then use it. | 681 | * this permission check, then use it. |
648 | */ | 682 | */ |
649 | avkey.target_class = tclass; | 683 | avkey.target_class = tclass; |
650 | avkey.specified = AVTAB_AV; | 684 | avkey.specified = AVTAB_AV | AVTAB_XPERMS; |
651 | sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); | 685 | sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); |
652 | BUG_ON(!sattr); | 686 | BUG_ON(!sattr); |
653 | tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1); | 687 | tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1); |
@@ -660,15 +694,18 @@ static void context_struct_compute_av(struct context *scontext, | |||
660 | node; | 694 | node; |
661 | node = avtab_search_node_next(node, avkey.specified)) { | 695 | node = avtab_search_node_next(node, avkey.specified)) { |
662 | if (node->key.specified == AVTAB_ALLOWED) | 696 | if (node->key.specified == AVTAB_ALLOWED) |
663 | avd->allowed |= node->datum.data; | 697 | avd->allowed |= node->datum.u.data; |
664 | else if (node->key.specified == AVTAB_AUDITALLOW) | 698 | else if (node->key.specified == AVTAB_AUDITALLOW) |
665 | avd->auditallow |= node->datum.data; | 699 | avd->auditallow |= node->datum.u.data; |
666 | else if (node->key.specified == AVTAB_AUDITDENY) | 700 | else if (node->key.specified == AVTAB_AUDITDENY) |
667 | avd->auditdeny &= node->datum.data; | 701 | avd->auditdeny &= node->datum.u.data; |
702 | else if (xperms && (node->key.specified & AVTAB_XPERMS)) | ||
703 | services_compute_xperms_drivers(xperms, node); | ||
668 | } | 704 | } |
669 | 705 | ||
670 | /* Check conditional av table for additional permissions */ | 706 | /* Check conditional av table for additional permissions */ |
671 | cond_compute_av(&policydb.te_cond_avtab, &avkey, avd); | 707 | cond_compute_av(&policydb.te_cond_avtab, &avkey, |
708 | avd, xperms); | ||
672 | 709 | ||
673 | } | 710 | } |
674 | } | 711 | } |
@@ -899,6 +936,139 @@ static void avd_init(struct av_decision *avd) | |||
899 | avd->flags = 0; | 936 | avd->flags = 0; |
900 | } | 937 | } |
901 | 938 | ||
939 | void services_compute_xperms_decision(struct extended_perms_decision *xpermd, | ||
940 | struct avtab_node *node) | ||
941 | { | ||
942 | unsigned int i; | ||
943 | |||
944 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { | ||
945 | if (xpermd->driver != node->datum.u.xperms->driver) | ||
946 | return; | ||
947 | } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { | ||
948 | if (!security_xperm_test(node->datum.u.xperms->perms.p, | ||
949 | xpermd->driver)) | ||
950 | return; | ||
951 | } else { | ||
952 | BUG(); | ||
953 | } | ||
954 | |||
955 | if (node->key.specified == AVTAB_XPERMS_ALLOWED) { | ||
956 | xpermd->used |= XPERMS_ALLOWED; | ||
957 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { | ||
958 | memset(xpermd->allowed->p, 0xff, | ||
959 | sizeof(xpermd->allowed->p)); | ||
960 | } | ||
961 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { | ||
962 | for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++) | ||
963 | xpermd->allowed->p[i] |= | ||
964 | node->datum.u.xperms->perms.p[i]; | ||
965 | } | ||
966 | } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) { | ||
967 | xpermd->used |= XPERMS_AUDITALLOW; | ||
968 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { | ||
969 | memset(xpermd->auditallow->p, 0xff, | ||
970 | sizeof(xpermd->auditallow->p)); | ||
971 | } | ||
972 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { | ||
973 | for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++) | ||
974 | xpermd->auditallow->p[i] |= | ||
975 | node->datum.u.xperms->perms.p[i]; | ||
976 | } | ||
977 | } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) { | ||
978 | xpermd->used |= XPERMS_DONTAUDIT; | ||
979 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { | ||
980 | memset(xpermd->dontaudit->p, 0xff, | ||
981 | sizeof(xpermd->dontaudit->p)); | ||
982 | } | ||
983 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { | ||
984 | for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++) | ||
985 | xpermd->dontaudit->p[i] |= | ||
986 | node->datum.u.xperms->perms.p[i]; | ||
987 | } | ||
988 | } else { | ||
989 | BUG(); | ||
990 | } | ||
991 | } | ||
992 | |||
993 | void security_compute_xperms_decision(u32 ssid, | ||
994 | u32 tsid, | ||
995 | u16 orig_tclass, | ||
996 | u8 driver, | ||
997 | struct extended_perms_decision *xpermd) | ||
998 | { | ||
999 | u16 tclass; | ||
1000 | struct context *scontext, *tcontext; | ||
1001 | struct avtab_key avkey; | ||
1002 | struct avtab_node *node; | ||
1003 | struct ebitmap *sattr, *tattr; | ||
1004 | struct ebitmap_node *snode, *tnode; | ||
1005 | unsigned int i, j; | ||
1006 | |||
1007 | xpermd->driver = driver; | ||
1008 | xpermd->used = 0; | ||
1009 | memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p)); | ||
1010 | memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p)); | ||
1011 | memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p)); | ||
1012 | |||
1013 | read_lock(&policy_rwlock); | ||
1014 | if (!ss_initialized) | ||
1015 | goto allow; | ||
1016 | |||
1017 | scontext = sidtab_search(&sidtab, ssid); | ||
1018 | if (!scontext) { | ||
1019 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
1020 | __func__, ssid); | ||
1021 | goto out; | ||
1022 | } | ||
1023 | |||
1024 | tcontext = sidtab_search(&sidtab, tsid); | ||
1025 | if (!tcontext) { | ||
1026 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
1027 | __func__, tsid); | ||
1028 | goto out; | ||
1029 | } | ||
1030 | |||
1031 | tclass = unmap_class(orig_tclass); | ||
1032 | if (unlikely(orig_tclass && !tclass)) { | ||
1033 | if (policydb.allow_unknown) | ||
1034 | goto allow; | ||
1035 | goto out; | ||
1036 | } | ||
1037 | |||
1038 | |||
1039 | if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { | ||
1040 | pr_warn_ratelimited("SELinux: Invalid class %hu\n", tclass); | ||
1041 | goto out; | ||
1042 | } | ||
1043 | |||
1044 | avkey.target_class = tclass; | ||
1045 | avkey.specified = AVTAB_XPERMS; | ||
1046 | sattr = flex_array_get(policydb.type_attr_map_array, | ||
1047 | scontext->type - 1); | ||
1048 | BUG_ON(!sattr); | ||
1049 | tattr = flex_array_get(policydb.type_attr_map_array, | ||
1050 | tcontext->type - 1); | ||
1051 | BUG_ON(!tattr); | ||
1052 | ebitmap_for_each_positive_bit(sattr, snode, i) { | ||
1053 | ebitmap_for_each_positive_bit(tattr, tnode, j) { | ||
1054 | avkey.source_type = i + 1; | ||
1055 | avkey.target_type = j + 1; | ||
1056 | for (node = avtab_search_node(&policydb.te_avtab, &avkey); | ||
1057 | node; | ||
1058 | node = avtab_search_node_next(node, avkey.specified)) | ||
1059 | services_compute_xperms_decision(xpermd, node); | ||
1060 | |||
1061 | cond_compute_xperms(&policydb.te_cond_avtab, | ||
1062 | &avkey, xpermd); | ||
1063 | } | ||
1064 | } | ||
1065 | out: | ||
1066 | read_unlock(&policy_rwlock); | ||
1067 | return; | ||
1068 | allow: | ||
1069 | memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p)); | ||
1070 | goto out; | ||
1071 | } | ||
902 | 1072 | ||
903 | /** | 1073 | /** |
904 | * security_compute_av - Compute access vector decisions. | 1074 | * security_compute_av - Compute access vector decisions. |
@@ -906,6 +1076,7 @@ static void avd_init(struct av_decision *avd) | |||
906 | * @tsid: target security identifier | 1076 | * @tsid: target security identifier |
907 | * @tclass: target security class | 1077 | * @tclass: target security class |
908 | * @avd: access vector decisions | 1078 | * @avd: access vector decisions |
1079 | * @xperms: extended permissions | ||
909 | * | 1080 | * |
910 | * Compute a set of access vector decisions based on the | 1081 | * Compute a set of access vector decisions based on the |
911 | * SID pair (@ssid, @tsid) for the permissions in @tclass. | 1082 | * SID pair (@ssid, @tsid) for the permissions in @tclass. |
@@ -913,13 +1084,15 @@ static void avd_init(struct av_decision *avd) | |||
913 | void security_compute_av(u32 ssid, | 1084 | void security_compute_av(u32 ssid, |
914 | u32 tsid, | 1085 | u32 tsid, |
915 | u16 orig_tclass, | 1086 | u16 orig_tclass, |
916 | struct av_decision *avd) | 1087 | struct av_decision *avd, |
1088 | struct extended_perms *xperms) | ||
917 | { | 1089 | { |
918 | u16 tclass; | 1090 | u16 tclass; |
919 | struct context *scontext = NULL, *tcontext = NULL; | 1091 | struct context *scontext = NULL, *tcontext = NULL; |
920 | 1092 | ||
921 | read_lock(&policy_rwlock); | 1093 | read_lock(&policy_rwlock); |
922 | avd_init(avd); | 1094 | avd_init(avd); |
1095 | xperms->len = 0; | ||
923 | if (!ss_initialized) | 1096 | if (!ss_initialized) |
924 | goto allow; | 1097 | goto allow; |
925 | 1098 | ||
@@ -947,7 +1120,7 @@ void security_compute_av(u32 ssid, | |||
947 | goto allow; | 1120 | goto allow; |
948 | goto out; | 1121 | goto out; |
949 | } | 1122 | } |
950 | context_struct_compute_av(scontext, tcontext, tclass, avd); | 1123 | context_struct_compute_av(scontext, tcontext, tclass, avd, xperms); |
951 | map_decision(orig_tclass, avd, policydb.allow_unknown); | 1124 | map_decision(orig_tclass, avd, policydb.allow_unknown); |
952 | out: | 1125 | out: |
953 | read_unlock(&policy_rwlock); | 1126 | read_unlock(&policy_rwlock); |
@@ -993,7 +1166,7 @@ void security_compute_av_user(u32 ssid, | |||
993 | goto out; | 1166 | goto out; |
994 | } | 1167 | } |
995 | 1168 | ||
996 | context_struct_compute_av(scontext, tcontext, tclass, avd); | 1169 | context_struct_compute_av(scontext, tcontext, tclass, avd, NULL); |
997 | out: | 1170 | out: |
998 | read_unlock(&policy_rwlock); | 1171 | read_unlock(&policy_rwlock); |
999 | return; | 1172 | return; |
@@ -1515,7 +1688,7 @@ static int security_compute_sid(u32 ssid, | |||
1515 | 1688 | ||
1516 | if (avdatum) { | 1689 | if (avdatum) { |
1517 | /* Use the type from the type transition/member/change rule. */ | 1690 | /* Use the type from the type transition/member/change rule. */ |
1518 | newcontext.type = avdatum->data; | 1691 | newcontext.type = avdatum->u.data; |
1519 | } | 1692 | } |
1520 | 1693 | ||
1521 | /* if we have a objname this is a file trans check so check those rules */ | 1694 | /* if we have a objname this is a file trans check so check those rules */ |
diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h index e8d907e903cd..6abcd8729ec3 100644 --- a/security/selinux/ss/services.h +++ b/security/selinux/ss/services.h | |||
@@ -11,5 +11,11 @@ | |||
11 | 11 | ||
12 | extern struct policydb policydb; | 12 | extern struct policydb policydb; |
13 | 13 | ||
14 | void services_compute_xperms_drivers(struct extended_perms *xperms, | ||
15 | struct avtab_node *node); | ||
16 | |||
17 | void services_compute_xperms_decision(struct extended_perms_decision *xpermd, | ||
18 | struct avtab_node *node); | ||
19 | |||
14 | #endif /* _SS_SERVICES_H_ */ | 20 | #endif /* _SS_SERVICES_H_ */ |
15 | 21 | ||