aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorStephen Smalley <sds@tycho.nsa.gov>2010-01-14 17:28:10 -0500
committerJames Morris <jmorris@namei.org>2010-01-17 17:54:26 -0500
commit19439d05b88dafc4e55d9ffce84ccc27cf8b2bcc (patch)
treee529e1bbba49f30684c3b88a67df1d62ba3e11b1 /security
parent8d9525048c74786205b99f3fcd05a839721edfb7 (diff)
selinux: change the handling of unknown classes
If allow_unknown==deny, SELinux treats an undefined kernel security class as an error condition rather than as a typical permission denial and thus does not allow permissions on undefined classes even when in permissive mode. Change the SELinux logic so that this case is handled as a typical permission denial, subject to the usual permissive mode and permissive domain handling. Also drop the 'requested' argument from security_compute_av() and helpers as it is a legacy of the original security server interface and is unused. Changes: - Handle permissive domains consistently by moving up the test for a permissive domain. - Make security_compute_av_user() consistent with security_compute_av(); the only difference now is that security_compute_av() performs mapping between the kernel-private class and permission indices and the policy values. In the userspace case, this mapping is handled by libselinux. - Moved avd_init inside the policy lock. Based in part on a patch by Paul Moore <paul.moore@hp.com>. Reported-by: Andrew Worsley <amworsley@gmail.com> Signed-off-by: Stephen D. Smalley <sds@tycho.nsa.gov> Reviewed-by: Paul Moore <paul.moore@hp.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security')
-rw-r--r--security/selinux/avc.c5
-rw-r--r--security/selinux/include/security.h10
-rw-r--r--security/selinux/selinuxfs.c7
-rw-r--r--security/selinux/ss/services.c186
4 files changed, 88 insertions, 120 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index f2dde268165a..3ee9b6a8beb6 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -746,9 +746,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
746 else 746 else
747 avd = &avd_entry; 747 avd = &avd_entry;
748 748
749 rc = security_compute_av(ssid, tsid, tclass, requested, avd); 749 security_compute_av(ssid, tsid, tclass, avd);
750 if (rc)
751 goto out;
752 rcu_read_lock(); 750 rcu_read_lock();
753 node = avc_insert(ssid, tsid, tclass, avd); 751 node = avc_insert(ssid, tsid, tclass, avd);
754 } else { 752 } else {
@@ -770,7 +768,6 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
770 } 768 }
771 769
772 rcu_read_unlock(); 770 rcu_read_unlock();
773out:
774 return rc; 771 return rc;
775} 772}
776 773
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 2553266ad793..022cf067aa3f 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -96,13 +96,11 @@ struct av_decision {
96/* definitions of av_decision.flags */ 96/* definitions of av_decision.flags */
97#define AVD_FLAGS_PERMISSIVE 0x0001 97#define AVD_FLAGS_PERMISSIVE 0x0001
98 98
99int security_compute_av(u32 ssid, u32 tsid, 99void security_compute_av(u32 ssid, u32 tsid,
100 u16 tclass, u32 requested, 100 u16 tclass, struct av_decision *avd);
101 struct av_decision *avd);
102 101
103int security_compute_av_user(u32 ssid, u32 tsid, 102void security_compute_av_user(u32 ssid, u32 tsid,
104 u16 tclass, u32 requested, 103 u16 tclass, struct av_decision *avd);
105 struct av_decision *avd);
106 104
107int security_transition_sid(u32 ssid, u32 tsid, 105int security_transition_sid(u32 ssid, u32 tsid,
108 u16 tclass, u32 *out_sid); 106 u16 tclass, u32 *out_sid);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index fab36fdf2769..b7bb0f5ec07c 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -494,7 +494,6 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
494 char *scon, *tcon; 494 char *scon, *tcon;
495 u32 ssid, tsid; 495 u32 ssid, tsid;
496 u16 tclass; 496 u16 tclass;
497 u32 req;
498 struct av_decision avd; 497 struct av_decision avd;
499 ssize_t length; 498 ssize_t length;
500 499
@@ -512,7 +511,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
512 goto out; 511 goto out;
513 512
514 length = -EINVAL; 513 length = -EINVAL;
515 if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4) 514 if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
516 goto out2; 515 goto out2;
517 516
518 length = security_context_to_sid(scon, strlen(scon)+1, &ssid); 517 length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
@@ -522,9 +521,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
522 if (length < 0) 521 if (length < 0)
523 goto out2; 522 goto out2;
524 523
525 length = security_compute_av_user(ssid, tsid, tclass, req, &avd); 524 security_compute_av_user(ssid, tsid, tclass, &avd);
526 if (length < 0)
527 goto out2;
528 525
529 length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, 526 length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
530 "%x %x %x %x %u %x", 527 "%x %x %x %x %u %x",
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 07ddc81d7b57..9ec24169ccd7 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -87,11 +87,10 @@ static u32 latest_granting;
87static int context_struct_to_string(struct context *context, char **scontext, 87static int context_struct_to_string(struct context *context, char **scontext,
88 u32 *scontext_len); 88 u32 *scontext_len);
89 89
90static int context_struct_compute_av(struct context *scontext, 90static void context_struct_compute_av(struct context *scontext,
91 struct context *tcontext, 91 struct context *tcontext,
92 u16 tclass, 92 u16 tclass,
93 u32 requested, 93 struct av_decision *avd);
94 struct av_decision *avd);
95 94
96struct selinux_mapping { 95struct selinux_mapping {
97 u16 value; /* policy value */ 96 u16 value; /* policy value */
@@ -196,23 +195,6 @@ static u16 unmap_class(u16 tclass)
196 return tclass; 195 return tclass;
197} 196}
198 197
199static u32 unmap_perm(u16 tclass, u32 tperm)
200{
201 if (tclass < current_mapping_size) {
202 unsigned i;
203 u32 kperm = 0;
204
205 for (i = 0; i < current_mapping[tclass].num_perms; i++)
206 if (tperm & (1<<i)) {
207 kperm |= current_mapping[tclass].perms[i];
208 tperm &= ~(1<<i);
209 }
210 return kperm;
211 }
212
213 return tperm;
214}
215
216static void map_decision(u16 tclass, struct av_decision *avd, 198static void map_decision(u16 tclass, struct av_decision *avd,
217 int allow_unknown) 199 int allow_unknown)
218{ 200{
@@ -532,7 +514,6 @@ out:
532static void type_attribute_bounds_av(struct context *scontext, 514static void type_attribute_bounds_av(struct context *scontext,
533 struct context *tcontext, 515 struct context *tcontext,
534 u16 tclass, 516 u16 tclass,
535 u32 requested,
536 struct av_decision *avd) 517 struct av_decision *avd)
537{ 518{
538 struct context lo_scontext; 519 struct context lo_scontext;
@@ -553,7 +534,6 @@ static void type_attribute_bounds_av(struct context *scontext,
553 context_struct_compute_av(&lo_scontext, 534 context_struct_compute_av(&lo_scontext,
554 tcontext, 535 tcontext,
555 tclass, 536 tclass,
556 requested,
557 &lo_avd); 537 &lo_avd);
558 if ((lo_avd.allowed & avd->allowed) == avd->allowed) 538 if ((lo_avd.allowed & avd->allowed) == avd->allowed)
559 return; /* no masked permission */ 539 return; /* no masked permission */
@@ -569,7 +549,6 @@ static void type_attribute_bounds_av(struct context *scontext,
569 context_struct_compute_av(scontext, 549 context_struct_compute_av(scontext,
570 &lo_tcontext, 550 &lo_tcontext,
571 tclass, 551 tclass,
572 requested,
573 &lo_avd); 552 &lo_avd);
574 if ((lo_avd.allowed & avd->allowed) == avd->allowed) 553 if ((lo_avd.allowed & avd->allowed) == avd->allowed)
575 return; /* no masked permission */ 554 return; /* no masked permission */
@@ -586,7 +565,6 @@ static void type_attribute_bounds_av(struct context *scontext,
586 context_struct_compute_av(&lo_scontext, 565 context_struct_compute_av(&lo_scontext,
587 &lo_tcontext, 566 &lo_tcontext,
588 tclass, 567 tclass,
589 requested,
590 &lo_avd); 568 &lo_avd);
591 if ((lo_avd.allowed & avd->allowed) == avd->allowed) 569 if ((lo_avd.allowed & avd->allowed) == avd->allowed)
592 return; /* no masked permission */ 570 return; /* no masked permission */
@@ -607,11 +585,10 @@ static void type_attribute_bounds_av(struct context *scontext,
607 * Compute access vectors based on a context structure pair for 585 * Compute access vectors based on a context structure pair for
608 * the permissions in a particular class. 586 * the permissions in a particular class.
609 */ 587 */
610static int context_struct_compute_av(struct context *scontext, 588static void context_struct_compute_av(struct context *scontext,
611 struct context *tcontext, 589 struct context *tcontext,
612 u16 tclass, 590 u16 tclass,
613 u32 requested, 591 struct av_decision *avd)
614 struct av_decision *avd)
615{ 592{
616 struct constraint_node *constraint; 593 struct constraint_node *constraint;
617 struct role_allow *ra; 594 struct role_allow *ra;
@@ -622,19 +599,14 @@ static int context_struct_compute_av(struct context *scontext,
622 struct ebitmap_node *snode, *tnode; 599 struct ebitmap_node *snode, *tnode;
623 unsigned int i, j; 600 unsigned int i, j;
624 601
625 /*
626 * Initialize the access vectors to the default values.
627 */
628 avd->allowed = 0; 602 avd->allowed = 0;
629 avd->auditallow = 0; 603 avd->auditallow = 0;
630 avd->auditdeny = 0xffffffff; 604 avd->auditdeny = 0xffffffff;
631 avd->seqno = latest_granting;
632 avd->flags = 0;
633 605
634 if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { 606 if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) {
635 if (printk_ratelimit()) 607 if (printk_ratelimit())
636 printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass); 608 printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass);
637 return -EINVAL; 609 return;
638 } 610 }
639 611
640 tclass_datum = policydb.class_val_to_struct[tclass - 1]; 612 tclass_datum = policydb.class_val_to_struct[tclass - 1];
@@ -705,9 +677,7 @@ static int context_struct_compute_av(struct context *scontext,
705 * permission and notice it to userspace via audit. 677 * permission and notice it to userspace via audit.
706 */ 678 */
707 type_attribute_bounds_av(scontext, tcontext, 679 type_attribute_bounds_av(scontext, tcontext,
708 tclass, requested, avd); 680 tclass, avd);
709
710 return 0;
711} 681}
712 682
713static int security_validtrans_handle_fail(struct context *ocontext, 683static int security_validtrans_handle_fail(struct context *ocontext,
@@ -886,110 +856,116 @@ out:
886 return rc; 856 return rc;
887} 857}
888 858
889 859static void avd_init(struct av_decision *avd)
890static int security_compute_av_core(u32 ssid,
891 u32 tsid,
892 u16 tclass,
893 u32 requested,
894 struct av_decision *avd)
895{ 860{
896 struct context *scontext = NULL, *tcontext = NULL; 861 avd->allowed = 0;
897 int rc = 0; 862 avd->auditallow = 0;
898 863 avd->auditdeny = 0xffffffff;
899 scontext = sidtab_search(&sidtab, ssid); 864 avd->seqno = latest_granting;
900 if (!scontext) { 865 avd->flags = 0;
901 printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
902 __func__, ssid);
903 return -EINVAL;
904 }
905 tcontext = sidtab_search(&sidtab, tsid);
906 if (!tcontext) {
907 printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
908 __func__, tsid);
909 return -EINVAL;
910 }
911
912 rc = context_struct_compute_av(scontext, tcontext, tclass,
913 requested, avd);
914
915 /* permissive domain? */
916 if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
917 avd->flags |= AVD_FLAGS_PERMISSIVE;
918
919 return rc;
920} 866}
921 867
868
922/** 869/**
923 * security_compute_av - Compute access vector decisions. 870 * security_compute_av - Compute access vector decisions.
924 * @ssid: source security identifier 871 * @ssid: source security identifier
925 * @tsid: target security identifier 872 * @tsid: target security identifier
926 * @tclass: target security class 873 * @tclass: target security class
927 * @requested: requested permissions
928 * @avd: access vector decisions 874 * @avd: access vector decisions
929 * 875 *
930 * Compute a set of access vector decisions based on the 876 * Compute a set of access vector decisions based on the
931 * SID pair (@ssid, @tsid) for the permissions in @tclass. 877 * SID pair (@ssid, @tsid) for the permissions in @tclass.
932 * Return -%EINVAL if any of the parameters are invalid or %0
933 * if the access vector decisions were computed successfully.
934 */ 878 */
935int security_compute_av(u32 ssid, 879void security_compute_av(u32 ssid,
936 u32 tsid, 880 u32 tsid,
937 u16 orig_tclass, 881 u16 orig_tclass,
938 u32 orig_requested, 882 struct av_decision *avd)
939 struct av_decision *avd)
940{ 883{
941 u16 tclass; 884 u16 tclass;
942 u32 requested; 885 struct context *scontext = NULL, *tcontext = NULL;
943 int rc;
944 886
945 read_lock(&policy_rwlock); 887 read_lock(&policy_rwlock);
946 888 avd_init(avd);
947 if (!ss_initialized) 889 if (!ss_initialized)
948 goto allow; 890 goto allow;
949 891
950 requested = unmap_perm(orig_tclass, orig_requested); 892 scontext = sidtab_search(&sidtab, ssid);
893 if (!scontext) {
894 printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
895 __func__, ssid);
896 goto out;
897 }
898
899 /* permissive domain? */
900 if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
901 avd->flags |= AVD_FLAGS_PERMISSIVE;
902
903 tcontext = sidtab_search(&sidtab, tsid);
904 if (!tcontext) {
905 printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
906 __func__, tsid);
907 goto out;
908 }
909
951 tclass = unmap_class(orig_tclass); 910 tclass = unmap_class(orig_tclass);
952 if (unlikely(orig_tclass && !tclass)) { 911 if (unlikely(orig_tclass && !tclass)) {
953 if (policydb.allow_unknown) 912 if (policydb.allow_unknown)
954 goto allow; 913 goto allow;
955 rc = -EINVAL;
956 goto out; 914 goto out;
957 } 915 }
958 rc = security_compute_av_core(ssid, tsid, tclass, requested, avd); 916 context_struct_compute_av(scontext, tcontext, tclass, avd);
959 map_decision(orig_tclass, avd, policydb.allow_unknown); 917 map_decision(orig_tclass, avd, policydb.allow_unknown);
960out: 918out:
961 read_unlock(&policy_rwlock); 919 read_unlock(&policy_rwlock);
962 return rc; 920 return;
963allow: 921allow:
964 avd->allowed = 0xffffffff; 922 avd->allowed = 0xffffffff;
965 avd->auditallow = 0;
966 avd->auditdeny = 0xffffffff;
967 avd->seqno = latest_granting;
968 avd->flags = 0;
969 rc = 0;
970 goto out; 923 goto out;
971} 924}
972 925
973int security_compute_av_user(u32 ssid, 926void security_compute_av_user(u32 ssid,
974 u32 tsid, 927 u32 tsid,
975 u16 tclass, 928 u16 tclass,
976 u32 requested, 929 struct av_decision *avd)
977 struct av_decision *avd)
978{ 930{
979 int rc; 931 struct context *scontext = NULL, *tcontext = NULL;
980 932
981 if (!ss_initialized) { 933 read_lock(&policy_rwlock);
982 avd->allowed = 0xffffffff; 934 avd_init(avd);
983 avd->auditallow = 0; 935 if (!ss_initialized)
984 avd->auditdeny = 0xffffffff; 936 goto allow;
985 avd->seqno = latest_granting; 937
986 return 0; 938 scontext = sidtab_search(&sidtab, ssid);
939 if (!scontext) {
940 printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
941 __func__, ssid);
942 goto out;
987 } 943 }
988 944
989 read_lock(&policy_rwlock); 945 /* permissive domain? */
990 rc = security_compute_av_core(ssid, tsid, tclass, requested, avd); 946 if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
947 avd->flags |= AVD_FLAGS_PERMISSIVE;
948
949 tcontext = sidtab_search(&sidtab, tsid);
950 if (!tcontext) {
951 printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
952 __func__, tsid);
953 goto out;
954 }
955
956 if (unlikely(!tclass)) {
957 if (policydb.allow_unknown)
958 goto allow;
959 goto out;
960 }
961
962 context_struct_compute_av(scontext, tcontext, tclass, avd);
963 out:
991 read_unlock(&policy_rwlock); 964 read_unlock(&policy_rwlock);
992 return rc; 965 return;
966allow:
967 avd->allowed = 0xffffffff;
968 goto out;
993} 969}
994 970
995/* 971/*