summaryrefslogtreecommitdiffstats
path: root/security/selinux/ss
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/ss')
-rw-r--r--security/selinux/ss/avtab.c104
-rw-r--r--security/selinux/ss/avtab.h33
-rw-r--r--security/selinux/ss/conditional.c32
-rw-r--r--security/selinux/ss/conditional.h6
-rw-r--r--security/selinux/ss/policydb.c5
-rw-r--r--security/selinux/ss/services.c213
-rw-r--r--security/selinux/ss/services.h6
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
26static struct kmem_cache *avtab_node_cachep; 26static struct kmem_cache *avtab_node_cachep;
27static 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
365int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, 389int 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:
543int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) 600int 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
593void avtab_cache_destroy(void) 668void 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
28struct avtab_key { 29struct 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 */
57struct 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
45struct avtab_datum { 73struct 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
49struct avtab_node { 80struct 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
617void 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 */
618void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd) 636void 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);
73int cond_write_bool(void *key, void *datum, void *ptr); 73int cond_write_bool(void *key, void *datum, void *ptr);
74int cond_write_list(struct policydb *p, struct cond_node *list, void *fp); 74int cond_write_list(struct policydb *p, struct cond_node *list, void *fp);
75 75
76void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd); 76void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
77 77 struct av_decision *avd, struct extended_perms *xperms);
78void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
79 struct extended_perms_decision *xpermd);
78int evaluate_cond_node(struct policydb *p, struct cond_node *node); 80int 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
153static struct policydb_compat_info *policydb_lookup_compat(int version) 158static 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
95static void context_struct_compute_av(struct context *scontext, 95static 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
100struct selinux_mapping { 101struct 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 */
623void 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 */
619static void context_struct_compute_av(struct context *scontext, 648static 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
939void 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
993void 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 }
1065out:
1066 read_unlock(&policy_rwlock);
1067 return;
1068allow:
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)
913void security_compute_av(u32 ssid, 1084void 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);
952out: 1125out:
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
12extern struct policydb policydb; 12extern struct policydb policydb;
13 13
14void services_compute_xperms_drivers(struct extended_perms *xperms,
15 struct avtab_node *node);
16
17void 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