diff options
author | Stephen Smalley <sds@tycho.nsa.gov> | 2010-01-14 17:28:10 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-01-17 17:54:26 -0500 |
commit | 19439d05b88dafc4e55d9ffce84ccc27cf8b2bcc (patch) | |
tree | e529e1bbba49f30684c3b88a67df1d62ba3e11b1 /security/selinux/ss/services.c | |
parent | 8d9525048c74786205b99f3fcd05a839721edfb7 (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/selinux/ss/services.c')
-rw-r--r-- | security/selinux/ss/services.c | 186 |
1 files changed, 81 insertions, 105 deletions
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; | |||
87 | static int context_struct_to_string(struct context *context, char **scontext, | 87 | static int context_struct_to_string(struct context *context, char **scontext, |
88 | u32 *scontext_len); | 88 | u32 *scontext_len); |
89 | 89 | ||
90 | static int context_struct_compute_av(struct context *scontext, | 90 | static 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 | ||
96 | struct selinux_mapping { | 95 | struct 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 | ||
199 | static 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 | |||
216 | static void map_decision(u16 tclass, struct av_decision *avd, | 198 | static void map_decision(u16 tclass, struct av_decision *avd, |
217 | int allow_unknown) | 199 | int allow_unknown) |
218 | { | 200 | { |
@@ -532,7 +514,6 @@ out: | |||
532 | static void type_attribute_bounds_av(struct context *scontext, | 514 | static 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 | */ |
610 | static int context_struct_compute_av(struct context *scontext, | 588 | static 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 | ||
713 | static int security_validtrans_handle_fail(struct context *ocontext, | 683 | static int security_validtrans_handle_fail(struct context *ocontext, |
@@ -886,110 +856,116 @@ out: | |||
886 | return rc; | 856 | return rc; |
887 | } | 857 | } |
888 | 858 | ||
889 | 859 | static void avd_init(struct av_decision *avd) | |
890 | static 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 | */ |
935 | int security_compute_av(u32 ssid, | 879 | void 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); |
960 | out: | 918 | out: |
961 | read_unlock(&policy_rwlock); | 919 | read_unlock(&policy_rwlock); |
962 | return rc; | 920 | return; |
963 | allow: | 921 | allow: |
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 | ||
973 | int security_compute_av_user(u32 ssid, | 926 | void 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; |
966 | allow: | ||
967 | avd->allowed = 0xffffffff; | ||
968 | goto out; | ||
993 | } | 969 | } |
994 | 970 | ||
995 | /* | 971 | /* |