.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Implementation of the security services. |
---|
3 | 4 | * |
---|
.. | .. |
---|
35 | 36 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. |
---|
36 | 37 | * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC |
---|
37 | 38 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> |
---|
38 | | - * This program is free software; you can redistribute it and/or modify |
---|
39 | | - * it under the terms of the GNU General Public License as published by |
---|
40 | | - * the Free Software Foundation, version 2. |
---|
41 | 39 | */ |
---|
42 | 40 | #include <linux/kernel.h> |
---|
43 | 41 | #include <linux/slab.h> |
---|
.. | .. |
---|
48 | 46 | #include <linux/in.h> |
---|
49 | 47 | #include <linux/sched.h> |
---|
50 | 48 | #include <linux/audit.h> |
---|
51 | | -#include <linux/mutex.h> |
---|
52 | | -#include <linux/selinux.h> |
---|
53 | | -#include <linux/flex_array.h> |
---|
54 | 49 | #include <linux/vmalloc.h> |
---|
55 | 50 | #include <net/netlabel.h> |
---|
56 | 51 | |
---|
.. | .. |
---|
69 | 64 | #include "xfrm.h" |
---|
70 | 65 | #include "ebitmap.h" |
---|
71 | 66 | #include "audit.h" |
---|
| 67 | +#include "policycap_names.h" |
---|
72 | 68 | |
---|
73 | | -/* Policy capability names */ |
---|
74 | | -const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = { |
---|
75 | | - "network_peer_controls", |
---|
76 | | - "open_perms", |
---|
77 | | - "extended_socket_class", |
---|
78 | | - "always_check_network", |
---|
79 | | - "cgroup_seclabel", |
---|
80 | | - "nnp_nosuid_transition" |
---|
| 69 | +#include <trace/hooks/selinux.h> |
---|
| 70 | + |
---|
| 71 | +struct convert_context_args { |
---|
| 72 | + struct selinux_state *state; |
---|
| 73 | + struct policydb *oldp; |
---|
| 74 | + struct policydb *newp; |
---|
81 | 75 | }; |
---|
82 | 76 | |
---|
83 | | -static struct selinux_ss selinux_ss; |
---|
84 | | - |
---|
85 | | -void selinux_ss_init(struct selinux_ss **ss) |
---|
86 | | -{ |
---|
87 | | - rwlock_init(&selinux_ss.policy_rwlock); |
---|
88 | | - mutex_init(&selinux_ss.status_lock); |
---|
89 | | - *ss = &selinux_ss; |
---|
90 | | -} |
---|
| 77 | +struct selinux_policy_convert_data { |
---|
| 78 | + struct convert_context_args args; |
---|
| 79 | + struct sidtab_convert_params sidtab_params; |
---|
| 80 | +}; |
---|
91 | 81 | |
---|
92 | 82 | /* Forward declaration. */ |
---|
93 | 83 | static int context_struct_to_string(struct policydb *policydb, |
---|
94 | 84 | struct context *context, |
---|
95 | 85 | char **scontext, |
---|
96 | 86 | u32 *scontext_len); |
---|
| 87 | + |
---|
| 88 | +static int sidtab_entry_to_string(struct policydb *policydb, |
---|
| 89 | + struct sidtab *sidtab, |
---|
| 90 | + struct sidtab_entry *entry, |
---|
| 91 | + char **scontext, |
---|
| 92 | + u32 *scontext_len); |
---|
97 | 93 | |
---|
98 | 94 | static void context_struct_compute_av(struct policydb *policydb, |
---|
99 | 95 | struct context *scontext, |
---|
.. | .. |
---|
247 | 243 | |
---|
248 | 244 | int security_mls_enabled(struct selinux_state *state) |
---|
249 | 245 | { |
---|
250 | | - struct policydb *p = &state->ss->policydb; |
---|
| 246 | + int mls_enabled; |
---|
| 247 | + struct selinux_policy *policy; |
---|
251 | 248 | |
---|
252 | | - return p->mls_enabled; |
---|
| 249 | + if (!selinux_initialized(state)) |
---|
| 250 | + return 0; |
---|
| 251 | + |
---|
| 252 | + rcu_read_lock(); |
---|
| 253 | + policy = rcu_dereference(state->policy); |
---|
| 254 | + mls_enabled = policy->policydb.mls_enabled; |
---|
| 255 | + rcu_read_unlock(); |
---|
| 256 | + return mls_enabled; |
---|
253 | 257 | } |
---|
254 | 258 | |
---|
255 | 259 | /* |
---|
.. | .. |
---|
481 | 485 | |
---|
482 | 486 | /* init permission_names */ |
---|
483 | 487 | if (common_dat && |
---|
484 | | - hashtab_map(common_dat->permissions.table, |
---|
| 488 | + hashtab_map(&common_dat->permissions.table, |
---|
485 | 489 | dump_masked_av_helper, permission_names) < 0) |
---|
486 | 490 | goto out; |
---|
487 | 491 | |
---|
488 | | - if (hashtab_map(tclass_dat->permissions.table, |
---|
| 492 | + if (hashtab_map(&tclass_dat->permissions.table, |
---|
489 | 493 | dump_masked_av_helper, permission_names) < 0) |
---|
490 | 494 | goto out; |
---|
491 | 495 | |
---|
.. | .. |
---|
546 | 550 | struct type_datum *target; |
---|
547 | 551 | u32 masked = 0; |
---|
548 | 552 | |
---|
549 | | - source = flex_array_get_ptr(policydb->type_val_to_struct_array, |
---|
550 | | - scontext->type - 1); |
---|
| 553 | + source = policydb->type_val_to_struct[scontext->type - 1]; |
---|
551 | 554 | BUG_ON(!source); |
---|
552 | 555 | |
---|
553 | 556 | if (!source->bounds) |
---|
554 | 557 | return; |
---|
555 | 558 | |
---|
556 | | - target = flex_array_get_ptr(policydb->type_val_to_struct_array, |
---|
557 | | - tcontext->type - 1); |
---|
| 559 | + target = policydb->type_val_to_struct[tcontext->type - 1]; |
---|
558 | 560 | BUG_ON(!target); |
---|
559 | 561 | |
---|
560 | 562 | memset(&lo_avd, 0, sizeof(lo_avd)); |
---|
.. | .. |
---|
654 | 656 | */ |
---|
655 | 657 | avkey.target_class = tclass; |
---|
656 | 658 | avkey.specified = AVTAB_AV | AVTAB_XPERMS; |
---|
657 | | - sattr = flex_array_get(policydb->type_attr_map_array, |
---|
658 | | - scontext->type - 1); |
---|
659 | | - BUG_ON(!sattr); |
---|
660 | | - tattr = flex_array_get(policydb->type_attr_map_array, |
---|
661 | | - tcontext->type - 1); |
---|
662 | | - BUG_ON(!tattr); |
---|
| 659 | + sattr = &policydb->type_attr_map_array[scontext->type - 1]; |
---|
| 660 | + tattr = &policydb->type_attr_map_array[tcontext->type - 1]; |
---|
663 | 661 | ebitmap_for_each_positive_bit(sattr, snode, i) { |
---|
664 | 662 | ebitmap_for_each_positive_bit(tattr, tnode, j) { |
---|
665 | 663 | avkey.source_type = i + 1; |
---|
.. | .. |
---|
726 | 724 | } |
---|
727 | 725 | |
---|
728 | 726 | static int security_validtrans_handle_fail(struct selinux_state *state, |
---|
729 | | - struct context *ocontext, |
---|
730 | | - struct context *ncontext, |
---|
731 | | - struct context *tcontext, |
---|
732 | | - u16 tclass) |
---|
| 727 | + struct selinux_policy *policy, |
---|
| 728 | + struct sidtab_entry *oentry, |
---|
| 729 | + struct sidtab_entry *nentry, |
---|
| 730 | + struct sidtab_entry *tentry, |
---|
| 731 | + u16 tclass) |
---|
733 | 732 | { |
---|
734 | | - struct policydb *p = &state->ss->policydb; |
---|
| 733 | + struct policydb *p = &policy->policydb; |
---|
| 734 | + struct sidtab *sidtab = policy->sidtab; |
---|
735 | 735 | char *o = NULL, *n = NULL, *t = NULL; |
---|
736 | 736 | u32 olen, nlen, tlen; |
---|
737 | 737 | |
---|
738 | | - if (context_struct_to_string(p, ocontext, &o, &olen)) |
---|
| 738 | + if (sidtab_entry_to_string(p, sidtab, oentry, &o, &olen)) |
---|
739 | 739 | goto out; |
---|
740 | | - if (context_struct_to_string(p, ncontext, &n, &nlen)) |
---|
| 740 | + if (sidtab_entry_to_string(p, sidtab, nentry, &n, &nlen)) |
---|
741 | 741 | goto out; |
---|
742 | | - if (context_struct_to_string(p, tcontext, &t, &tlen)) |
---|
| 742 | + if (sidtab_entry_to_string(p, sidtab, tentry, &t, &tlen)) |
---|
743 | 743 | goto out; |
---|
744 | 744 | audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR, |
---|
745 | 745 | "op=security_validate_transition seresult=denied" |
---|
.. | .. |
---|
759 | 759 | u32 oldsid, u32 newsid, u32 tasksid, |
---|
760 | 760 | u16 orig_tclass, bool user) |
---|
761 | 761 | { |
---|
| 762 | + struct selinux_policy *policy; |
---|
762 | 763 | struct policydb *policydb; |
---|
763 | 764 | struct sidtab *sidtab; |
---|
764 | | - struct context *ocontext; |
---|
765 | | - struct context *ncontext; |
---|
766 | | - struct context *tcontext; |
---|
| 765 | + struct sidtab_entry *oentry; |
---|
| 766 | + struct sidtab_entry *nentry; |
---|
| 767 | + struct sidtab_entry *tentry; |
---|
767 | 768 | struct class_datum *tclass_datum; |
---|
768 | 769 | struct constraint_node *constraint; |
---|
769 | 770 | u16 tclass; |
---|
770 | 771 | int rc = 0; |
---|
771 | 772 | |
---|
772 | 773 | |
---|
773 | | - if (!state->initialized) |
---|
| 774 | + if (!selinux_initialized(state)) |
---|
774 | 775 | return 0; |
---|
775 | 776 | |
---|
776 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 777 | + rcu_read_lock(); |
---|
777 | 778 | |
---|
778 | | - policydb = &state->ss->policydb; |
---|
779 | | - sidtab = state->ss->sidtab; |
---|
| 779 | + policy = rcu_dereference(state->policy); |
---|
| 780 | + policydb = &policy->policydb; |
---|
| 781 | + sidtab = policy->sidtab; |
---|
780 | 782 | |
---|
781 | 783 | if (!user) |
---|
782 | | - tclass = unmap_class(&state->ss->map, orig_tclass); |
---|
| 784 | + tclass = unmap_class(&policy->map, orig_tclass); |
---|
783 | 785 | else |
---|
784 | 786 | tclass = orig_tclass; |
---|
785 | 787 | |
---|
.. | .. |
---|
789 | 791 | } |
---|
790 | 792 | tclass_datum = policydb->class_val_to_struct[tclass - 1]; |
---|
791 | 793 | |
---|
792 | | - ocontext = sidtab_search(sidtab, oldsid); |
---|
793 | | - if (!ocontext) { |
---|
| 794 | + oentry = sidtab_search_entry(sidtab, oldsid); |
---|
| 795 | + if (!oentry) { |
---|
794 | 796 | pr_err("SELinux: %s: unrecognized SID %d\n", |
---|
795 | 797 | __func__, oldsid); |
---|
796 | 798 | rc = -EINVAL; |
---|
797 | 799 | goto out; |
---|
798 | 800 | } |
---|
799 | 801 | |
---|
800 | | - ncontext = sidtab_search(sidtab, newsid); |
---|
801 | | - if (!ncontext) { |
---|
| 802 | + nentry = sidtab_search_entry(sidtab, newsid); |
---|
| 803 | + if (!nentry) { |
---|
802 | 804 | pr_err("SELinux: %s: unrecognized SID %d\n", |
---|
803 | 805 | __func__, newsid); |
---|
804 | 806 | rc = -EINVAL; |
---|
805 | 807 | goto out; |
---|
806 | 808 | } |
---|
807 | 809 | |
---|
808 | | - tcontext = sidtab_search(sidtab, tasksid); |
---|
809 | | - if (!tcontext) { |
---|
| 810 | + tentry = sidtab_search_entry(sidtab, tasksid); |
---|
| 811 | + if (!tentry) { |
---|
810 | 812 | pr_err("SELinux: %s: unrecognized SID %d\n", |
---|
811 | 813 | __func__, tasksid); |
---|
812 | 814 | rc = -EINVAL; |
---|
.. | .. |
---|
815 | 817 | |
---|
816 | 818 | constraint = tclass_datum->validatetrans; |
---|
817 | 819 | while (constraint) { |
---|
818 | | - if (!constraint_expr_eval(policydb, ocontext, ncontext, |
---|
819 | | - tcontext, constraint->expr)) { |
---|
| 820 | + if (!constraint_expr_eval(policydb, &oentry->context, |
---|
| 821 | + &nentry->context, &tentry->context, |
---|
| 822 | + constraint->expr)) { |
---|
820 | 823 | if (user) |
---|
821 | 824 | rc = -EPERM; |
---|
822 | 825 | else |
---|
823 | 826 | rc = security_validtrans_handle_fail(state, |
---|
824 | | - ocontext, |
---|
825 | | - ncontext, |
---|
826 | | - tcontext, |
---|
827 | | - tclass); |
---|
| 827 | + policy, |
---|
| 828 | + oentry, |
---|
| 829 | + nentry, |
---|
| 830 | + tentry, |
---|
| 831 | + tclass); |
---|
828 | 832 | goto out; |
---|
829 | 833 | } |
---|
830 | 834 | constraint = constraint->next; |
---|
831 | 835 | } |
---|
832 | 836 | |
---|
833 | 837 | out: |
---|
834 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 838 | + rcu_read_unlock(); |
---|
835 | 839 | return rc; |
---|
836 | 840 | } |
---|
837 | 841 | |
---|
.. | .. |
---|
863 | 867 | int security_bounded_transition(struct selinux_state *state, |
---|
864 | 868 | u32 old_sid, u32 new_sid) |
---|
865 | 869 | { |
---|
| 870 | + struct selinux_policy *policy; |
---|
866 | 871 | struct policydb *policydb; |
---|
867 | 872 | struct sidtab *sidtab; |
---|
868 | | - struct context *old_context, *new_context; |
---|
| 873 | + struct sidtab_entry *old_entry, *new_entry; |
---|
869 | 874 | struct type_datum *type; |
---|
870 | 875 | int index; |
---|
871 | 876 | int rc; |
---|
872 | 877 | |
---|
873 | | - if (!state->initialized) |
---|
| 878 | + if (!selinux_initialized(state)) |
---|
874 | 879 | return 0; |
---|
875 | 880 | |
---|
876 | | - read_lock(&state->ss->policy_rwlock); |
---|
877 | | - |
---|
878 | | - policydb = &state->ss->policydb; |
---|
879 | | - sidtab = state->ss->sidtab; |
---|
| 881 | + rcu_read_lock(); |
---|
| 882 | + policy = rcu_dereference(state->policy); |
---|
| 883 | + policydb = &policy->policydb; |
---|
| 884 | + sidtab = policy->sidtab; |
---|
880 | 885 | |
---|
881 | 886 | rc = -EINVAL; |
---|
882 | | - old_context = sidtab_search(sidtab, old_sid); |
---|
883 | | - if (!old_context) { |
---|
| 887 | + old_entry = sidtab_search_entry(sidtab, old_sid); |
---|
| 888 | + if (!old_entry) { |
---|
884 | 889 | pr_err("SELinux: %s: unrecognized SID %u\n", |
---|
885 | 890 | __func__, old_sid); |
---|
886 | 891 | goto out; |
---|
887 | 892 | } |
---|
888 | 893 | |
---|
889 | 894 | rc = -EINVAL; |
---|
890 | | - new_context = sidtab_search(sidtab, new_sid); |
---|
891 | | - if (!new_context) { |
---|
| 895 | + new_entry = sidtab_search_entry(sidtab, new_sid); |
---|
| 896 | + if (!new_entry) { |
---|
892 | 897 | pr_err("SELinux: %s: unrecognized SID %u\n", |
---|
893 | 898 | __func__, new_sid); |
---|
894 | 899 | goto out; |
---|
.. | .. |
---|
896 | 901 | |
---|
897 | 902 | rc = 0; |
---|
898 | 903 | /* type/domain unchanged */ |
---|
899 | | - if (old_context->type == new_context->type) |
---|
| 904 | + if (old_entry->context.type == new_entry->context.type) |
---|
900 | 905 | goto out; |
---|
901 | 906 | |
---|
902 | | - index = new_context->type; |
---|
| 907 | + index = new_entry->context.type; |
---|
903 | 908 | while (true) { |
---|
904 | | - type = flex_array_get_ptr(policydb->type_val_to_struct_array, |
---|
905 | | - index - 1); |
---|
| 909 | + type = policydb->type_val_to_struct[index - 1]; |
---|
906 | 910 | BUG_ON(!type); |
---|
907 | 911 | |
---|
908 | 912 | /* not bounded anymore */ |
---|
.. | .. |
---|
912 | 916 | |
---|
913 | 917 | /* @newsid is bounded by @oldsid */ |
---|
914 | 918 | rc = 0; |
---|
915 | | - if (type->bounds == old_context->type) |
---|
| 919 | + if (type->bounds == old_entry->context.type) |
---|
916 | 920 | break; |
---|
917 | 921 | |
---|
918 | 922 | index = type->bounds; |
---|
.. | .. |
---|
923 | 927 | char *new_name = NULL; |
---|
924 | 928 | u32 length; |
---|
925 | 929 | |
---|
926 | | - if (!context_struct_to_string(policydb, old_context, |
---|
927 | | - &old_name, &length) && |
---|
928 | | - !context_struct_to_string(policydb, new_context, |
---|
929 | | - &new_name, &length)) { |
---|
| 930 | + if (!sidtab_entry_to_string(policydb, sidtab, old_entry, |
---|
| 931 | + &old_name, &length) && |
---|
| 932 | + !sidtab_entry_to_string(policydb, sidtab, new_entry, |
---|
| 933 | + &new_name, &length)) { |
---|
930 | 934 | audit_log(audit_context(), |
---|
931 | 935 | GFP_ATOMIC, AUDIT_SELINUX_ERR, |
---|
932 | 936 | "op=security_bounded_transition " |
---|
.. | .. |
---|
938 | 942 | kfree(old_name); |
---|
939 | 943 | } |
---|
940 | 944 | out: |
---|
941 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 945 | + rcu_read_unlock(); |
---|
942 | 946 | |
---|
943 | 947 | return rc; |
---|
944 | 948 | } |
---|
945 | 949 | |
---|
946 | | -static void avd_init(struct selinux_state *state, struct av_decision *avd) |
---|
| 950 | +static void avd_init(struct selinux_policy *policy, struct av_decision *avd) |
---|
947 | 951 | { |
---|
948 | 952 | avd->allowed = 0; |
---|
949 | 953 | avd->auditallow = 0; |
---|
950 | 954 | avd->auditdeny = 0xffffffff; |
---|
951 | | - avd->seqno = state->ss->latest_granting; |
---|
| 955 | + if (policy) |
---|
| 956 | + avd->seqno = policy->latest_granting; |
---|
| 957 | + else |
---|
| 958 | + avd->seqno = 0; |
---|
952 | 959 | avd->flags = 0; |
---|
953 | 960 | } |
---|
954 | 961 | |
---|
.. | .. |
---|
1013 | 1020 | u8 driver, |
---|
1014 | 1021 | struct extended_perms_decision *xpermd) |
---|
1015 | 1022 | { |
---|
| 1023 | + struct selinux_policy *policy; |
---|
1016 | 1024 | struct policydb *policydb; |
---|
1017 | 1025 | struct sidtab *sidtab; |
---|
1018 | 1026 | u16 tclass; |
---|
.. | .. |
---|
1029 | 1037 | memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p)); |
---|
1030 | 1038 | memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p)); |
---|
1031 | 1039 | |
---|
1032 | | - read_lock(&state->ss->policy_rwlock); |
---|
1033 | | - if (!state->initialized) |
---|
| 1040 | + rcu_read_lock(); |
---|
| 1041 | + if (!selinux_initialized(state)) |
---|
1034 | 1042 | goto allow; |
---|
1035 | 1043 | |
---|
1036 | | - policydb = &state->ss->policydb; |
---|
1037 | | - sidtab = state->ss->sidtab; |
---|
| 1044 | + policy = rcu_dereference(state->policy); |
---|
| 1045 | + policydb = &policy->policydb; |
---|
| 1046 | + sidtab = policy->sidtab; |
---|
1038 | 1047 | |
---|
1039 | 1048 | scontext = sidtab_search(sidtab, ssid); |
---|
1040 | 1049 | if (!scontext) { |
---|
.. | .. |
---|
1050 | 1059 | goto out; |
---|
1051 | 1060 | } |
---|
1052 | 1061 | |
---|
1053 | | - tclass = unmap_class(&state->ss->map, orig_tclass); |
---|
| 1062 | + tclass = unmap_class(&policy->map, orig_tclass); |
---|
1054 | 1063 | if (unlikely(orig_tclass && !tclass)) { |
---|
1055 | 1064 | if (policydb->allow_unknown) |
---|
1056 | 1065 | goto allow; |
---|
.. | .. |
---|
1065 | 1074 | |
---|
1066 | 1075 | avkey.target_class = tclass; |
---|
1067 | 1076 | avkey.specified = AVTAB_XPERMS; |
---|
1068 | | - sattr = flex_array_get(policydb->type_attr_map_array, |
---|
1069 | | - scontext->type - 1); |
---|
1070 | | - BUG_ON(!sattr); |
---|
1071 | | - tattr = flex_array_get(policydb->type_attr_map_array, |
---|
1072 | | - tcontext->type - 1); |
---|
1073 | | - BUG_ON(!tattr); |
---|
| 1077 | + sattr = &policydb->type_attr_map_array[scontext->type - 1]; |
---|
| 1078 | + tattr = &policydb->type_attr_map_array[tcontext->type - 1]; |
---|
1074 | 1079 | ebitmap_for_each_positive_bit(sattr, snode, i) { |
---|
1075 | 1080 | ebitmap_for_each_positive_bit(tattr, tnode, j) { |
---|
1076 | 1081 | avkey.source_type = i + 1; |
---|
.. | .. |
---|
1086 | 1091 | } |
---|
1087 | 1092 | } |
---|
1088 | 1093 | out: |
---|
1089 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 1094 | + rcu_read_unlock(); |
---|
1090 | 1095 | return; |
---|
1091 | 1096 | allow: |
---|
1092 | 1097 | memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p)); |
---|
.. | .. |
---|
1111 | 1116 | struct av_decision *avd, |
---|
1112 | 1117 | struct extended_perms *xperms) |
---|
1113 | 1118 | { |
---|
| 1119 | + struct selinux_policy *policy; |
---|
1114 | 1120 | struct policydb *policydb; |
---|
1115 | 1121 | struct sidtab *sidtab; |
---|
1116 | 1122 | u16 tclass; |
---|
1117 | 1123 | struct context *scontext = NULL, *tcontext = NULL; |
---|
1118 | 1124 | |
---|
1119 | | - read_lock(&state->ss->policy_rwlock); |
---|
1120 | | - avd_init(state, avd); |
---|
| 1125 | + rcu_read_lock(); |
---|
| 1126 | + policy = rcu_dereference(state->policy); |
---|
| 1127 | + avd_init(policy, avd); |
---|
1121 | 1128 | xperms->len = 0; |
---|
1122 | | - if (!state->initialized) |
---|
| 1129 | + if (!selinux_initialized(state)) |
---|
1123 | 1130 | goto allow; |
---|
1124 | 1131 | |
---|
1125 | | - policydb = &state->ss->policydb; |
---|
1126 | | - sidtab = state->ss->sidtab; |
---|
| 1132 | + policydb = &policy->policydb; |
---|
| 1133 | + sidtab = policy->sidtab; |
---|
1127 | 1134 | |
---|
1128 | 1135 | scontext = sidtab_search(sidtab, ssid); |
---|
1129 | 1136 | if (!scontext) { |
---|
.. | .. |
---|
1143 | 1150 | goto out; |
---|
1144 | 1151 | } |
---|
1145 | 1152 | |
---|
1146 | | - tclass = unmap_class(&state->ss->map, orig_tclass); |
---|
| 1153 | + tclass = unmap_class(&policy->map, orig_tclass); |
---|
1147 | 1154 | if (unlikely(orig_tclass && !tclass)) { |
---|
1148 | 1155 | if (policydb->allow_unknown) |
---|
1149 | 1156 | goto allow; |
---|
.. | .. |
---|
1151 | 1158 | } |
---|
1152 | 1159 | context_struct_compute_av(policydb, scontext, tcontext, tclass, avd, |
---|
1153 | 1160 | xperms); |
---|
1154 | | - map_decision(&state->ss->map, orig_tclass, avd, |
---|
| 1161 | + map_decision(&policy->map, orig_tclass, avd, |
---|
1155 | 1162 | policydb->allow_unknown); |
---|
1156 | 1163 | out: |
---|
1157 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 1164 | + rcu_read_unlock(); |
---|
1158 | 1165 | return; |
---|
1159 | 1166 | allow: |
---|
1160 | 1167 | avd->allowed = 0xffffffff; |
---|
.. | .. |
---|
1167 | 1174 | u16 tclass, |
---|
1168 | 1175 | struct av_decision *avd) |
---|
1169 | 1176 | { |
---|
| 1177 | + struct selinux_policy *policy; |
---|
1170 | 1178 | struct policydb *policydb; |
---|
1171 | 1179 | struct sidtab *sidtab; |
---|
1172 | 1180 | struct context *scontext = NULL, *tcontext = NULL; |
---|
1173 | 1181 | |
---|
1174 | | - read_lock(&state->ss->policy_rwlock); |
---|
1175 | | - avd_init(state, avd); |
---|
1176 | | - if (!state->initialized) |
---|
| 1182 | + rcu_read_lock(); |
---|
| 1183 | + policy = rcu_dereference(state->policy); |
---|
| 1184 | + avd_init(policy, avd); |
---|
| 1185 | + if (!selinux_initialized(state)) |
---|
1177 | 1186 | goto allow; |
---|
1178 | 1187 | |
---|
1179 | | - policydb = &state->ss->policydb; |
---|
1180 | | - sidtab = state->ss->sidtab; |
---|
| 1188 | + policydb = &policy->policydb; |
---|
| 1189 | + sidtab = policy->sidtab; |
---|
1181 | 1190 | |
---|
1182 | 1191 | scontext = sidtab_search(sidtab, ssid); |
---|
1183 | 1192 | if (!scontext) { |
---|
.. | .. |
---|
1206 | 1215 | context_struct_compute_av(policydb, scontext, tcontext, tclass, avd, |
---|
1207 | 1216 | NULL); |
---|
1208 | 1217 | out: |
---|
1209 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 1218 | + rcu_read_unlock(); |
---|
1210 | 1219 | return; |
---|
1211 | 1220 | allow: |
---|
1212 | 1221 | avd->allowed = 0xffffffff; |
---|
.. | .. |
---|
1270 | 1279 | return 0; |
---|
1271 | 1280 | } |
---|
1272 | 1281 | |
---|
| 1282 | +static int sidtab_entry_to_string(struct policydb *p, |
---|
| 1283 | + struct sidtab *sidtab, |
---|
| 1284 | + struct sidtab_entry *entry, |
---|
| 1285 | + char **scontext, u32 *scontext_len) |
---|
| 1286 | +{ |
---|
| 1287 | + int rc = sidtab_sid2str_get(sidtab, entry, scontext, scontext_len); |
---|
| 1288 | + |
---|
| 1289 | + if (rc != -ENOENT) |
---|
| 1290 | + return rc; |
---|
| 1291 | + |
---|
| 1292 | + rc = context_struct_to_string(p, &entry->context, scontext, |
---|
| 1293 | + scontext_len); |
---|
| 1294 | + if (!rc && scontext) |
---|
| 1295 | + sidtab_sid2str_put(sidtab, entry, *scontext, *scontext_len); |
---|
| 1296 | + return rc; |
---|
| 1297 | +} |
---|
| 1298 | + |
---|
1273 | 1299 | #include "initial_sid_to_string.h" |
---|
1274 | 1300 | |
---|
1275 | 1301 | int security_sidtab_hash_stats(struct selinux_state *state, char *page) |
---|
1276 | 1302 | { |
---|
| 1303 | + struct selinux_policy *policy; |
---|
1277 | 1304 | int rc; |
---|
1278 | 1305 | |
---|
1279 | | - if (!state->initialized) { |
---|
| 1306 | + if (!selinux_initialized(state)) { |
---|
1280 | 1307 | pr_err("SELinux: %s: called before initial load_policy\n", |
---|
1281 | 1308 | __func__); |
---|
1282 | 1309 | return -EINVAL; |
---|
1283 | 1310 | } |
---|
1284 | 1311 | |
---|
1285 | | - read_lock(&state->ss->policy_rwlock); |
---|
1286 | | - rc = sidtab_hash_stats(state->ss->sidtab, page); |
---|
1287 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 1312 | + rcu_read_lock(); |
---|
| 1313 | + policy = rcu_dereference(state->policy); |
---|
| 1314 | + rc = sidtab_hash_stats(policy->sidtab, page); |
---|
| 1315 | + rcu_read_unlock(); |
---|
1288 | 1316 | |
---|
1289 | 1317 | return rc; |
---|
1290 | 1318 | } |
---|
.. | .. |
---|
1298 | 1326 | |
---|
1299 | 1327 | static int security_sid_to_context_core(struct selinux_state *state, |
---|
1300 | 1328 | u32 sid, char **scontext, |
---|
1301 | | - u32 *scontext_len, int force) |
---|
| 1329 | + u32 *scontext_len, int force, |
---|
| 1330 | + int only_invalid) |
---|
1302 | 1331 | { |
---|
| 1332 | + struct selinux_policy *policy; |
---|
1303 | 1333 | struct policydb *policydb; |
---|
1304 | 1334 | struct sidtab *sidtab; |
---|
1305 | | - struct context *context; |
---|
| 1335 | + struct sidtab_entry *entry; |
---|
1306 | 1336 | int rc = 0; |
---|
1307 | 1337 | |
---|
1308 | 1338 | if (scontext) |
---|
1309 | 1339 | *scontext = NULL; |
---|
1310 | 1340 | *scontext_len = 0; |
---|
1311 | 1341 | |
---|
1312 | | - if (!state->initialized) { |
---|
| 1342 | + if (!selinux_initialized(state)) { |
---|
1313 | 1343 | if (sid <= SECINITSID_NUM) { |
---|
1314 | 1344 | char *scontextp; |
---|
| 1345 | + const char *s = initial_sid_to_string[sid]; |
---|
1315 | 1346 | |
---|
1316 | | - *scontext_len = strlen(initial_sid_to_string[sid]) + 1; |
---|
| 1347 | + if (!s) |
---|
| 1348 | + return -EINVAL; |
---|
| 1349 | + *scontext_len = strlen(s) + 1; |
---|
1317 | 1350 | if (!scontext) |
---|
1318 | | - goto out; |
---|
1319 | | - scontextp = kmemdup(initial_sid_to_string[sid], |
---|
1320 | | - *scontext_len, GFP_ATOMIC); |
---|
1321 | | - if (!scontextp) { |
---|
1322 | | - rc = -ENOMEM; |
---|
1323 | | - goto out; |
---|
1324 | | - } |
---|
| 1351 | + return 0; |
---|
| 1352 | + scontextp = kmemdup(s, *scontext_len, GFP_ATOMIC); |
---|
| 1353 | + if (!scontextp) |
---|
| 1354 | + return -ENOMEM; |
---|
1325 | 1355 | *scontext = scontextp; |
---|
1326 | | - goto out; |
---|
| 1356 | + return 0; |
---|
1327 | 1357 | } |
---|
1328 | 1358 | pr_err("SELinux: %s: called before initial " |
---|
1329 | 1359 | "load_policy on unknown SID %d\n", __func__, sid); |
---|
1330 | | - rc = -EINVAL; |
---|
1331 | | - goto out; |
---|
| 1360 | + return -EINVAL; |
---|
1332 | 1361 | } |
---|
1333 | | - read_lock(&state->ss->policy_rwlock); |
---|
1334 | | - policydb = &state->ss->policydb; |
---|
1335 | | - sidtab = state->ss->sidtab; |
---|
| 1362 | + rcu_read_lock(); |
---|
| 1363 | + policy = rcu_dereference(state->policy); |
---|
| 1364 | + policydb = &policy->policydb; |
---|
| 1365 | + sidtab = policy->sidtab; |
---|
| 1366 | + |
---|
1336 | 1367 | if (force) |
---|
1337 | | - context = sidtab_search_force(sidtab, sid); |
---|
| 1368 | + entry = sidtab_search_entry_force(sidtab, sid); |
---|
1338 | 1369 | else |
---|
1339 | | - context = sidtab_search(sidtab, sid); |
---|
1340 | | - if (!context) { |
---|
| 1370 | + entry = sidtab_search_entry(sidtab, sid); |
---|
| 1371 | + if (!entry) { |
---|
1341 | 1372 | pr_err("SELinux: %s: unrecognized SID %d\n", |
---|
1342 | 1373 | __func__, sid); |
---|
1343 | 1374 | rc = -EINVAL; |
---|
1344 | 1375 | goto out_unlock; |
---|
1345 | 1376 | } |
---|
1346 | | - rc = context_struct_to_string(policydb, context, scontext, |
---|
1347 | | - scontext_len); |
---|
| 1377 | + if (only_invalid && !entry->context.len) |
---|
| 1378 | + goto out_unlock; |
---|
| 1379 | + |
---|
| 1380 | + rc = sidtab_entry_to_string(policydb, sidtab, entry, scontext, |
---|
| 1381 | + scontext_len); |
---|
| 1382 | + |
---|
1348 | 1383 | out_unlock: |
---|
1349 | | - read_unlock(&state->ss->policy_rwlock); |
---|
1350 | | -out: |
---|
| 1384 | + rcu_read_unlock(); |
---|
1351 | 1385 | return rc; |
---|
1352 | 1386 | |
---|
1353 | 1387 | } |
---|
.. | .. |
---|
1366 | 1400 | u32 sid, char **scontext, u32 *scontext_len) |
---|
1367 | 1401 | { |
---|
1368 | 1402 | return security_sid_to_context_core(state, sid, scontext, |
---|
1369 | | - scontext_len, 0); |
---|
| 1403 | + scontext_len, 0, 0); |
---|
1370 | 1404 | } |
---|
1371 | 1405 | |
---|
1372 | 1406 | int security_sid_to_context_force(struct selinux_state *state, u32 sid, |
---|
1373 | 1407 | char **scontext, u32 *scontext_len) |
---|
1374 | 1408 | { |
---|
1375 | 1409 | return security_sid_to_context_core(state, sid, scontext, |
---|
1376 | | - scontext_len, 1); |
---|
| 1410 | + scontext_len, 1, 0); |
---|
| 1411 | +} |
---|
| 1412 | + |
---|
| 1413 | +/** |
---|
| 1414 | + * security_sid_to_context_inval - Obtain a context for a given SID if it |
---|
| 1415 | + * is invalid. |
---|
| 1416 | + * @sid: security identifier, SID |
---|
| 1417 | + * @scontext: security context |
---|
| 1418 | + * @scontext_len: length in bytes |
---|
| 1419 | + * |
---|
| 1420 | + * Write the string representation of the context associated with @sid |
---|
| 1421 | + * into a dynamically allocated string of the correct size, but only if the |
---|
| 1422 | + * context is invalid in the current policy. Set @scontext to point to |
---|
| 1423 | + * this string (or NULL if the context is valid) and set @scontext_len to |
---|
| 1424 | + * the length of the string (or 0 if the context is valid). |
---|
| 1425 | + */ |
---|
| 1426 | +int security_sid_to_context_inval(struct selinux_state *state, u32 sid, |
---|
| 1427 | + char **scontext, u32 *scontext_len) |
---|
| 1428 | +{ |
---|
| 1429 | + return security_sid_to_context_core(state, sid, scontext, |
---|
| 1430 | + scontext_len, 1, 1); |
---|
1377 | 1431 | } |
---|
1378 | 1432 | |
---|
1379 | 1433 | /* |
---|
.. | .. |
---|
1408 | 1462 | |
---|
1409 | 1463 | *p++ = 0; |
---|
1410 | 1464 | |
---|
1411 | | - usrdatum = hashtab_search(pol->p_users.table, scontextp); |
---|
| 1465 | + usrdatum = symtab_search(&pol->p_users, scontextp); |
---|
1412 | 1466 | if (!usrdatum) |
---|
1413 | 1467 | goto out; |
---|
1414 | 1468 | |
---|
.. | .. |
---|
1424 | 1478 | |
---|
1425 | 1479 | *p++ = 0; |
---|
1426 | 1480 | |
---|
1427 | | - role = hashtab_search(pol->p_roles.table, scontextp); |
---|
| 1481 | + role = symtab_search(&pol->p_roles, scontextp); |
---|
1428 | 1482 | if (!role) |
---|
1429 | 1483 | goto out; |
---|
1430 | 1484 | ctx->role = role->value; |
---|
.. | .. |
---|
1436 | 1490 | oldc = *p; |
---|
1437 | 1491 | *p++ = 0; |
---|
1438 | 1492 | |
---|
1439 | | - typdatum = hashtab_search(pol->p_types.table, scontextp); |
---|
| 1493 | + typdatum = symtab_search(&pol->p_types, scontextp); |
---|
1440 | 1494 | if (!typdatum || typdatum->attribute) |
---|
1441 | 1495 | goto out; |
---|
1442 | 1496 | |
---|
.. | .. |
---|
1457 | 1511 | return rc; |
---|
1458 | 1512 | } |
---|
1459 | 1513 | |
---|
1460 | | -int context_add_hash(struct policydb *policydb, |
---|
1461 | | - struct context *context) |
---|
1462 | | -{ |
---|
1463 | | - int rc; |
---|
1464 | | - char *str; |
---|
1465 | | - int len; |
---|
1466 | | - |
---|
1467 | | - if (context->str) { |
---|
1468 | | - context->hash = context_compute_hash(context->str); |
---|
1469 | | - } else { |
---|
1470 | | - rc = context_struct_to_string(policydb, context, |
---|
1471 | | - &str, &len); |
---|
1472 | | - if (rc) |
---|
1473 | | - return rc; |
---|
1474 | | - context->hash = context_compute_hash(str); |
---|
1475 | | - kfree(str); |
---|
1476 | | - } |
---|
1477 | | - return 0; |
---|
1478 | | -} |
---|
1479 | | - |
---|
1480 | | -static int context_struct_to_sid(struct selinux_state *state, |
---|
1481 | | - struct context *context, u32 *sid) |
---|
1482 | | -{ |
---|
1483 | | - int rc; |
---|
1484 | | - struct sidtab *sidtab = state->ss->sidtab; |
---|
1485 | | - struct policydb *policydb = &state->ss->policydb; |
---|
1486 | | - |
---|
1487 | | - if (!context->hash) { |
---|
1488 | | - rc = context_add_hash(policydb, context); |
---|
1489 | | - if (rc) |
---|
1490 | | - return rc; |
---|
1491 | | - } |
---|
1492 | | - |
---|
1493 | | - return sidtab_context_to_sid(sidtab, context, sid); |
---|
1494 | | -} |
---|
1495 | | - |
---|
1496 | 1514 | static int security_context_to_sid_core(struct selinux_state *state, |
---|
1497 | 1515 | const char *scontext, u32 scontext_len, |
---|
1498 | 1516 | u32 *sid, u32 def_sid, gfp_t gfp_flags, |
---|
1499 | 1517 | int force) |
---|
1500 | 1518 | { |
---|
| 1519 | + struct selinux_policy *policy; |
---|
1501 | 1520 | struct policydb *policydb; |
---|
1502 | 1521 | struct sidtab *sidtab; |
---|
1503 | 1522 | char *scontext2, *str = NULL; |
---|
.. | .. |
---|
1513 | 1532 | if (!scontext2) |
---|
1514 | 1533 | return -ENOMEM; |
---|
1515 | 1534 | |
---|
1516 | | - if (!state->initialized) { |
---|
| 1535 | + if (!selinux_initialized(state)) { |
---|
1517 | 1536 | int i; |
---|
1518 | 1537 | |
---|
1519 | 1538 | for (i = 1; i < SECINITSID_NUM; i++) { |
---|
1520 | | - if (!strcmp(initial_sid_to_string[i], scontext2)) { |
---|
| 1539 | + const char *s = initial_sid_to_string[i]; |
---|
| 1540 | + |
---|
| 1541 | + if (s && !strcmp(s, scontext2)) { |
---|
1521 | 1542 | *sid = i; |
---|
1522 | 1543 | goto out; |
---|
1523 | 1544 | } |
---|
.. | .. |
---|
1534 | 1555 | if (!str) |
---|
1535 | 1556 | goto out; |
---|
1536 | 1557 | } |
---|
1537 | | - read_lock(&state->ss->policy_rwlock); |
---|
1538 | | - policydb = &state->ss->policydb; |
---|
1539 | | - sidtab = state->ss->sidtab; |
---|
| 1558 | +retry: |
---|
| 1559 | + rcu_read_lock(); |
---|
| 1560 | + policy = rcu_dereference(state->policy); |
---|
| 1561 | + policydb = &policy->policydb; |
---|
| 1562 | + sidtab = policy->sidtab; |
---|
1540 | 1563 | rc = string_to_context_struct(policydb, sidtab, scontext2, |
---|
1541 | 1564 | &context, def_sid); |
---|
1542 | 1565 | if (rc == -EINVAL && force) { |
---|
.. | .. |
---|
1545 | 1568 | str = NULL; |
---|
1546 | 1569 | } else if (rc) |
---|
1547 | 1570 | goto out_unlock; |
---|
1548 | | - rc = context_struct_to_sid(state, &context, sid); |
---|
| 1571 | + rc = sidtab_context_to_sid(sidtab, &context, sid); |
---|
| 1572 | + if (rc == -ESTALE) { |
---|
| 1573 | + rcu_read_unlock(); |
---|
| 1574 | + if (context.str) { |
---|
| 1575 | + str = context.str; |
---|
| 1576 | + context.str = NULL; |
---|
| 1577 | + } |
---|
| 1578 | + context_destroy(&context); |
---|
| 1579 | + goto retry; |
---|
| 1580 | + } |
---|
1549 | 1581 | context_destroy(&context); |
---|
1550 | 1582 | out_unlock: |
---|
1551 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 1583 | + rcu_read_unlock(); |
---|
1552 | 1584 | out: |
---|
1553 | 1585 | kfree(scontext2); |
---|
1554 | 1586 | kfree(str); |
---|
.. | .. |
---|
1618 | 1650 | |
---|
1619 | 1651 | static int compute_sid_handle_invalid_context( |
---|
1620 | 1652 | struct selinux_state *state, |
---|
1621 | | - struct context *scontext, |
---|
1622 | | - struct context *tcontext, |
---|
| 1653 | + struct selinux_policy *policy, |
---|
| 1654 | + struct sidtab_entry *sentry, |
---|
| 1655 | + struct sidtab_entry *tentry, |
---|
1623 | 1656 | u16 tclass, |
---|
1624 | 1657 | struct context *newcontext) |
---|
1625 | 1658 | { |
---|
1626 | | - struct policydb *policydb = &state->ss->policydb; |
---|
| 1659 | + struct policydb *policydb = &policy->policydb; |
---|
| 1660 | + struct sidtab *sidtab = policy->sidtab; |
---|
1627 | 1661 | char *s = NULL, *t = NULL, *n = NULL; |
---|
1628 | 1662 | u32 slen, tlen, nlen; |
---|
| 1663 | + struct audit_buffer *ab; |
---|
1629 | 1664 | |
---|
1630 | | - if (context_struct_to_string(policydb, scontext, &s, &slen)) |
---|
| 1665 | + if (sidtab_entry_to_string(policydb, sidtab, sentry, &s, &slen)) |
---|
1631 | 1666 | goto out; |
---|
1632 | | - if (context_struct_to_string(policydb, tcontext, &t, &tlen)) |
---|
| 1667 | + if (sidtab_entry_to_string(policydb, sidtab, tentry, &t, &tlen)) |
---|
1633 | 1668 | goto out; |
---|
1634 | 1669 | if (context_struct_to_string(policydb, newcontext, &n, &nlen)) |
---|
1635 | 1670 | goto out; |
---|
1636 | | - audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR, |
---|
1637 | | - "op=security_compute_sid invalid_context=%s" |
---|
1638 | | - " scontext=%s" |
---|
1639 | | - " tcontext=%s" |
---|
1640 | | - " tclass=%s", |
---|
1641 | | - n, s, t, sym_name(policydb, SYM_CLASSES, tclass-1)); |
---|
| 1671 | + ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR); |
---|
| 1672 | + audit_log_format(ab, |
---|
| 1673 | + "op=security_compute_sid invalid_context="); |
---|
| 1674 | + /* no need to record the NUL with untrusted strings */ |
---|
| 1675 | + audit_log_n_untrustedstring(ab, n, nlen - 1); |
---|
| 1676 | + audit_log_format(ab, " scontext=%s tcontext=%s tclass=%s", |
---|
| 1677 | + s, t, sym_name(policydb, SYM_CLASSES, tclass-1)); |
---|
| 1678 | + audit_log_end(ab); |
---|
1642 | 1679 | out: |
---|
1643 | 1680 | kfree(s); |
---|
1644 | 1681 | kfree(t); |
---|
.. | .. |
---|
1653 | 1690 | u32 stype, u32 ttype, u16 tclass, |
---|
1654 | 1691 | const char *objname) |
---|
1655 | 1692 | { |
---|
1656 | | - struct filename_trans ft; |
---|
1657 | | - struct filename_trans_datum *otype; |
---|
| 1693 | + struct filename_trans_key ft; |
---|
| 1694 | + struct filename_trans_datum *datum; |
---|
1658 | 1695 | |
---|
1659 | 1696 | /* |
---|
1660 | 1697 | * Most filename trans rules are going to live in specific directories |
---|
.. | .. |
---|
1664 | 1701 | if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype)) |
---|
1665 | 1702 | return; |
---|
1666 | 1703 | |
---|
1667 | | - ft.stype = stype; |
---|
1668 | 1704 | ft.ttype = ttype; |
---|
1669 | 1705 | ft.tclass = tclass; |
---|
1670 | 1706 | ft.name = objname; |
---|
1671 | 1707 | |
---|
1672 | | - otype = hashtab_search(policydb->filename_trans, &ft); |
---|
1673 | | - if (otype) |
---|
1674 | | - newcontext->type = otype->otype; |
---|
| 1708 | + datum = policydb_filenametr_search(policydb, &ft); |
---|
| 1709 | + while (datum) { |
---|
| 1710 | + if (ebitmap_get_bit(&datum->stypes, stype - 1)) { |
---|
| 1711 | + newcontext->type = datum->otype; |
---|
| 1712 | + return; |
---|
| 1713 | + } |
---|
| 1714 | + datum = datum->next; |
---|
| 1715 | + } |
---|
1675 | 1716 | } |
---|
1676 | 1717 | |
---|
1677 | 1718 | static int security_compute_sid(struct selinux_state *state, |
---|
.. | .. |
---|
1683 | 1724 | u32 *out_sid, |
---|
1684 | 1725 | bool kern) |
---|
1685 | 1726 | { |
---|
| 1727 | + struct selinux_policy *policy; |
---|
1686 | 1728 | struct policydb *policydb; |
---|
1687 | 1729 | struct sidtab *sidtab; |
---|
1688 | | - struct class_datum *cladatum = NULL; |
---|
1689 | | - struct context *scontext = NULL, *tcontext = NULL, newcontext; |
---|
1690 | | - struct role_trans *roletr = NULL; |
---|
| 1730 | + struct class_datum *cladatum; |
---|
| 1731 | + struct context *scontext, *tcontext, newcontext; |
---|
| 1732 | + struct sidtab_entry *sentry, *tentry; |
---|
1691 | 1733 | struct avtab_key avkey; |
---|
1692 | 1734 | struct avtab_datum *avdatum; |
---|
1693 | 1735 | struct avtab_node *node; |
---|
.. | .. |
---|
1695 | 1737 | int rc = 0; |
---|
1696 | 1738 | bool sock; |
---|
1697 | 1739 | |
---|
1698 | | - if (!state->initialized) { |
---|
| 1740 | + if (!selinux_initialized(state)) { |
---|
1699 | 1741 | switch (orig_tclass) { |
---|
1700 | 1742 | case SECCLASS_PROCESS: /* kernel value */ |
---|
1701 | 1743 | *out_sid = ssid; |
---|
.. | .. |
---|
1707 | 1749 | goto out; |
---|
1708 | 1750 | } |
---|
1709 | 1751 | |
---|
| 1752 | +retry: |
---|
| 1753 | + cladatum = NULL; |
---|
1710 | 1754 | context_init(&newcontext); |
---|
1711 | 1755 | |
---|
1712 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 1756 | + rcu_read_lock(); |
---|
| 1757 | + |
---|
| 1758 | + policy = rcu_dereference(state->policy); |
---|
1713 | 1759 | |
---|
1714 | 1760 | if (kern) { |
---|
1715 | | - tclass = unmap_class(&state->ss->map, orig_tclass); |
---|
| 1761 | + tclass = unmap_class(&policy->map, orig_tclass); |
---|
1716 | 1762 | sock = security_is_socket_class(orig_tclass); |
---|
1717 | 1763 | } else { |
---|
1718 | 1764 | tclass = orig_tclass; |
---|
1719 | | - sock = security_is_socket_class(map_class(&state->ss->map, |
---|
| 1765 | + sock = security_is_socket_class(map_class(&policy->map, |
---|
1720 | 1766 | tclass)); |
---|
1721 | 1767 | } |
---|
1722 | 1768 | |
---|
1723 | | - policydb = &state->ss->policydb; |
---|
1724 | | - sidtab = state->ss->sidtab; |
---|
| 1769 | + policydb = &policy->policydb; |
---|
| 1770 | + sidtab = policy->sidtab; |
---|
1725 | 1771 | |
---|
1726 | | - scontext = sidtab_search(sidtab, ssid); |
---|
1727 | | - if (!scontext) { |
---|
| 1772 | + sentry = sidtab_search_entry(sidtab, ssid); |
---|
| 1773 | + if (!sentry) { |
---|
1728 | 1774 | pr_err("SELinux: %s: unrecognized SID %d\n", |
---|
1729 | 1775 | __func__, ssid); |
---|
1730 | 1776 | rc = -EINVAL; |
---|
1731 | 1777 | goto out_unlock; |
---|
1732 | 1778 | } |
---|
1733 | | - tcontext = sidtab_search(sidtab, tsid); |
---|
1734 | | - if (!tcontext) { |
---|
| 1779 | + tentry = sidtab_search_entry(sidtab, tsid); |
---|
| 1780 | + if (!tentry) { |
---|
1735 | 1781 | pr_err("SELinux: %s: unrecognized SID %d\n", |
---|
1736 | 1782 | __func__, tsid); |
---|
1737 | 1783 | rc = -EINVAL; |
---|
1738 | 1784 | goto out_unlock; |
---|
1739 | 1785 | } |
---|
| 1786 | + |
---|
| 1787 | + scontext = &sentry->context; |
---|
| 1788 | + tcontext = &tentry->context; |
---|
1740 | 1789 | |
---|
1741 | 1790 | if (tclass && tclass <= policydb->p_classes.nprim) |
---|
1742 | 1791 | cladatum = policydb->class_val_to_struct[tclass - 1]; |
---|
.. | .. |
---|
1765 | 1814 | } else if (cladatum && cladatum->default_role == DEFAULT_TARGET) { |
---|
1766 | 1815 | newcontext.role = tcontext->role; |
---|
1767 | 1816 | } else { |
---|
1768 | | - if ((tclass == policydb->process_class) || (sock == true)) |
---|
| 1817 | + if ((tclass == policydb->process_class) || sock) |
---|
1769 | 1818 | newcontext.role = scontext->role; |
---|
1770 | 1819 | else |
---|
1771 | 1820 | newcontext.role = OBJECT_R_VAL; |
---|
.. | .. |
---|
1777 | 1826 | } else if (cladatum && cladatum->default_type == DEFAULT_TARGET) { |
---|
1778 | 1827 | newcontext.type = tcontext->type; |
---|
1779 | 1828 | } else { |
---|
1780 | | - if ((tclass == policydb->process_class) || (sock == true)) { |
---|
| 1829 | + if ((tclass == policydb->process_class) || sock) { |
---|
1781 | 1830 | /* Use the type of process. */ |
---|
1782 | 1831 | newcontext.type = scontext->type; |
---|
1783 | 1832 | } else { |
---|
.. | .. |
---|
1817 | 1866 | /* Check for class-specific changes. */ |
---|
1818 | 1867 | if (specified & AVTAB_TRANSITION) { |
---|
1819 | 1868 | /* Look for a role transition rule. */ |
---|
1820 | | - for (roletr = policydb->role_tr; roletr; |
---|
1821 | | - roletr = roletr->next) { |
---|
1822 | | - if ((roletr->role == scontext->role) && |
---|
1823 | | - (roletr->type == tcontext->type) && |
---|
1824 | | - (roletr->tclass == tclass)) { |
---|
1825 | | - /* Use the role transition rule. */ |
---|
1826 | | - newcontext.role = roletr->new_role; |
---|
1827 | | - break; |
---|
1828 | | - } |
---|
1829 | | - } |
---|
| 1869 | + struct role_trans_datum *rtd; |
---|
| 1870 | + struct role_trans_key rtk = { |
---|
| 1871 | + .role = scontext->role, |
---|
| 1872 | + .type = tcontext->type, |
---|
| 1873 | + .tclass = tclass, |
---|
| 1874 | + }; |
---|
| 1875 | + |
---|
| 1876 | + rtd = policydb_roletr_search(policydb, &rtk); |
---|
| 1877 | + if (rtd) |
---|
| 1878 | + newcontext.role = rtd->new_role; |
---|
1830 | 1879 | } |
---|
1831 | 1880 | |
---|
1832 | 1881 | /* Set the MLS attributes. |
---|
.. | .. |
---|
1838 | 1887 | |
---|
1839 | 1888 | /* Check the validity of the context. */ |
---|
1840 | 1889 | if (!policydb_context_isvalid(policydb, &newcontext)) { |
---|
1841 | | - rc = compute_sid_handle_invalid_context(state, scontext, |
---|
1842 | | - tcontext, |
---|
1843 | | - tclass, |
---|
| 1890 | + rc = compute_sid_handle_invalid_context(state, policy, sentry, |
---|
| 1891 | + tentry, tclass, |
---|
1844 | 1892 | &newcontext); |
---|
1845 | 1893 | if (rc) |
---|
1846 | 1894 | goto out_unlock; |
---|
1847 | 1895 | } |
---|
1848 | 1896 | /* Obtain the sid for the context. */ |
---|
1849 | | - rc = context_struct_to_sid(state, &newcontext, out_sid); |
---|
| 1897 | + rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid); |
---|
| 1898 | + if (rc == -ESTALE) { |
---|
| 1899 | + rcu_read_unlock(); |
---|
| 1900 | + context_destroy(&newcontext); |
---|
| 1901 | + goto retry; |
---|
| 1902 | + } |
---|
1850 | 1903 | out_unlock: |
---|
1851 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 1904 | + rcu_read_unlock(); |
---|
1852 | 1905 | context_destroy(&newcontext); |
---|
1853 | 1906 | out: |
---|
1854 | 1907 | return rc; |
---|
.. | .. |
---|
1935 | 1988 | |
---|
1936 | 1989 | static inline int convert_context_handle_invalid_context( |
---|
1937 | 1990 | struct selinux_state *state, |
---|
| 1991 | + struct policydb *policydb, |
---|
1938 | 1992 | struct context *context) |
---|
1939 | 1993 | { |
---|
1940 | | - struct policydb *policydb = &state->ss->policydb; |
---|
1941 | 1994 | char *s; |
---|
1942 | 1995 | u32 len; |
---|
1943 | 1996 | |
---|
.. | .. |
---|
1952 | 2005 | return 0; |
---|
1953 | 2006 | } |
---|
1954 | 2007 | |
---|
1955 | | -struct convert_context_args { |
---|
1956 | | - struct selinux_state *state; |
---|
1957 | | - struct policydb *oldp; |
---|
1958 | | - struct policydb *newp; |
---|
1959 | | -}; |
---|
1960 | | - |
---|
1961 | 2008 | /* |
---|
1962 | 2009 | * Convert the values in the security context |
---|
1963 | 2010 | * structure `oldc' from the values specified |
---|
.. | .. |
---|
1966 | 2013 | * in `newc'. Verify that the context is valid |
---|
1967 | 2014 | * under the new policy. |
---|
1968 | 2015 | */ |
---|
1969 | | -static int convert_context(struct context *oldc, struct context *newc, void *p) |
---|
| 2016 | +static int convert_context(struct context *oldc, struct context *newc, void *p, |
---|
| 2017 | + gfp_t gfp_flags) |
---|
1970 | 2018 | { |
---|
1971 | 2019 | struct convert_context_args *args; |
---|
1972 | 2020 | struct ocontext *oc; |
---|
.. | .. |
---|
1980 | 2028 | args = p; |
---|
1981 | 2029 | |
---|
1982 | 2030 | if (oldc->str) { |
---|
1983 | | - s = kstrdup(oldc->str, GFP_KERNEL); |
---|
| 2031 | + s = kstrdup(oldc->str, gfp_flags); |
---|
1984 | 2032 | if (!s) |
---|
1985 | 2033 | return -ENOMEM; |
---|
1986 | 2034 | |
---|
.. | .. |
---|
1998 | 2046 | context_init(newc); |
---|
1999 | 2047 | newc->str = s; |
---|
2000 | 2048 | newc->len = oldc->len; |
---|
2001 | | - newc->hash = oldc->hash; |
---|
2002 | 2049 | return 0; |
---|
2003 | 2050 | } |
---|
2004 | 2051 | kfree(s); |
---|
.. | .. |
---|
2017 | 2064 | |
---|
2018 | 2065 | /* Convert the user. */ |
---|
2019 | 2066 | rc = -EINVAL; |
---|
2020 | | - usrdatum = hashtab_search(args->newp->p_users.table, |
---|
2021 | | - sym_name(args->oldp, |
---|
2022 | | - SYM_USERS, oldc->user - 1)); |
---|
| 2067 | + usrdatum = symtab_search(&args->newp->p_users, |
---|
| 2068 | + sym_name(args->oldp, |
---|
| 2069 | + SYM_USERS, oldc->user - 1)); |
---|
2023 | 2070 | if (!usrdatum) |
---|
2024 | 2071 | goto bad; |
---|
2025 | 2072 | newc->user = usrdatum->value; |
---|
2026 | 2073 | |
---|
2027 | 2074 | /* Convert the role. */ |
---|
2028 | 2075 | rc = -EINVAL; |
---|
2029 | | - role = hashtab_search(args->newp->p_roles.table, |
---|
2030 | | - sym_name(args->oldp, SYM_ROLES, oldc->role - 1)); |
---|
| 2076 | + role = symtab_search(&args->newp->p_roles, |
---|
| 2077 | + sym_name(args->oldp, SYM_ROLES, oldc->role - 1)); |
---|
2031 | 2078 | if (!role) |
---|
2032 | 2079 | goto bad; |
---|
2033 | 2080 | newc->role = role->value; |
---|
2034 | 2081 | |
---|
2035 | 2082 | /* Convert the type. */ |
---|
2036 | 2083 | rc = -EINVAL; |
---|
2037 | | - typdatum = hashtab_search(args->newp->p_types.table, |
---|
2038 | | - sym_name(args->oldp, |
---|
2039 | | - SYM_TYPES, oldc->type - 1)); |
---|
| 2084 | + typdatum = symtab_search(&args->newp->p_types, |
---|
| 2085 | + sym_name(args->oldp, |
---|
| 2086 | + SYM_TYPES, oldc->type - 1)); |
---|
2040 | 2087 | if (!typdatum) |
---|
2041 | 2088 | goto bad; |
---|
2042 | 2089 | newc->type = typdatum->value; |
---|
.. | .. |
---|
2070 | 2117 | |
---|
2071 | 2118 | /* Check the validity of the new context. */ |
---|
2072 | 2119 | if (!policydb_context_isvalid(args->newp, newc)) { |
---|
2073 | | - rc = convert_context_handle_invalid_context(args->state, oldc); |
---|
| 2120 | + rc = convert_context_handle_invalid_context(args->state, |
---|
| 2121 | + args->oldp, |
---|
| 2122 | + oldc); |
---|
2074 | 2123 | if (rc) |
---|
2075 | 2124 | goto bad; |
---|
2076 | 2125 | } |
---|
2077 | | - |
---|
2078 | | - rc = context_add_hash(args->newp, newc); |
---|
2079 | | - if (rc) |
---|
2080 | | - goto bad; |
---|
2081 | 2126 | |
---|
2082 | 2127 | return 0; |
---|
2083 | 2128 | bad: |
---|
.. | .. |
---|
2088 | 2133 | context_destroy(newc); |
---|
2089 | 2134 | newc->str = s; |
---|
2090 | 2135 | newc->len = len; |
---|
2091 | | - newc->hash = context_compute_hash(s); |
---|
2092 | 2136 | pr_info("SELinux: Context %s became invalid (unmapped).\n", |
---|
2093 | 2137 | newc->str); |
---|
2094 | 2138 | return 0; |
---|
2095 | 2139 | } |
---|
2096 | 2140 | |
---|
2097 | | -static void security_load_policycaps(struct selinux_state *state) |
---|
| 2141 | +static void security_load_policycaps(struct selinux_state *state, |
---|
| 2142 | + struct selinux_policy *policy) |
---|
2098 | 2143 | { |
---|
2099 | | - struct policydb *p = &state->ss->policydb; |
---|
| 2144 | + struct policydb *p; |
---|
2100 | 2145 | unsigned int i; |
---|
2101 | 2146 | struct ebitmap_node *node; |
---|
2102 | 2147 | |
---|
| 2148 | + p = &policy->policydb; |
---|
| 2149 | + |
---|
2103 | 2150 | for (i = 0; i < ARRAY_SIZE(state->policycap); i++) |
---|
2104 | | - state->policycap[i] = ebitmap_get_bit(&p->policycaps, i); |
---|
| 2151 | + WRITE_ONCE(state->policycap[i], |
---|
| 2152 | + ebitmap_get_bit(&p->policycaps, i)); |
---|
2105 | 2153 | |
---|
2106 | 2154 | for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++) |
---|
2107 | 2155 | pr_info("SELinux: policy capability %s=%d\n", |
---|
.. | .. |
---|
2119 | 2167 | selinux_nlmsg_init(); |
---|
2120 | 2168 | } |
---|
2121 | 2169 | |
---|
2122 | | -static int security_preserve_bools(struct selinux_state *state, |
---|
2123 | | - struct policydb *newpolicydb); |
---|
| 2170 | +static int security_preserve_bools(struct selinux_policy *oldpolicy, |
---|
| 2171 | + struct selinux_policy *newpolicy); |
---|
| 2172 | + |
---|
| 2173 | +static void selinux_policy_free(struct selinux_policy *policy) |
---|
| 2174 | +{ |
---|
| 2175 | + if (!policy) |
---|
| 2176 | + return; |
---|
| 2177 | + |
---|
| 2178 | + sidtab_destroy(policy->sidtab); |
---|
| 2179 | + kfree(policy->map.mapping); |
---|
| 2180 | + policydb_destroy(&policy->policydb); |
---|
| 2181 | + kfree(policy->sidtab); |
---|
| 2182 | + kfree(policy); |
---|
| 2183 | +} |
---|
| 2184 | + |
---|
| 2185 | +static void selinux_policy_cond_free(struct selinux_policy *policy) |
---|
| 2186 | +{ |
---|
| 2187 | + cond_policydb_destroy_dup(&policy->policydb); |
---|
| 2188 | + kfree(policy); |
---|
| 2189 | +} |
---|
| 2190 | + |
---|
| 2191 | +void selinux_policy_cancel(struct selinux_state *state, |
---|
| 2192 | + struct selinux_load_state *load_state) |
---|
| 2193 | +{ |
---|
| 2194 | + struct selinux_policy *oldpolicy; |
---|
| 2195 | + |
---|
| 2196 | + oldpolicy = rcu_dereference_protected(state->policy, |
---|
| 2197 | + lockdep_is_held(&state->policy_mutex)); |
---|
| 2198 | + |
---|
| 2199 | + sidtab_cancel_convert(oldpolicy->sidtab); |
---|
| 2200 | + selinux_policy_free(load_state->policy); |
---|
| 2201 | + kfree(load_state->convert_data); |
---|
| 2202 | +} |
---|
| 2203 | + |
---|
| 2204 | +static void selinux_notify_policy_change(struct selinux_state *state, |
---|
| 2205 | + u32 seqno) |
---|
| 2206 | +{ |
---|
| 2207 | + /* Flush external caches and notify userspace of policy load */ |
---|
| 2208 | + avc_ss_reset(state->avc, seqno); |
---|
| 2209 | + selnl_notify_policyload(seqno); |
---|
| 2210 | + selinux_status_update_policyload(state, seqno); |
---|
| 2211 | + selinux_netlbl_cache_invalidate(); |
---|
| 2212 | + selinux_xfrm_notify_policyload(); |
---|
| 2213 | +} |
---|
| 2214 | + |
---|
| 2215 | +void selinux_policy_commit(struct selinux_state *state, |
---|
| 2216 | + struct selinux_load_state *load_state) |
---|
| 2217 | +{ |
---|
| 2218 | + struct selinux_policy *oldpolicy, *newpolicy = load_state->policy; |
---|
| 2219 | + unsigned long flags; |
---|
| 2220 | + u32 seqno; |
---|
| 2221 | + |
---|
| 2222 | + oldpolicy = rcu_dereference_protected(state->policy, |
---|
| 2223 | + lockdep_is_held(&state->policy_mutex)); |
---|
| 2224 | + |
---|
| 2225 | + /* If switching between different policy types, log MLS status */ |
---|
| 2226 | + if (oldpolicy) { |
---|
| 2227 | + if (oldpolicy->policydb.mls_enabled && !newpolicy->policydb.mls_enabled) |
---|
| 2228 | + pr_info("SELinux: Disabling MLS support...\n"); |
---|
| 2229 | + else if (!oldpolicy->policydb.mls_enabled && newpolicy->policydb.mls_enabled) |
---|
| 2230 | + pr_info("SELinux: Enabling MLS support...\n"); |
---|
| 2231 | + } |
---|
| 2232 | + |
---|
| 2233 | + /* Set latest granting seqno for new policy. */ |
---|
| 2234 | + if (oldpolicy) |
---|
| 2235 | + newpolicy->latest_granting = oldpolicy->latest_granting + 1; |
---|
| 2236 | + else |
---|
| 2237 | + newpolicy->latest_granting = 1; |
---|
| 2238 | + seqno = newpolicy->latest_granting; |
---|
| 2239 | + |
---|
| 2240 | + /* Install the new policy. */ |
---|
| 2241 | + if (oldpolicy) { |
---|
| 2242 | + sidtab_freeze_begin(oldpolicy->sidtab, &flags); |
---|
| 2243 | + rcu_assign_pointer(state->policy, newpolicy); |
---|
| 2244 | + sidtab_freeze_end(oldpolicy->sidtab, &flags); |
---|
| 2245 | + } else { |
---|
| 2246 | + rcu_assign_pointer(state->policy, newpolicy); |
---|
| 2247 | + } |
---|
| 2248 | + |
---|
| 2249 | + /* Load the policycaps from the new policy */ |
---|
| 2250 | + security_load_policycaps(state, newpolicy); |
---|
| 2251 | + |
---|
| 2252 | + if (!selinux_initialized(state)) { |
---|
| 2253 | + /* |
---|
| 2254 | + * After first policy load, the security server is |
---|
| 2255 | + * marked as initialized and ready to handle requests and |
---|
| 2256 | + * any objects created prior to policy load are then labeled. |
---|
| 2257 | + */ |
---|
| 2258 | + selinux_mark_initialized(state); |
---|
| 2259 | + selinux_complete_init(); |
---|
| 2260 | + trace_android_vh_selinux_is_initialized(state); |
---|
| 2261 | + } |
---|
| 2262 | + |
---|
| 2263 | + /* Free the old policy */ |
---|
| 2264 | + synchronize_rcu(); |
---|
| 2265 | + selinux_policy_free(oldpolicy); |
---|
| 2266 | + kfree(load_state->convert_data); |
---|
| 2267 | + |
---|
| 2268 | + /* Notify others of the policy change */ |
---|
| 2269 | + selinux_notify_policy_change(state, seqno); |
---|
| 2270 | +} |
---|
2124 | 2271 | |
---|
2125 | 2272 | /** |
---|
2126 | 2273 | * security_load_policy - Load a security policy configuration. |
---|
.. | .. |
---|
2132 | 2279 | * This function will flush the access vector cache after |
---|
2133 | 2280 | * loading the new policy. |
---|
2134 | 2281 | */ |
---|
2135 | | -int security_load_policy(struct selinux_state *state, void *data, size_t len) |
---|
| 2282 | +int security_load_policy(struct selinux_state *state, void *data, size_t len, |
---|
| 2283 | + struct selinux_load_state *load_state) |
---|
2136 | 2284 | { |
---|
2137 | | - struct policydb *policydb; |
---|
2138 | | - struct sidtab *oldsidtab, *newsidtab; |
---|
2139 | | - struct policydb *oldpolicydb, *newpolicydb; |
---|
2140 | | - struct selinux_mapping *oldmapping; |
---|
2141 | | - struct selinux_map newmap; |
---|
2142 | | - struct sidtab_convert_params convert_params; |
---|
2143 | | - struct convert_context_args args; |
---|
2144 | | - u32 seqno; |
---|
| 2285 | + struct selinux_policy *newpolicy, *oldpolicy; |
---|
| 2286 | + struct selinux_policy_convert_data *convert_data; |
---|
2145 | 2287 | int rc = 0; |
---|
2146 | 2288 | struct policy_file file = { data, len }, *fp = &file; |
---|
2147 | 2289 | |
---|
2148 | | - oldpolicydb = kcalloc(2, sizeof(*oldpolicydb), GFP_KERNEL); |
---|
2149 | | - if (!oldpolicydb) { |
---|
| 2290 | + newpolicy = kzalloc(sizeof(*newpolicy), GFP_KERNEL); |
---|
| 2291 | + if (!newpolicy) |
---|
| 2292 | + return -ENOMEM; |
---|
| 2293 | + |
---|
| 2294 | + newpolicy->sidtab = kzalloc(sizeof(*newpolicy->sidtab), GFP_KERNEL); |
---|
| 2295 | + if (!newpolicy->sidtab) { |
---|
2150 | 2296 | rc = -ENOMEM; |
---|
2151 | | - goto out; |
---|
2152 | | - } |
---|
2153 | | - newpolicydb = oldpolicydb + 1; |
---|
2154 | | - |
---|
2155 | | - policydb = &state->ss->policydb; |
---|
2156 | | - |
---|
2157 | | - newsidtab = kmalloc(sizeof(*newsidtab), GFP_KERNEL); |
---|
2158 | | - if (!newsidtab) { |
---|
2159 | | - rc = -ENOMEM; |
---|
2160 | | - goto out; |
---|
| 2297 | + goto err_policy; |
---|
2161 | 2298 | } |
---|
2162 | 2299 | |
---|
2163 | | - if (!state->initialized) { |
---|
2164 | | - rc = policydb_read(policydb, fp); |
---|
2165 | | - if (rc) { |
---|
2166 | | - kfree(newsidtab); |
---|
2167 | | - goto out; |
---|
2168 | | - } |
---|
| 2300 | + rc = policydb_read(&newpolicy->policydb, fp); |
---|
| 2301 | + if (rc) |
---|
| 2302 | + goto err_sidtab; |
---|
2169 | 2303 | |
---|
2170 | | - policydb->len = len; |
---|
2171 | | - rc = selinux_set_mapping(policydb, secclass_map, |
---|
2172 | | - &state->ss->map); |
---|
2173 | | - if (rc) { |
---|
2174 | | - kfree(newsidtab); |
---|
2175 | | - policydb_destroy(policydb); |
---|
2176 | | - goto out; |
---|
2177 | | - } |
---|
| 2304 | + newpolicy->policydb.len = len; |
---|
| 2305 | + rc = selinux_set_mapping(&newpolicy->policydb, secclass_map, |
---|
| 2306 | + &newpolicy->map); |
---|
| 2307 | + if (rc) |
---|
| 2308 | + goto err_policydb; |
---|
2178 | 2309 | |
---|
2179 | | - rc = policydb_load_isids(policydb, newsidtab); |
---|
2180 | | - if (rc) { |
---|
2181 | | - kfree(newsidtab); |
---|
2182 | | - policydb_destroy(policydb); |
---|
2183 | | - goto out; |
---|
2184 | | - } |
---|
2185 | | - |
---|
2186 | | - state->ss->sidtab = newsidtab; |
---|
2187 | | - security_load_policycaps(state); |
---|
2188 | | - state->initialized = 1; |
---|
2189 | | - seqno = ++state->ss->latest_granting; |
---|
2190 | | - selinux_complete_init(); |
---|
2191 | | - avc_ss_reset(state->avc, seqno); |
---|
2192 | | - selnl_notify_policyload(seqno); |
---|
2193 | | - selinux_status_update_policyload(state, seqno); |
---|
2194 | | - selinux_netlbl_cache_invalidate(); |
---|
2195 | | - selinux_xfrm_notify_policyload(); |
---|
2196 | | - goto out; |
---|
2197 | | - } |
---|
2198 | | - |
---|
2199 | | - rc = policydb_read(newpolicydb, fp); |
---|
2200 | | - if (rc) { |
---|
2201 | | - kfree(newsidtab); |
---|
2202 | | - goto out; |
---|
2203 | | - } |
---|
2204 | | - |
---|
2205 | | - newpolicydb->len = len; |
---|
2206 | | - /* If switching between different policy types, log MLS status */ |
---|
2207 | | - if (policydb->mls_enabled && !newpolicydb->mls_enabled) |
---|
2208 | | - pr_info("SELinux: Disabling MLS support...\n"); |
---|
2209 | | - else if (!policydb->mls_enabled && newpolicydb->mls_enabled) |
---|
2210 | | - pr_info("SELinux: Enabling MLS support...\n"); |
---|
2211 | | - |
---|
2212 | | - rc = policydb_load_isids(newpolicydb, newsidtab); |
---|
| 2310 | + rc = policydb_load_isids(&newpolicy->policydb, newpolicy->sidtab); |
---|
2213 | 2311 | if (rc) { |
---|
2214 | 2312 | pr_err("SELinux: unable to load the initial SIDs\n"); |
---|
2215 | | - policydb_destroy(newpolicydb); |
---|
2216 | | - kfree(newsidtab); |
---|
2217 | | - goto out; |
---|
| 2313 | + goto err_mapping; |
---|
2218 | 2314 | } |
---|
2219 | 2315 | |
---|
2220 | | - rc = selinux_set_mapping(newpolicydb, secclass_map, &newmap); |
---|
2221 | | - if (rc) |
---|
2222 | | - goto err; |
---|
| 2316 | + if (!selinux_initialized(state)) { |
---|
| 2317 | + /* First policy load, so no need to preserve state from old policy */ |
---|
| 2318 | + load_state->policy = newpolicy; |
---|
| 2319 | + load_state->convert_data = NULL; |
---|
| 2320 | + return 0; |
---|
| 2321 | + } |
---|
2223 | 2322 | |
---|
2224 | | - rc = security_preserve_bools(state, newpolicydb); |
---|
| 2323 | + oldpolicy = rcu_dereference_protected(state->policy, |
---|
| 2324 | + lockdep_is_held(&state->policy_mutex)); |
---|
| 2325 | + |
---|
| 2326 | + /* Preserve active boolean values from the old policy */ |
---|
| 2327 | + rc = security_preserve_bools(oldpolicy, newpolicy); |
---|
2225 | 2328 | if (rc) { |
---|
2226 | 2329 | pr_err("SELinux: unable to preserve booleans\n"); |
---|
2227 | | - goto err; |
---|
| 2330 | + goto err_free_isids; |
---|
2228 | 2331 | } |
---|
2229 | 2332 | |
---|
2230 | | - oldsidtab = state->ss->sidtab; |
---|
| 2333 | + convert_data = kmalloc(sizeof(*convert_data), GFP_KERNEL); |
---|
| 2334 | + if (!convert_data) { |
---|
| 2335 | + rc = -ENOMEM; |
---|
| 2336 | + goto err_free_isids; |
---|
| 2337 | + } |
---|
2231 | 2338 | |
---|
2232 | 2339 | /* |
---|
2233 | 2340 | * Convert the internal representations of contexts |
---|
2234 | 2341 | * in the new SID table. |
---|
2235 | 2342 | */ |
---|
2236 | | - args.state = state; |
---|
2237 | | - args.oldp = policydb; |
---|
2238 | | - args.newp = newpolicydb; |
---|
| 2343 | + convert_data->args.state = state; |
---|
| 2344 | + convert_data->args.oldp = &oldpolicy->policydb; |
---|
| 2345 | + convert_data->args.newp = &newpolicy->policydb; |
---|
2239 | 2346 | |
---|
2240 | | - convert_params.func = convert_context; |
---|
2241 | | - convert_params.args = &args; |
---|
2242 | | - convert_params.target = newsidtab; |
---|
| 2347 | + convert_data->sidtab_params.func = convert_context; |
---|
| 2348 | + convert_data->sidtab_params.args = &convert_data->args; |
---|
| 2349 | + convert_data->sidtab_params.target = newpolicy->sidtab; |
---|
2243 | 2350 | |
---|
2244 | | - rc = sidtab_convert(oldsidtab, &convert_params); |
---|
| 2351 | + rc = sidtab_convert(oldpolicy->sidtab, &convert_data->sidtab_params); |
---|
2245 | 2352 | if (rc) { |
---|
2246 | 2353 | pr_err("SELinux: unable to convert the internal" |
---|
2247 | 2354 | " representation of contexts in the new SID" |
---|
2248 | 2355 | " table\n"); |
---|
2249 | | - goto err; |
---|
| 2356 | + goto err_free_convert_data; |
---|
2250 | 2357 | } |
---|
2251 | 2358 | |
---|
2252 | | - /* Save the old policydb and SID table to free later. */ |
---|
2253 | | - memcpy(oldpolicydb, policydb, sizeof(*policydb)); |
---|
| 2359 | + load_state->policy = newpolicy; |
---|
| 2360 | + load_state->convert_data = convert_data; |
---|
| 2361 | + return 0; |
---|
2254 | 2362 | |
---|
2255 | | - /* Install the new policydb and SID table. */ |
---|
2256 | | - write_lock_irq(&state->ss->policy_rwlock); |
---|
2257 | | - memcpy(policydb, newpolicydb, sizeof(*policydb)); |
---|
2258 | | - state->ss->sidtab = newsidtab; |
---|
2259 | | - security_load_policycaps(state); |
---|
2260 | | - oldmapping = state->ss->map.mapping; |
---|
2261 | | - state->ss->map.mapping = newmap.mapping; |
---|
2262 | | - state->ss->map.size = newmap.size; |
---|
2263 | | - seqno = ++state->ss->latest_granting; |
---|
2264 | | - write_unlock_irq(&state->ss->policy_rwlock); |
---|
| 2363 | +err_free_convert_data: |
---|
| 2364 | + kfree(convert_data); |
---|
| 2365 | +err_free_isids: |
---|
| 2366 | + sidtab_destroy(newpolicy->sidtab); |
---|
| 2367 | +err_mapping: |
---|
| 2368 | + kfree(newpolicy->map.mapping); |
---|
| 2369 | +err_policydb: |
---|
| 2370 | + policydb_destroy(&newpolicy->policydb); |
---|
| 2371 | +err_sidtab: |
---|
| 2372 | + kfree(newpolicy->sidtab); |
---|
| 2373 | +err_policy: |
---|
| 2374 | + kfree(newpolicy); |
---|
2265 | 2375 | |
---|
2266 | | - /* Free the old policydb and SID table. */ |
---|
2267 | | - policydb_destroy(oldpolicydb); |
---|
2268 | | - sidtab_destroy(oldsidtab); |
---|
2269 | | - kfree(oldsidtab); |
---|
2270 | | - kfree(oldmapping); |
---|
2271 | | - |
---|
2272 | | - avc_ss_reset(state->avc, seqno); |
---|
2273 | | - selnl_notify_policyload(seqno); |
---|
2274 | | - selinux_status_update_policyload(state, seqno); |
---|
2275 | | - selinux_netlbl_cache_invalidate(); |
---|
2276 | | - selinux_xfrm_notify_policyload(); |
---|
2277 | | - |
---|
2278 | | - rc = 0; |
---|
2279 | | - goto out; |
---|
2280 | | - |
---|
2281 | | -err: |
---|
2282 | | - kfree(newmap.mapping); |
---|
2283 | | - sidtab_destroy(newsidtab); |
---|
2284 | | - kfree(newsidtab); |
---|
2285 | | - policydb_destroy(newpolicydb); |
---|
2286 | | - |
---|
2287 | | -out: |
---|
2288 | | - kfree(oldpolicydb); |
---|
2289 | 2376 | return rc; |
---|
2290 | 2377 | } |
---|
2291 | 2378 | |
---|
2292 | | -size_t security_policydb_len(struct selinux_state *state) |
---|
| 2379 | +/** |
---|
| 2380 | + * ocontext_to_sid - Helper to safely get sid for an ocontext |
---|
| 2381 | + * @sidtab: SID table |
---|
| 2382 | + * @c: ocontext structure |
---|
| 2383 | + * @index: index of the context entry (0 or 1) |
---|
| 2384 | + * @out_sid: pointer to the resulting SID value |
---|
| 2385 | + * |
---|
| 2386 | + * For all ocontexts except OCON_ISID the SID fields are populated |
---|
| 2387 | + * on-demand when needed. Since updating the SID value is an SMP-sensitive |
---|
| 2388 | + * operation, this helper must be used to do that safely. |
---|
| 2389 | + * |
---|
| 2390 | + * WARNING: This function may return -ESTALE, indicating that the caller |
---|
| 2391 | + * must retry the operation after re-acquiring the policy pointer! |
---|
| 2392 | + */ |
---|
| 2393 | +static int ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c, |
---|
| 2394 | + size_t index, u32 *out_sid) |
---|
2293 | 2395 | { |
---|
2294 | | - struct policydb *p = &state->ss->policydb; |
---|
2295 | | - size_t len; |
---|
| 2396 | + int rc; |
---|
| 2397 | + u32 sid; |
---|
2296 | 2398 | |
---|
2297 | | - read_lock(&state->ss->policy_rwlock); |
---|
2298 | | - len = p->len; |
---|
2299 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 2399 | + /* Ensure the associated sidtab entry is visible to this thread. */ |
---|
| 2400 | + sid = smp_load_acquire(&c->sid[index]); |
---|
| 2401 | + if (!sid) { |
---|
| 2402 | + rc = sidtab_context_to_sid(sidtab, &c->context[index], &sid); |
---|
| 2403 | + if (rc) |
---|
| 2404 | + return rc; |
---|
2300 | 2405 | |
---|
2301 | | - return len; |
---|
| 2406 | + /* |
---|
| 2407 | + * Ensure the new sidtab entry is visible to other threads |
---|
| 2408 | + * when they see the SID. |
---|
| 2409 | + */ |
---|
| 2410 | + smp_store_release(&c->sid[index], sid); |
---|
| 2411 | + } |
---|
| 2412 | + *out_sid = sid; |
---|
| 2413 | + return 0; |
---|
2302 | 2414 | } |
---|
2303 | 2415 | |
---|
2304 | 2416 | /** |
---|
.. | .. |
---|
2310 | 2422 | int security_port_sid(struct selinux_state *state, |
---|
2311 | 2423 | u8 protocol, u16 port, u32 *out_sid) |
---|
2312 | 2424 | { |
---|
| 2425 | + struct selinux_policy *policy; |
---|
2313 | 2426 | struct policydb *policydb; |
---|
2314 | 2427 | struct sidtab *sidtab; |
---|
2315 | 2428 | struct ocontext *c; |
---|
2316 | | - int rc = 0; |
---|
| 2429 | + int rc; |
---|
2317 | 2430 | |
---|
2318 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 2431 | + if (!selinux_initialized(state)) { |
---|
| 2432 | + *out_sid = SECINITSID_PORT; |
---|
| 2433 | + return 0; |
---|
| 2434 | + } |
---|
2319 | 2435 | |
---|
2320 | | - policydb = &state->ss->policydb; |
---|
2321 | | - sidtab = state->ss->sidtab; |
---|
| 2436 | +retry: |
---|
| 2437 | + rc = 0; |
---|
| 2438 | + rcu_read_lock(); |
---|
| 2439 | + policy = rcu_dereference(state->policy); |
---|
| 2440 | + policydb = &policy->policydb; |
---|
| 2441 | + sidtab = policy->sidtab; |
---|
2322 | 2442 | |
---|
2323 | 2443 | c = policydb->ocontexts[OCON_PORT]; |
---|
2324 | 2444 | while (c) { |
---|
.. | .. |
---|
2330 | 2450 | } |
---|
2331 | 2451 | |
---|
2332 | 2452 | if (c) { |
---|
2333 | | - if (!c->sid[0]) { |
---|
2334 | | - rc = context_struct_to_sid(state, &c->context[0], |
---|
2335 | | - &c->sid[0]); |
---|
2336 | | - if (rc) |
---|
2337 | | - goto out; |
---|
| 2453 | + rc = ocontext_to_sid(sidtab, c, 0, out_sid); |
---|
| 2454 | + if (rc == -ESTALE) { |
---|
| 2455 | + rcu_read_unlock(); |
---|
| 2456 | + goto retry; |
---|
2338 | 2457 | } |
---|
2339 | | - *out_sid = c->sid[0]; |
---|
| 2458 | + if (rc) |
---|
| 2459 | + goto out; |
---|
2340 | 2460 | } else { |
---|
2341 | 2461 | *out_sid = SECINITSID_PORT; |
---|
2342 | 2462 | } |
---|
2343 | 2463 | |
---|
2344 | 2464 | out: |
---|
2345 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 2465 | + rcu_read_unlock(); |
---|
2346 | 2466 | return rc; |
---|
2347 | 2467 | } |
---|
2348 | 2468 | |
---|
.. | .. |
---|
2355 | 2475 | int security_ib_pkey_sid(struct selinux_state *state, |
---|
2356 | 2476 | u64 subnet_prefix, u16 pkey_num, u32 *out_sid) |
---|
2357 | 2477 | { |
---|
| 2478 | + struct selinux_policy *policy; |
---|
2358 | 2479 | struct policydb *policydb; |
---|
| 2480 | + struct sidtab *sidtab; |
---|
2359 | 2481 | struct ocontext *c; |
---|
2360 | | - int rc = 0; |
---|
| 2482 | + int rc; |
---|
2361 | 2483 | |
---|
2362 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 2484 | + if (!selinux_initialized(state)) { |
---|
| 2485 | + *out_sid = SECINITSID_UNLABELED; |
---|
| 2486 | + return 0; |
---|
| 2487 | + } |
---|
2363 | 2488 | |
---|
2364 | | - policydb = &state->ss->policydb; |
---|
| 2489 | +retry: |
---|
| 2490 | + rc = 0; |
---|
| 2491 | + rcu_read_lock(); |
---|
| 2492 | + policy = rcu_dereference(state->policy); |
---|
| 2493 | + policydb = &policy->policydb; |
---|
| 2494 | + sidtab = policy->sidtab; |
---|
2365 | 2495 | |
---|
2366 | 2496 | c = policydb->ocontexts[OCON_IBPKEY]; |
---|
2367 | 2497 | while (c) { |
---|
.. | .. |
---|
2374 | 2504 | } |
---|
2375 | 2505 | |
---|
2376 | 2506 | if (c) { |
---|
2377 | | - if (!c->sid[0]) { |
---|
2378 | | - rc = context_struct_to_sid(state, |
---|
2379 | | - &c->context[0], |
---|
2380 | | - &c->sid[0]); |
---|
2381 | | - if (rc) |
---|
2382 | | - goto out; |
---|
| 2507 | + rc = ocontext_to_sid(sidtab, c, 0, out_sid); |
---|
| 2508 | + if (rc == -ESTALE) { |
---|
| 2509 | + rcu_read_unlock(); |
---|
| 2510 | + goto retry; |
---|
2383 | 2511 | } |
---|
2384 | | - *out_sid = c->sid[0]; |
---|
| 2512 | + if (rc) |
---|
| 2513 | + goto out; |
---|
2385 | 2514 | } else |
---|
2386 | 2515 | *out_sid = SECINITSID_UNLABELED; |
---|
2387 | 2516 | |
---|
2388 | 2517 | out: |
---|
2389 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 2518 | + rcu_read_unlock(); |
---|
2390 | 2519 | return rc; |
---|
2391 | 2520 | } |
---|
2392 | 2521 | |
---|
.. | .. |
---|
2399 | 2528 | int security_ib_endport_sid(struct selinux_state *state, |
---|
2400 | 2529 | const char *dev_name, u8 port_num, u32 *out_sid) |
---|
2401 | 2530 | { |
---|
| 2531 | + struct selinux_policy *policy; |
---|
2402 | 2532 | struct policydb *policydb; |
---|
2403 | 2533 | struct sidtab *sidtab; |
---|
2404 | 2534 | struct ocontext *c; |
---|
2405 | | - int rc = 0; |
---|
| 2535 | + int rc; |
---|
2406 | 2536 | |
---|
2407 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 2537 | + if (!selinux_initialized(state)) { |
---|
| 2538 | + *out_sid = SECINITSID_UNLABELED; |
---|
| 2539 | + return 0; |
---|
| 2540 | + } |
---|
2408 | 2541 | |
---|
2409 | | - policydb = &state->ss->policydb; |
---|
2410 | | - sidtab = state->ss->sidtab; |
---|
| 2542 | +retry: |
---|
| 2543 | + rc = 0; |
---|
| 2544 | + rcu_read_lock(); |
---|
| 2545 | + policy = rcu_dereference(state->policy); |
---|
| 2546 | + policydb = &policy->policydb; |
---|
| 2547 | + sidtab = policy->sidtab; |
---|
2411 | 2548 | |
---|
2412 | 2549 | c = policydb->ocontexts[OCON_IBENDPORT]; |
---|
2413 | 2550 | while (c) { |
---|
.. | .. |
---|
2421 | 2558 | } |
---|
2422 | 2559 | |
---|
2423 | 2560 | if (c) { |
---|
2424 | | - if (!c->sid[0]) { |
---|
2425 | | - rc = context_struct_to_sid(state, &c->context[0], |
---|
2426 | | - &c->sid[0]); |
---|
2427 | | - if (rc) |
---|
2428 | | - goto out; |
---|
| 2561 | + rc = ocontext_to_sid(sidtab, c, 0, out_sid); |
---|
| 2562 | + if (rc == -ESTALE) { |
---|
| 2563 | + rcu_read_unlock(); |
---|
| 2564 | + goto retry; |
---|
2429 | 2565 | } |
---|
2430 | | - *out_sid = c->sid[0]; |
---|
| 2566 | + if (rc) |
---|
| 2567 | + goto out; |
---|
2431 | 2568 | } else |
---|
2432 | 2569 | *out_sid = SECINITSID_UNLABELED; |
---|
2433 | 2570 | |
---|
2434 | 2571 | out: |
---|
2435 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 2572 | + rcu_read_unlock(); |
---|
2436 | 2573 | return rc; |
---|
2437 | 2574 | } |
---|
2438 | 2575 | |
---|
.. | .. |
---|
2444 | 2581 | int security_netif_sid(struct selinux_state *state, |
---|
2445 | 2582 | char *name, u32 *if_sid) |
---|
2446 | 2583 | { |
---|
| 2584 | + struct selinux_policy *policy; |
---|
2447 | 2585 | struct policydb *policydb; |
---|
2448 | 2586 | struct sidtab *sidtab; |
---|
2449 | | - int rc = 0; |
---|
| 2587 | + int rc; |
---|
2450 | 2588 | struct ocontext *c; |
---|
2451 | 2589 | |
---|
2452 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 2590 | + if (!selinux_initialized(state)) { |
---|
| 2591 | + *if_sid = SECINITSID_NETIF; |
---|
| 2592 | + return 0; |
---|
| 2593 | + } |
---|
2453 | 2594 | |
---|
2454 | | - policydb = &state->ss->policydb; |
---|
2455 | | - sidtab = state->ss->sidtab; |
---|
| 2595 | +retry: |
---|
| 2596 | + rc = 0; |
---|
| 2597 | + rcu_read_lock(); |
---|
| 2598 | + policy = rcu_dereference(state->policy); |
---|
| 2599 | + policydb = &policy->policydb; |
---|
| 2600 | + sidtab = policy->sidtab; |
---|
2456 | 2601 | |
---|
2457 | 2602 | c = policydb->ocontexts[OCON_NETIF]; |
---|
2458 | 2603 | while (c) { |
---|
.. | .. |
---|
2462 | 2607 | } |
---|
2463 | 2608 | |
---|
2464 | 2609 | if (c) { |
---|
2465 | | - if (!c->sid[0] || !c->sid[1]) { |
---|
2466 | | - rc = context_struct_to_sid(state, &c->context[0], |
---|
2467 | | - &c->sid[0]); |
---|
2468 | | - if (rc) |
---|
2469 | | - goto out; |
---|
2470 | | - rc = context_struct_to_sid(state, &c->context[1], |
---|
2471 | | - &c->sid[1]); |
---|
2472 | | - if (rc) |
---|
2473 | | - goto out; |
---|
| 2610 | + rc = ocontext_to_sid(sidtab, c, 0, if_sid); |
---|
| 2611 | + if (rc == -ESTALE) { |
---|
| 2612 | + rcu_read_unlock(); |
---|
| 2613 | + goto retry; |
---|
2474 | 2614 | } |
---|
2475 | | - *if_sid = c->sid[0]; |
---|
| 2615 | + if (rc) |
---|
| 2616 | + goto out; |
---|
2476 | 2617 | } else |
---|
2477 | 2618 | *if_sid = SECINITSID_NETIF; |
---|
2478 | 2619 | |
---|
2479 | 2620 | out: |
---|
2480 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 2621 | + rcu_read_unlock(); |
---|
2481 | 2622 | return rc; |
---|
2482 | 2623 | } |
---|
2483 | 2624 | |
---|
.. | .. |
---|
2507 | 2648 | u32 addrlen, |
---|
2508 | 2649 | u32 *out_sid) |
---|
2509 | 2650 | { |
---|
| 2651 | + struct selinux_policy *policy; |
---|
2510 | 2652 | struct policydb *policydb; |
---|
| 2653 | + struct sidtab *sidtab; |
---|
2511 | 2654 | int rc; |
---|
2512 | 2655 | struct ocontext *c; |
---|
2513 | 2656 | |
---|
2514 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 2657 | + if (!selinux_initialized(state)) { |
---|
| 2658 | + *out_sid = SECINITSID_NODE; |
---|
| 2659 | + return 0; |
---|
| 2660 | + } |
---|
2515 | 2661 | |
---|
2516 | | - policydb = &state->ss->policydb; |
---|
| 2662 | +retry: |
---|
| 2663 | + rcu_read_lock(); |
---|
| 2664 | + policy = rcu_dereference(state->policy); |
---|
| 2665 | + policydb = &policy->policydb; |
---|
| 2666 | + sidtab = policy->sidtab; |
---|
2517 | 2667 | |
---|
2518 | 2668 | switch (domain) { |
---|
2519 | 2669 | case AF_INET: { |
---|
.. | .. |
---|
2554 | 2704 | } |
---|
2555 | 2705 | |
---|
2556 | 2706 | if (c) { |
---|
2557 | | - if (!c->sid[0]) { |
---|
2558 | | - rc = context_struct_to_sid(state, |
---|
2559 | | - &c->context[0], |
---|
2560 | | - &c->sid[0]); |
---|
2561 | | - if (rc) |
---|
2562 | | - goto out; |
---|
| 2707 | + rc = ocontext_to_sid(sidtab, c, 0, out_sid); |
---|
| 2708 | + if (rc == -ESTALE) { |
---|
| 2709 | + rcu_read_unlock(); |
---|
| 2710 | + goto retry; |
---|
2563 | 2711 | } |
---|
2564 | | - *out_sid = c->sid[0]; |
---|
| 2712 | + if (rc) |
---|
| 2713 | + goto out; |
---|
2565 | 2714 | } else { |
---|
2566 | 2715 | *out_sid = SECINITSID_NODE; |
---|
2567 | 2716 | } |
---|
2568 | 2717 | |
---|
2569 | 2718 | rc = 0; |
---|
2570 | 2719 | out: |
---|
2571 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 2720 | + rcu_read_unlock(); |
---|
2572 | 2721 | return rc; |
---|
2573 | 2722 | } |
---|
2574 | 2723 | |
---|
.. | .. |
---|
2594 | 2743 | u32 **sids, |
---|
2595 | 2744 | u32 *nel) |
---|
2596 | 2745 | { |
---|
| 2746 | + struct selinux_policy *policy; |
---|
2597 | 2747 | struct policydb *policydb; |
---|
2598 | 2748 | struct sidtab *sidtab; |
---|
2599 | 2749 | struct context *fromcon, usercon; |
---|
2600 | 2750 | u32 *mysids = NULL, *mysids2, sid; |
---|
2601 | | - u32 mynel = 0, maxnel = SIDS_NEL; |
---|
| 2751 | + u32 i, j, mynel, maxnel = SIDS_NEL; |
---|
2602 | 2752 | struct user_datum *user; |
---|
2603 | 2753 | struct role_datum *role; |
---|
2604 | 2754 | struct ebitmap_node *rnode, *tnode; |
---|
2605 | | - int rc = 0, i, j; |
---|
| 2755 | + int rc; |
---|
2606 | 2756 | |
---|
2607 | 2757 | *sids = NULL; |
---|
2608 | 2758 | *nel = 0; |
---|
2609 | 2759 | |
---|
2610 | | - if (!state->initialized) |
---|
2611 | | - goto out; |
---|
| 2760 | + if (!selinux_initialized(state)) |
---|
| 2761 | + return 0; |
---|
2612 | 2762 | |
---|
2613 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 2763 | + mysids = kcalloc(maxnel, sizeof(*mysids), GFP_KERNEL); |
---|
| 2764 | + if (!mysids) |
---|
| 2765 | + return -ENOMEM; |
---|
2614 | 2766 | |
---|
2615 | | - policydb = &state->ss->policydb; |
---|
2616 | | - sidtab = state->ss->sidtab; |
---|
| 2767 | +retry: |
---|
| 2768 | + mynel = 0; |
---|
| 2769 | + rcu_read_lock(); |
---|
| 2770 | + policy = rcu_dereference(state->policy); |
---|
| 2771 | + policydb = &policy->policydb; |
---|
| 2772 | + sidtab = policy->sidtab; |
---|
2617 | 2773 | |
---|
2618 | 2774 | context_init(&usercon); |
---|
2619 | 2775 | |
---|
.. | .. |
---|
2623 | 2779 | goto out_unlock; |
---|
2624 | 2780 | |
---|
2625 | 2781 | rc = -EINVAL; |
---|
2626 | | - user = hashtab_search(policydb->p_users.table, username); |
---|
| 2782 | + user = symtab_search(&policydb->p_users, username); |
---|
2627 | 2783 | if (!user) |
---|
2628 | 2784 | goto out_unlock; |
---|
2629 | 2785 | |
---|
2630 | 2786 | usercon.user = user->value; |
---|
2631 | | - |
---|
2632 | | - rc = -ENOMEM; |
---|
2633 | | - mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC); |
---|
2634 | | - if (!mysids) |
---|
2635 | | - goto out_unlock; |
---|
2636 | 2787 | |
---|
2637 | 2788 | ebitmap_for_each_positive_bit(&user->roles, rnode, i) { |
---|
2638 | 2789 | role = policydb->role_val_to_struct[i]; |
---|
2639 | 2790 | usercon.role = i + 1; |
---|
2640 | 2791 | ebitmap_for_each_positive_bit(&role->types, tnode, j) { |
---|
2641 | 2792 | usercon.type = j + 1; |
---|
2642 | | - /* |
---|
2643 | | - * The same context struct is reused here so the hash |
---|
2644 | | - * must be reset. |
---|
2645 | | - */ |
---|
2646 | | - usercon.hash = 0; |
---|
2647 | 2793 | |
---|
2648 | 2794 | if (mls_setup_user_range(policydb, fromcon, user, |
---|
2649 | 2795 | &usercon)) |
---|
2650 | 2796 | continue; |
---|
2651 | 2797 | |
---|
2652 | | - rc = context_struct_to_sid(state, &usercon, &sid); |
---|
| 2798 | + rc = sidtab_context_to_sid(sidtab, &usercon, &sid); |
---|
| 2799 | + if (rc == -ESTALE) { |
---|
| 2800 | + rcu_read_unlock(); |
---|
| 2801 | + goto retry; |
---|
| 2802 | + } |
---|
2653 | 2803 | if (rc) |
---|
2654 | 2804 | goto out_unlock; |
---|
2655 | 2805 | if (mynel < maxnel) { |
---|
.. | .. |
---|
2669 | 2819 | } |
---|
2670 | 2820 | rc = 0; |
---|
2671 | 2821 | out_unlock: |
---|
2672 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 2822 | + rcu_read_unlock(); |
---|
2673 | 2823 | if (rc || !mynel) { |
---|
2674 | 2824 | kfree(mysids); |
---|
2675 | | - goto out; |
---|
| 2825 | + return rc; |
---|
2676 | 2826 | } |
---|
2677 | 2827 | |
---|
2678 | 2828 | rc = -ENOMEM; |
---|
2679 | 2829 | mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL); |
---|
2680 | 2830 | if (!mysids2) { |
---|
2681 | 2831 | kfree(mysids); |
---|
2682 | | - goto out; |
---|
| 2832 | + return rc; |
---|
2683 | 2833 | } |
---|
2684 | 2834 | for (i = 0, j = 0; i < mynel; i++) { |
---|
2685 | 2835 | struct av_decision dummy_avd; |
---|
.. | .. |
---|
2692 | 2842 | mysids2[j++] = mysids[i]; |
---|
2693 | 2843 | cond_resched(); |
---|
2694 | 2844 | } |
---|
2695 | | - rc = 0; |
---|
2696 | 2845 | kfree(mysids); |
---|
2697 | 2846 | *sids = mysids2; |
---|
2698 | 2847 | *nel = j; |
---|
2699 | | -out: |
---|
2700 | | - return rc; |
---|
| 2848 | + return 0; |
---|
2701 | 2849 | } |
---|
2702 | 2850 | |
---|
2703 | 2851 | /** |
---|
.. | .. |
---|
2711 | 2859 | * cannot support xattr or use a fixed labeling behavior like |
---|
2712 | 2860 | * transition SIDs or task SIDs. |
---|
2713 | 2861 | * |
---|
2714 | | - * The caller must acquire the policy_rwlock before calling this function. |
---|
| 2862 | + * WARNING: This function may return -ESTALE, indicating that the caller |
---|
| 2863 | + * must retry the operation after re-acquiring the policy pointer! |
---|
2715 | 2864 | */ |
---|
2716 | | -static inline int __security_genfs_sid(struct selinux_state *state, |
---|
| 2865 | +static inline int __security_genfs_sid(struct selinux_policy *policy, |
---|
2717 | 2866 | const char *fstype, |
---|
2718 | 2867 | char *path, |
---|
2719 | 2868 | u16 orig_sclass, |
---|
2720 | 2869 | u32 *sid) |
---|
2721 | 2870 | { |
---|
2722 | | - struct policydb *policydb = &state->ss->policydb; |
---|
| 2871 | + struct policydb *policydb = &policy->policydb; |
---|
| 2872 | + struct sidtab *sidtab = policy->sidtab; |
---|
2723 | 2873 | int len; |
---|
2724 | 2874 | u16 sclass; |
---|
2725 | 2875 | struct genfs *genfs; |
---|
2726 | 2876 | struct ocontext *c; |
---|
2727 | | - int rc, cmp = 0; |
---|
| 2877 | + int cmp = 0; |
---|
2728 | 2878 | |
---|
2729 | 2879 | while (path[0] == '/' && path[1] == '/') |
---|
2730 | 2880 | path++; |
---|
2731 | 2881 | |
---|
2732 | | - sclass = unmap_class(&state->ss->map, orig_sclass); |
---|
| 2882 | + sclass = unmap_class(&policy->map, orig_sclass); |
---|
2733 | 2883 | *sid = SECINITSID_UNLABELED; |
---|
2734 | 2884 | |
---|
2735 | 2885 | for (genfs = policydb->genfs; genfs; genfs = genfs->next) { |
---|
.. | .. |
---|
2738 | 2888 | break; |
---|
2739 | 2889 | } |
---|
2740 | 2890 | |
---|
2741 | | - rc = -ENOENT; |
---|
2742 | 2891 | if (!genfs || cmp) |
---|
2743 | | - goto out; |
---|
| 2892 | + return -ENOENT; |
---|
2744 | 2893 | |
---|
2745 | 2894 | for (c = genfs->head; c; c = c->next) { |
---|
2746 | 2895 | len = strlen(c->u.name); |
---|
.. | .. |
---|
2749 | 2898 | break; |
---|
2750 | 2899 | } |
---|
2751 | 2900 | |
---|
2752 | | - rc = -ENOENT; |
---|
2753 | 2901 | if (!c) |
---|
2754 | | - goto out; |
---|
| 2902 | + return -ENOENT; |
---|
2755 | 2903 | |
---|
2756 | | - if (!c->sid[0]) { |
---|
2757 | | - rc = context_struct_to_sid(state, &c->context[0], &c->sid[0]); |
---|
2758 | | - if (rc) |
---|
2759 | | - goto out; |
---|
2760 | | - } |
---|
2761 | | - |
---|
2762 | | - *sid = c->sid[0]; |
---|
2763 | | - rc = 0; |
---|
2764 | | -out: |
---|
2765 | | - return rc; |
---|
| 2904 | + return ocontext_to_sid(sidtab, c, 0, sid); |
---|
2766 | 2905 | } |
---|
2767 | 2906 | |
---|
2768 | 2907 | /** |
---|
.. | .. |
---|
2781 | 2920 | u16 orig_sclass, |
---|
2782 | 2921 | u32 *sid) |
---|
2783 | 2922 | { |
---|
| 2923 | + struct selinux_policy *policy; |
---|
2784 | 2924 | int retval; |
---|
2785 | 2925 | |
---|
2786 | | - read_lock(&state->ss->policy_rwlock); |
---|
2787 | | - retval = __security_genfs_sid(state, fstype, path, orig_sclass, sid); |
---|
2788 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 2926 | + if (!selinux_initialized(state)) { |
---|
| 2927 | + *sid = SECINITSID_UNLABELED; |
---|
| 2928 | + return 0; |
---|
| 2929 | + } |
---|
| 2930 | + |
---|
| 2931 | + do { |
---|
| 2932 | + rcu_read_lock(); |
---|
| 2933 | + policy = rcu_dereference(state->policy); |
---|
| 2934 | + retval = __security_genfs_sid(policy, fstype, path, |
---|
| 2935 | + orig_sclass, sid); |
---|
| 2936 | + rcu_read_unlock(); |
---|
| 2937 | + } while (retval == -ESTALE); |
---|
2789 | 2938 | return retval; |
---|
| 2939 | +} |
---|
| 2940 | + |
---|
| 2941 | +int selinux_policy_genfs_sid(struct selinux_policy *policy, |
---|
| 2942 | + const char *fstype, |
---|
| 2943 | + char *path, |
---|
| 2944 | + u16 orig_sclass, |
---|
| 2945 | + u32 *sid) |
---|
| 2946 | +{ |
---|
| 2947 | + /* no lock required, policy is not yet accessible by other threads */ |
---|
| 2948 | + return __security_genfs_sid(policy, fstype, path, orig_sclass, sid); |
---|
2790 | 2949 | } |
---|
2791 | 2950 | |
---|
2792 | 2951 | /** |
---|
.. | .. |
---|
2795 | 2954 | */ |
---|
2796 | 2955 | int security_fs_use(struct selinux_state *state, struct super_block *sb) |
---|
2797 | 2956 | { |
---|
| 2957 | + struct selinux_policy *policy; |
---|
2798 | 2958 | struct policydb *policydb; |
---|
2799 | 2959 | struct sidtab *sidtab; |
---|
2800 | | - int rc = 0; |
---|
| 2960 | + int rc; |
---|
2801 | 2961 | struct ocontext *c; |
---|
2802 | 2962 | struct superblock_security_struct *sbsec = sb->s_security; |
---|
2803 | 2963 | const char *fstype = sb->s_type->name; |
---|
2804 | 2964 | |
---|
2805 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 2965 | + if (!selinux_initialized(state)) { |
---|
| 2966 | + sbsec->behavior = SECURITY_FS_USE_NONE; |
---|
| 2967 | + sbsec->sid = SECINITSID_UNLABELED; |
---|
| 2968 | + return 0; |
---|
| 2969 | + } |
---|
2806 | 2970 | |
---|
2807 | | - policydb = &state->ss->policydb; |
---|
2808 | | - sidtab = state->ss->sidtab; |
---|
| 2971 | +retry: |
---|
| 2972 | + rc = 0; |
---|
| 2973 | + rcu_read_lock(); |
---|
| 2974 | + policy = rcu_dereference(state->policy); |
---|
| 2975 | + policydb = &policy->policydb; |
---|
| 2976 | + sidtab = policy->sidtab; |
---|
2809 | 2977 | |
---|
2810 | 2978 | c = policydb->ocontexts[OCON_FSUSE]; |
---|
2811 | 2979 | while (c) { |
---|
.. | .. |
---|
2816 | 2984 | |
---|
2817 | 2985 | if (c) { |
---|
2818 | 2986 | sbsec->behavior = c->v.behavior; |
---|
2819 | | - if (!c->sid[0]) { |
---|
2820 | | - rc = context_struct_to_sid(state, &c->context[0], |
---|
2821 | | - &c->sid[0]); |
---|
2822 | | - if (rc) |
---|
2823 | | - goto out; |
---|
| 2987 | + rc = ocontext_to_sid(sidtab, c, 0, &sbsec->sid); |
---|
| 2988 | + if (rc == -ESTALE) { |
---|
| 2989 | + rcu_read_unlock(); |
---|
| 2990 | + goto retry; |
---|
2824 | 2991 | } |
---|
2825 | | - sbsec->sid = c->sid[0]; |
---|
| 2992 | + if (rc) |
---|
| 2993 | + goto out; |
---|
2826 | 2994 | } else { |
---|
2827 | | - rc = __security_genfs_sid(state, fstype, "/", SECCLASS_DIR, |
---|
2828 | | - &sbsec->sid); |
---|
| 2995 | + rc = __security_genfs_sid(policy, fstype, "/", |
---|
| 2996 | + SECCLASS_DIR, &sbsec->sid); |
---|
| 2997 | + if (rc == -ESTALE) { |
---|
| 2998 | + rcu_read_unlock(); |
---|
| 2999 | + goto retry; |
---|
| 3000 | + } |
---|
2829 | 3001 | if (rc) { |
---|
2830 | 3002 | sbsec->behavior = SECURITY_FS_USE_NONE; |
---|
2831 | 3003 | rc = 0; |
---|
.. | .. |
---|
2835 | 3007 | } |
---|
2836 | 3008 | |
---|
2837 | 3009 | out: |
---|
2838 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 3010 | + rcu_read_unlock(); |
---|
2839 | 3011 | return rc; |
---|
2840 | 3012 | } |
---|
2841 | 3013 | |
---|
2842 | | -int security_get_bools(struct selinux_state *state, |
---|
2843 | | - int *len, char ***names, int **values) |
---|
| 3014 | +int security_get_bools(struct selinux_policy *policy, |
---|
| 3015 | + u32 *len, char ***names, int **values) |
---|
2844 | 3016 | { |
---|
2845 | 3017 | struct policydb *policydb; |
---|
2846 | | - int i, rc; |
---|
| 3018 | + u32 i; |
---|
| 3019 | + int rc; |
---|
2847 | 3020 | |
---|
2848 | | - if (!state->initialized) { |
---|
2849 | | - *len = 0; |
---|
2850 | | - *names = NULL; |
---|
2851 | | - *values = NULL; |
---|
2852 | | - return 0; |
---|
2853 | | - } |
---|
2854 | | - |
---|
2855 | | - read_lock(&state->ss->policy_rwlock); |
---|
2856 | | - |
---|
2857 | | - policydb = &state->ss->policydb; |
---|
| 3021 | + policydb = &policy->policydb; |
---|
2858 | 3022 | |
---|
2859 | 3023 | *names = NULL; |
---|
2860 | 3024 | *values = NULL; |
---|
.. | .. |
---|
2885 | 3049 | } |
---|
2886 | 3050 | rc = 0; |
---|
2887 | 3051 | out: |
---|
2888 | | - read_unlock(&state->ss->policy_rwlock); |
---|
2889 | 3052 | return rc; |
---|
2890 | 3053 | err: |
---|
2891 | 3054 | if (*names) { |
---|
.. | .. |
---|
2901 | 3064 | } |
---|
2902 | 3065 | |
---|
2903 | 3066 | |
---|
2904 | | -int security_set_bools(struct selinux_state *state, int len, int *values) |
---|
| 3067 | +int security_set_bools(struct selinux_state *state, u32 len, int *values) |
---|
2905 | 3068 | { |
---|
2906 | | - struct policydb *policydb; |
---|
2907 | | - int i, rc; |
---|
2908 | | - int lenp, seqno = 0; |
---|
2909 | | - struct cond_node *cur; |
---|
| 3069 | + struct selinux_policy *newpolicy, *oldpolicy; |
---|
| 3070 | + int rc; |
---|
| 3071 | + u32 i, seqno = 0; |
---|
2910 | 3072 | |
---|
2911 | | - write_lock_irq(&state->ss->policy_rwlock); |
---|
| 3073 | + if (!selinux_initialized(state)) |
---|
| 3074 | + return -EINVAL; |
---|
2912 | 3075 | |
---|
2913 | | - policydb = &state->ss->policydb; |
---|
| 3076 | + oldpolicy = rcu_dereference_protected(state->policy, |
---|
| 3077 | + lockdep_is_held(&state->policy_mutex)); |
---|
2914 | 3078 | |
---|
2915 | | - rc = -EFAULT; |
---|
2916 | | - lenp = policydb->p_bools.nprim; |
---|
2917 | | - if (len != lenp) |
---|
2918 | | - goto out; |
---|
| 3079 | + /* Consistency check on number of booleans, should never fail */ |
---|
| 3080 | + if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim)) |
---|
| 3081 | + return -EINVAL; |
---|
2919 | 3082 | |
---|
| 3083 | + newpolicy = kmemdup(oldpolicy, sizeof(*newpolicy), GFP_KERNEL); |
---|
| 3084 | + if (!newpolicy) |
---|
| 3085 | + return -ENOMEM; |
---|
| 3086 | + |
---|
| 3087 | + /* |
---|
| 3088 | + * Deep copy only the parts of the policydb that might be |
---|
| 3089 | + * modified as a result of changing booleans. |
---|
| 3090 | + */ |
---|
| 3091 | + rc = cond_policydb_dup(&newpolicy->policydb, &oldpolicy->policydb); |
---|
| 3092 | + if (rc) { |
---|
| 3093 | + kfree(newpolicy); |
---|
| 3094 | + return -ENOMEM; |
---|
| 3095 | + } |
---|
| 3096 | + |
---|
| 3097 | + /* Update the boolean states in the copy */ |
---|
2920 | 3098 | for (i = 0; i < len; i++) { |
---|
2921 | | - if (!!values[i] != policydb->bool_val_to_struct[i]->state) { |
---|
| 3099 | + int new_state = !!values[i]; |
---|
| 3100 | + int old_state = newpolicy->policydb.bool_val_to_struct[i]->state; |
---|
| 3101 | + |
---|
| 3102 | + if (new_state != old_state) { |
---|
2922 | 3103 | audit_log(audit_context(), GFP_ATOMIC, |
---|
2923 | 3104 | AUDIT_MAC_CONFIG_CHANGE, |
---|
2924 | 3105 | "bool=%s val=%d old_val=%d auid=%u ses=%u", |
---|
2925 | | - sym_name(policydb, SYM_BOOLS, i), |
---|
2926 | | - !!values[i], |
---|
2927 | | - policydb->bool_val_to_struct[i]->state, |
---|
| 3106 | + sym_name(&newpolicy->policydb, SYM_BOOLS, i), |
---|
| 3107 | + new_state, |
---|
| 3108 | + old_state, |
---|
2928 | 3109 | from_kuid(&init_user_ns, audit_get_loginuid(current)), |
---|
2929 | 3110 | audit_get_sessionid(current)); |
---|
| 3111 | + newpolicy->policydb.bool_val_to_struct[i]->state = new_state; |
---|
2930 | 3112 | } |
---|
2931 | | - if (values[i]) |
---|
2932 | | - policydb->bool_val_to_struct[i]->state = 1; |
---|
2933 | | - else |
---|
2934 | | - policydb->bool_val_to_struct[i]->state = 0; |
---|
2935 | 3113 | } |
---|
2936 | 3114 | |
---|
2937 | | - for (cur = policydb->cond_list; cur; cur = cur->next) { |
---|
2938 | | - rc = evaluate_cond_node(policydb, cur); |
---|
2939 | | - if (rc) |
---|
2940 | | - goto out; |
---|
2941 | | - } |
---|
| 3115 | + /* Re-evaluate the conditional rules in the copy */ |
---|
| 3116 | + evaluate_cond_nodes(&newpolicy->policydb); |
---|
2942 | 3117 | |
---|
2943 | | - seqno = ++state->ss->latest_granting; |
---|
2944 | | - rc = 0; |
---|
2945 | | -out: |
---|
2946 | | - write_unlock_irq(&state->ss->policy_rwlock); |
---|
2947 | | - if (!rc) { |
---|
2948 | | - avc_ss_reset(state->avc, seqno); |
---|
2949 | | - selnl_notify_policyload(seqno); |
---|
2950 | | - selinux_status_update_policyload(state, seqno); |
---|
2951 | | - selinux_xfrm_notify_policyload(); |
---|
2952 | | - } |
---|
2953 | | - return rc; |
---|
| 3118 | + /* Set latest granting seqno for new policy */ |
---|
| 3119 | + newpolicy->latest_granting = oldpolicy->latest_granting + 1; |
---|
| 3120 | + seqno = newpolicy->latest_granting; |
---|
| 3121 | + |
---|
| 3122 | + /* Install the new policy */ |
---|
| 3123 | + rcu_assign_pointer(state->policy, newpolicy); |
---|
| 3124 | + |
---|
| 3125 | + /* |
---|
| 3126 | + * Free the conditional portions of the old policydb |
---|
| 3127 | + * that were copied for the new policy, and the oldpolicy |
---|
| 3128 | + * structure itself but not what it references. |
---|
| 3129 | + */ |
---|
| 3130 | + synchronize_rcu(); |
---|
| 3131 | + selinux_policy_cond_free(oldpolicy); |
---|
| 3132 | + |
---|
| 3133 | + /* Notify others of the policy change */ |
---|
| 3134 | + selinux_notify_policy_change(state, seqno); |
---|
| 3135 | + return 0; |
---|
2954 | 3136 | } |
---|
2955 | 3137 | |
---|
2956 | 3138 | int security_get_bool_value(struct selinux_state *state, |
---|
2957 | | - int index) |
---|
| 3139 | + u32 index) |
---|
2958 | 3140 | { |
---|
| 3141 | + struct selinux_policy *policy; |
---|
2959 | 3142 | struct policydb *policydb; |
---|
2960 | 3143 | int rc; |
---|
2961 | | - int len; |
---|
| 3144 | + u32 len; |
---|
2962 | 3145 | |
---|
2963 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 3146 | + if (!selinux_initialized(state)) |
---|
| 3147 | + return 0; |
---|
2964 | 3148 | |
---|
2965 | | - policydb = &state->ss->policydb; |
---|
| 3149 | + rcu_read_lock(); |
---|
| 3150 | + policy = rcu_dereference(state->policy); |
---|
| 3151 | + policydb = &policy->policydb; |
---|
2966 | 3152 | |
---|
2967 | 3153 | rc = -EFAULT; |
---|
2968 | 3154 | len = policydb->p_bools.nprim; |
---|
.. | .. |
---|
2971 | 3157 | |
---|
2972 | 3158 | rc = policydb->bool_val_to_struct[index]->state; |
---|
2973 | 3159 | out: |
---|
2974 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 3160 | + rcu_read_unlock(); |
---|
2975 | 3161 | return rc; |
---|
2976 | 3162 | } |
---|
2977 | 3163 | |
---|
2978 | | -static int security_preserve_bools(struct selinux_state *state, |
---|
2979 | | - struct policydb *policydb) |
---|
| 3164 | +static int security_preserve_bools(struct selinux_policy *oldpolicy, |
---|
| 3165 | + struct selinux_policy *newpolicy) |
---|
2980 | 3166 | { |
---|
2981 | | - int rc, nbools = 0, *bvalues = NULL, i; |
---|
| 3167 | + int rc, *bvalues = NULL; |
---|
2982 | 3168 | char **bnames = NULL; |
---|
2983 | 3169 | struct cond_bool_datum *booldatum; |
---|
2984 | | - struct cond_node *cur; |
---|
| 3170 | + u32 i, nbools = 0; |
---|
2985 | 3171 | |
---|
2986 | | - rc = security_get_bools(state, &nbools, &bnames, &bvalues); |
---|
| 3172 | + rc = security_get_bools(oldpolicy, &nbools, &bnames, &bvalues); |
---|
2987 | 3173 | if (rc) |
---|
2988 | 3174 | goto out; |
---|
2989 | 3175 | for (i = 0; i < nbools; i++) { |
---|
2990 | | - booldatum = hashtab_search(policydb->p_bools.table, bnames[i]); |
---|
| 3176 | + booldatum = symtab_search(&newpolicy->policydb.p_bools, |
---|
| 3177 | + bnames[i]); |
---|
2991 | 3178 | if (booldatum) |
---|
2992 | 3179 | booldatum->state = bvalues[i]; |
---|
2993 | 3180 | } |
---|
2994 | | - for (cur = policydb->cond_list; cur; cur = cur->next) { |
---|
2995 | | - rc = evaluate_cond_node(policydb, cur); |
---|
2996 | | - if (rc) |
---|
2997 | | - goto out; |
---|
2998 | | - } |
---|
| 3181 | + evaluate_cond_nodes(&newpolicy->policydb); |
---|
2999 | 3182 | |
---|
3000 | 3183 | out: |
---|
3001 | 3184 | if (bnames) { |
---|
.. | .. |
---|
3014 | 3197 | int security_sid_mls_copy(struct selinux_state *state, |
---|
3015 | 3198 | u32 sid, u32 mls_sid, u32 *new_sid) |
---|
3016 | 3199 | { |
---|
3017 | | - struct policydb *policydb = &state->ss->policydb; |
---|
3018 | | - struct sidtab *sidtab = state->ss->sidtab; |
---|
| 3200 | + struct selinux_policy *policy; |
---|
| 3201 | + struct policydb *policydb; |
---|
| 3202 | + struct sidtab *sidtab; |
---|
3019 | 3203 | struct context *context1; |
---|
3020 | 3204 | struct context *context2; |
---|
3021 | 3205 | struct context newcon; |
---|
.. | .. |
---|
3023 | 3207 | u32 len; |
---|
3024 | 3208 | int rc; |
---|
3025 | 3209 | |
---|
3026 | | - rc = 0; |
---|
3027 | | - if (!state->initialized || !policydb->mls_enabled) { |
---|
| 3210 | + if (!selinux_initialized(state)) { |
---|
3028 | 3211 | *new_sid = sid; |
---|
3029 | | - goto out; |
---|
| 3212 | + return 0; |
---|
3030 | 3213 | } |
---|
3031 | 3214 | |
---|
| 3215 | +retry: |
---|
| 3216 | + rc = 0; |
---|
3032 | 3217 | context_init(&newcon); |
---|
3033 | 3218 | |
---|
3034 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 3219 | + rcu_read_lock(); |
---|
| 3220 | + policy = rcu_dereference(state->policy); |
---|
| 3221 | + policydb = &policy->policydb; |
---|
| 3222 | + sidtab = policy->sidtab; |
---|
| 3223 | + |
---|
| 3224 | + if (!policydb->mls_enabled) { |
---|
| 3225 | + *new_sid = sid; |
---|
| 3226 | + goto out_unlock; |
---|
| 3227 | + } |
---|
3035 | 3228 | |
---|
3036 | 3229 | rc = -EINVAL; |
---|
3037 | 3230 | context1 = sidtab_search(sidtab, sid); |
---|
.. | .. |
---|
3058 | 3251 | |
---|
3059 | 3252 | /* Check the validity of the new context. */ |
---|
3060 | 3253 | if (!policydb_context_isvalid(policydb, &newcon)) { |
---|
3061 | | - rc = convert_context_handle_invalid_context(state, &newcon); |
---|
| 3254 | + rc = convert_context_handle_invalid_context(state, policydb, |
---|
| 3255 | + &newcon); |
---|
3062 | 3256 | if (rc) { |
---|
3063 | 3257 | if (!context_struct_to_string(policydb, &newcon, &s, |
---|
3064 | 3258 | &len)) { |
---|
3065 | | - audit_log(audit_context(), |
---|
3066 | | - GFP_ATOMIC, AUDIT_SELINUX_ERR, |
---|
3067 | | - "op=security_sid_mls_copy " |
---|
3068 | | - "invalid_context=%s", s); |
---|
| 3259 | + struct audit_buffer *ab; |
---|
| 3260 | + |
---|
| 3261 | + ab = audit_log_start(audit_context(), |
---|
| 3262 | + GFP_ATOMIC, |
---|
| 3263 | + AUDIT_SELINUX_ERR); |
---|
| 3264 | + audit_log_format(ab, |
---|
| 3265 | + "op=security_sid_mls_copy invalid_context="); |
---|
| 3266 | + /* don't record NUL with untrusted strings */ |
---|
| 3267 | + audit_log_n_untrustedstring(ab, s, len - 1); |
---|
| 3268 | + audit_log_end(ab); |
---|
3069 | 3269 | kfree(s); |
---|
3070 | 3270 | } |
---|
3071 | 3271 | goto out_unlock; |
---|
3072 | 3272 | } |
---|
3073 | 3273 | } |
---|
3074 | | - rc = context_struct_to_sid(state, &newcon, new_sid); |
---|
| 3274 | + rc = sidtab_context_to_sid(sidtab, &newcon, new_sid); |
---|
| 3275 | + if (rc == -ESTALE) { |
---|
| 3276 | + rcu_read_unlock(); |
---|
| 3277 | + context_destroy(&newcon); |
---|
| 3278 | + goto retry; |
---|
| 3279 | + } |
---|
3075 | 3280 | out_unlock: |
---|
3076 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 3281 | + rcu_read_unlock(); |
---|
3077 | 3282 | context_destroy(&newcon); |
---|
3078 | | -out: |
---|
3079 | 3283 | return rc; |
---|
3080 | 3284 | } |
---|
3081 | 3285 | |
---|
.. | .. |
---|
3104 | 3308 | u32 xfrm_sid, |
---|
3105 | 3309 | u32 *peer_sid) |
---|
3106 | 3310 | { |
---|
3107 | | - struct policydb *policydb = &state->ss->policydb; |
---|
3108 | | - struct sidtab *sidtab = state->ss->sidtab; |
---|
| 3311 | + struct selinux_policy *policy; |
---|
| 3312 | + struct policydb *policydb; |
---|
| 3313 | + struct sidtab *sidtab; |
---|
3109 | 3314 | int rc; |
---|
3110 | 3315 | struct context *nlbl_ctx; |
---|
3111 | 3316 | struct context *xfrm_ctx; |
---|
.. | .. |
---|
3127 | 3332 | return 0; |
---|
3128 | 3333 | } |
---|
3129 | 3334 | |
---|
| 3335 | + if (!selinux_initialized(state)) |
---|
| 3336 | + return 0; |
---|
| 3337 | + |
---|
| 3338 | + rcu_read_lock(); |
---|
| 3339 | + policy = rcu_dereference(state->policy); |
---|
| 3340 | + policydb = &policy->policydb; |
---|
| 3341 | + sidtab = policy->sidtab; |
---|
| 3342 | + |
---|
3130 | 3343 | /* |
---|
3131 | 3344 | * We don't need to check initialized here since the only way both |
---|
3132 | 3345 | * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the |
---|
3133 | 3346 | * security server was initialized and state->initialized was true. |
---|
3134 | 3347 | */ |
---|
3135 | | - if (!policydb->mls_enabled) |
---|
3136 | | - return 0; |
---|
3137 | | - |
---|
3138 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 3348 | + if (!policydb->mls_enabled) { |
---|
| 3349 | + rc = 0; |
---|
| 3350 | + goto out; |
---|
| 3351 | + } |
---|
3139 | 3352 | |
---|
3140 | 3353 | rc = -EINVAL; |
---|
3141 | 3354 | nlbl_ctx = sidtab_search(sidtab, nlbl_sid); |
---|
.. | .. |
---|
3162 | 3375 | * expressive */ |
---|
3163 | 3376 | *peer_sid = xfrm_sid; |
---|
3164 | 3377 | out: |
---|
3165 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 3378 | + rcu_read_unlock(); |
---|
3166 | 3379 | return rc; |
---|
3167 | 3380 | } |
---|
3168 | 3381 | |
---|
.. | .. |
---|
3179 | 3392 | return 0; |
---|
3180 | 3393 | } |
---|
3181 | 3394 | |
---|
3182 | | -int security_get_classes(struct selinux_state *state, |
---|
| 3395 | +int security_get_classes(struct selinux_policy *policy, |
---|
3183 | 3396 | char ***classes, int *nclasses) |
---|
3184 | 3397 | { |
---|
3185 | | - struct policydb *policydb = &state->ss->policydb; |
---|
| 3398 | + struct policydb *policydb; |
---|
3186 | 3399 | int rc; |
---|
3187 | 3400 | |
---|
3188 | | - if (!state->initialized) { |
---|
3189 | | - *nclasses = 0; |
---|
3190 | | - *classes = NULL; |
---|
3191 | | - return 0; |
---|
3192 | | - } |
---|
3193 | | - |
---|
3194 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 3401 | + policydb = &policy->policydb; |
---|
3195 | 3402 | |
---|
3196 | 3403 | rc = -ENOMEM; |
---|
3197 | 3404 | *nclasses = policydb->p_classes.nprim; |
---|
.. | .. |
---|
3199 | 3406 | if (!*classes) |
---|
3200 | 3407 | goto out; |
---|
3201 | 3408 | |
---|
3202 | | - rc = hashtab_map(policydb->p_classes.table, get_classes_callback, |
---|
3203 | | - *classes); |
---|
| 3409 | + rc = hashtab_map(&policydb->p_classes.table, get_classes_callback, |
---|
| 3410 | + *classes); |
---|
3204 | 3411 | if (rc) { |
---|
3205 | 3412 | int i; |
---|
3206 | 3413 | for (i = 0; i < *nclasses; i++) |
---|
.. | .. |
---|
3209 | 3416 | } |
---|
3210 | 3417 | |
---|
3211 | 3418 | out: |
---|
3212 | | - read_unlock(&state->ss->policy_rwlock); |
---|
3213 | 3419 | return rc; |
---|
3214 | 3420 | } |
---|
3215 | 3421 | |
---|
.. | .. |
---|
3226 | 3432 | return 0; |
---|
3227 | 3433 | } |
---|
3228 | 3434 | |
---|
3229 | | -int security_get_permissions(struct selinux_state *state, |
---|
| 3435 | +int security_get_permissions(struct selinux_policy *policy, |
---|
3230 | 3436 | char *class, char ***perms, int *nperms) |
---|
3231 | 3437 | { |
---|
3232 | | - struct policydb *policydb = &state->ss->policydb; |
---|
| 3438 | + struct policydb *policydb; |
---|
3233 | 3439 | int rc, i; |
---|
3234 | 3440 | struct class_datum *match; |
---|
3235 | 3441 | |
---|
3236 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 3442 | + policydb = &policy->policydb; |
---|
3237 | 3443 | |
---|
3238 | 3444 | rc = -EINVAL; |
---|
3239 | | - match = hashtab_search(policydb->p_classes.table, class); |
---|
| 3445 | + match = symtab_search(&policydb->p_classes, class); |
---|
3240 | 3446 | if (!match) { |
---|
3241 | 3447 | pr_err("SELinux: %s: unrecognized class %s\n", |
---|
3242 | 3448 | __func__, class); |
---|
.. | .. |
---|
3250 | 3456 | goto out; |
---|
3251 | 3457 | |
---|
3252 | 3458 | if (match->comdatum) { |
---|
3253 | | - rc = hashtab_map(match->comdatum->permissions.table, |
---|
3254 | | - get_permissions_callback, *perms); |
---|
| 3459 | + rc = hashtab_map(&match->comdatum->permissions.table, |
---|
| 3460 | + get_permissions_callback, *perms); |
---|
3255 | 3461 | if (rc) |
---|
3256 | 3462 | goto err; |
---|
3257 | 3463 | } |
---|
3258 | 3464 | |
---|
3259 | | - rc = hashtab_map(match->permissions.table, get_permissions_callback, |
---|
3260 | | - *perms); |
---|
| 3465 | + rc = hashtab_map(&match->permissions.table, get_permissions_callback, |
---|
| 3466 | + *perms); |
---|
3261 | 3467 | if (rc) |
---|
3262 | 3468 | goto err; |
---|
3263 | 3469 | |
---|
3264 | 3470 | out: |
---|
3265 | | - read_unlock(&state->ss->policy_rwlock); |
---|
3266 | 3471 | return rc; |
---|
3267 | 3472 | |
---|
3268 | 3473 | err: |
---|
3269 | | - read_unlock(&state->ss->policy_rwlock); |
---|
3270 | 3474 | for (i = 0; i < *nperms; i++) |
---|
3271 | 3475 | kfree((*perms)[i]); |
---|
3272 | 3476 | kfree(*perms); |
---|
.. | .. |
---|
3275 | 3479 | |
---|
3276 | 3480 | int security_get_reject_unknown(struct selinux_state *state) |
---|
3277 | 3481 | { |
---|
3278 | | - return state->ss->policydb.reject_unknown; |
---|
| 3482 | + struct selinux_policy *policy; |
---|
| 3483 | + int value; |
---|
| 3484 | + |
---|
| 3485 | + if (!selinux_initialized(state)) |
---|
| 3486 | + return 0; |
---|
| 3487 | + |
---|
| 3488 | + rcu_read_lock(); |
---|
| 3489 | + policy = rcu_dereference(state->policy); |
---|
| 3490 | + value = policy->policydb.reject_unknown; |
---|
| 3491 | + rcu_read_unlock(); |
---|
| 3492 | + return value; |
---|
3279 | 3493 | } |
---|
3280 | 3494 | |
---|
3281 | 3495 | int security_get_allow_unknown(struct selinux_state *state) |
---|
3282 | 3496 | { |
---|
3283 | | - return state->ss->policydb.allow_unknown; |
---|
| 3497 | + struct selinux_policy *policy; |
---|
| 3498 | + int value; |
---|
| 3499 | + |
---|
| 3500 | + if (!selinux_initialized(state)) |
---|
| 3501 | + return 0; |
---|
| 3502 | + |
---|
| 3503 | + rcu_read_lock(); |
---|
| 3504 | + policy = rcu_dereference(state->policy); |
---|
| 3505 | + value = policy->policydb.allow_unknown; |
---|
| 3506 | + rcu_read_unlock(); |
---|
| 3507 | + return value; |
---|
3284 | 3508 | } |
---|
3285 | 3509 | |
---|
3286 | 3510 | /** |
---|
.. | .. |
---|
3296 | 3520 | int security_policycap_supported(struct selinux_state *state, |
---|
3297 | 3521 | unsigned int req_cap) |
---|
3298 | 3522 | { |
---|
3299 | | - struct policydb *policydb = &state->ss->policydb; |
---|
| 3523 | + struct selinux_policy *policy; |
---|
3300 | 3524 | int rc; |
---|
3301 | 3525 | |
---|
3302 | | - read_lock(&state->ss->policy_rwlock); |
---|
3303 | | - rc = ebitmap_get_bit(&policydb->policycaps, req_cap); |
---|
3304 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 3526 | + if (!selinux_initialized(state)) |
---|
| 3527 | + return 0; |
---|
| 3528 | + |
---|
| 3529 | + rcu_read_lock(); |
---|
| 3530 | + policy = rcu_dereference(state->policy); |
---|
| 3531 | + rc = ebitmap_get_bit(&policy->policydb.policycaps, req_cap); |
---|
| 3532 | + rcu_read_unlock(); |
---|
3305 | 3533 | |
---|
3306 | 3534 | return rc; |
---|
3307 | 3535 | } |
---|
.. | .. |
---|
3324 | 3552 | int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) |
---|
3325 | 3553 | { |
---|
3326 | 3554 | struct selinux_state *state = &selinux_state; |
---|
3327 | | - struct policydb *policydb = &state->ss->policydb; |
---|
| 3555 | + struct selinux_policy *policy; |
---|
| 3556 | + struct policydb *policydb; |
---|
3328 | 3557 | struct selinux_audit_rule *tmprule; |
---|
3329 | 3558 | struct role_datum *roledatum; |
---|
3330 | 3559 | struct type_datum *typedatum; |
---|
.. | .. |
---|
3334 | 3563 | |
---|
3335 | 3564 | *rule = NULL; |
---|
3336 | 3565 | |
---|
3337 | | - if (!state->initialized) |
---|
| 3566 | + if (!selinux_initialized(state)) |
---|
3338 | 3567 | return -EOPNOTSUPP; |
---|
3339 | 3568 | |
---|
3340 | 3569 | switch (field) { |
---|
.. | .. |
---|
3367 | 3596 | |
---|
3368 | 3597 | context_init(&tmprule->au_ctxt); |
---|
3369 | 3598 | |
---|
3370 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 3599 | + rcu_read_lock(); |
---|
| 3600 | + policy = rcu_dereference(state->policy); |
---|
| 3601 | + policydb = &policy->policydb; |
---|
3371 | 3602 | |
---|
3372 | | - tmprule->au_seqno = state->ss->latest_granting; |
---|
| 3603 | + tmprule->au_seqno = policy->latest_granting; |
---|
3373 | 3604 | |
---|
3374 | 3605 | switch (field) { |
---|
3375 | 3606 | case AUDIT_SUBJ_USER: |
---|
3376 | 3607 | case AUDIT_OBJ_USER: |
---|
3377 | 3608 | rc = -EINVAL; |
---|
3378 | | - userdatum = hashtab_search(policydb->p_users.table, rulestr); |
---|
| 3609 | + userdatum = symtab_search(&policydb->p_users, rulestr); |
---|
3379 | 3610 | if (!userdatum) |
---|
3380 | 3611 | goto out; |
---|
3381 | 3612 | tmprule->au_ctxt.user = userdatum->value; |
---|
.. | .. |
---|
3383 | 3614 | case AUDIT_SUBJ_ROLE: |
---|
3384 | 3615 | case AUDIT_OBJ_ROLE: |
---|
3385 | 3616 | rc = -EINVAL; |
---|
3386 | | - roledatum = hashtab_search(policydb->p_roles.table, rulestr); |
---|
| 3617 | + roledatum = symtab_search(&policydb->p_roles, rulestr); |
---|
3387 | 3618 | if (!roledatum) |
---|
3388 | 3619 | goto out; |
---|
3389 | 3620 | tmprule->au_ctxt.role = roledatum->value; |
---|
.. | .. |
---|
3391 | 3622 | case AUDIT_SUBJ_TYPE: |
---|
3392 | 3623 | case AUDIT_OBJ_TYPE: |
---|
3393 | 3624 | rc = -EINVAL; |
---|
3394 | | - typedatum = hashtab_search(policydb->p_types.table, rulestr); |
---|
| 3625 | + typedatum = symtab_search(&policydb->p_types, rulestr); |
---|
3395 | 3626 | if (!typedatum) |
---|
3396 | 3627 | goto out; |
---|
3397 | 3628 | tmprule->au_ctxt.type = typedatum->value; |
---|
.. | .. |
---|
3408 | 3639 | } |
---|
3409 | 3640 | rc = 0; |
---|
3410 | 3641 | out: |
---|
3411 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 3642 | + rcu_read_unlock(); |
---|
3412 | 3643 | |
---|
3413 | 3644 | if (rc) { |
---|
3414 | 3645 | selinux_audit_rule_free(tmprule); |
---|
.. | .. |
---|
3445 | 3676 | return 0; |
---|
3446 | 3677 | } |
---|
3447 | 3678 | |
---|
3448 | | -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, |
---|
3449 | | - struct audit_context *actx) |
---|
| 3679 | +int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule) |
---|
3450 | 3680 | { |
---|
3451 | 3681 | struct selinux_state *state = &selinux_state; |
---|
| 3682 | + struct selinux_policy *policy; |
---|
3452 | 3683 | struct context *ctxt; |
---|
3453 | 3684 | struct mls_level *level; |
---|
3454 | 3685 | struct selinux_audit_rule *rule = vrule; |
---|
.. | .. |
---|
3459 | 3690 | return -ENOENT; |
---|
3460 | 3691 | } |
---|
3461 | 3692 | |
---|
3462 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 3693 | + if (!selinux_initialized(state)) |
---|
| 3694 | + return 0; |
---|
3463 | 3695 | |
---|
3464 | | - if (rule->au_seqno < state->ss->latest_granting) { |
---|
| 3696 | + rcu_read_lock(); |
---|
| 3697 | + |
---|
| 3698 | + policy = rcu_dereference(state->policy); |
---|
| 3699 | + |
---|
| 3700 | + if (rule->au_seqno < policy->latest_granting) { |
---|
3465 | 3701 | match = -ESTALE; |
---|
3466 | 3702 | goto out; |
---|
3467 | 3703 | } |
---|
3468 | 3704 | |
---|
3469 | | - ctxt = sidtab_search(state->ss->sidtab, sid); |
---|
| 3705 | + ctxt = sidtab_search(policy->sidtab, sid); |
---|
3470 | 3706 | if (unlikely(!ctxt)) { |
---|
3471 | 3707 | WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", |
---|
3472 | 3708 | sid); |
---|
.. | .. |
---|
3550 | 3786 | } |
---|
3551 | 3787 | |
---|
3552 | 3788 | out: |
---|
3553 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 3789 | + rcu_read_unlock(); |
---|
3554 | 3790 | return match; |
---|
3555 | 3791 | } |
---|
3556 | 3792 | |
---|
.. | .. |
---|
3628 | 3864 | struct netlbl_lsm_secattr *secattr, |
---|
3629 | 3865 | u32 *sid) |
---|
3630 | 3866 | { |
---|
3631 | | - struct policydb *policydb = &state->ss->policydb; |
---|
3632 | | - struct sidtab *sidtab = state->ss->sidtab; |
---|
| 3867 | + struct selinux_policy *policy; |
---|
| 3868 | + struct policydb *policydb; |
---|
| 3869 | + struct sidtab *sidtab; |
---|
3633 | 3870 | int rc; |
---|
3634 | 3871 | struct context *ctx; |
---|
3635 | 3872 | struct context ctx_new; |
---|
3636 | 3873 | |
---|
3637 | | - if (!state->initialized) { |
---|
| 3874 | + if (!selinux_initialized(state)) { |
---|
3638 | 3875 | *sid = SECSID_NULL; |
---|
3639 | 3876 | return 0; |
---|
3640 | 3877 | } |
---|
3641 | 3878 | |
---|
3642 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 3879 | +retry: |
---|
| 3880 | + rc = 0; |
---|
| 3881 | + rcu_read_lock(); |
---|
| 3882 | + policy = rcu_dereference(state->policy); |
---|
| 3883 | + policydb = &policy->policydb; |
---|
| 3884 | + sidtab = policy->sidtab; |
---|
3643 | 3885 | |
---|
3644 | 3886 | if (secattr->flags & NETLBL_SECATTR_CACHE) |
---|
3645 | 3887 | *sid = *(u32 *)secattr->cache->data; |
---|
.. | .. |
---|
3662 | 3904 | goto out; |
---|
3663 | 3905 | } |
---|
3664 | 3906 | rc = -EIDRM; |
---|
3665 | | - if (!mls_context_isvalid(policydb, &ctx_new)) |
---|
3666 | | - goto out_free; |
---|
| 3907 | + if (!mls_context_isvalid(policydb, &ctx_new)) { |
---|
| 3908 | + ebitmap_destroy(&ctx_new.range.level[0].cat); |
---|
| 3909 | + goto out; |
---|
| 3910 | + } |
---|
3667 | 3911 | |
---|
3668 | | - rc = context_struct_to_sid(state, &ctx_new, sid); |
---|
| 3912 | + rc = sidtab_context_to_sid(sidtab, &ctx_new, sid); |
---|
| 3913 | + ebitmap_destroy(&ctx_new.range.level[0].cat); |
---|
| 3914 | + if (rc == -ESTALE) { |
---|
| 3915 | + rcu_read_unlock(); |
---|
| 3916 | + goto retry; |
---|
| 3917 | + } |
---|
3669 | 3918 | if (rc) |
---|
3670 | | - goto out_free; |
---|
| 3919 | + goto out; |
---|
3671 | 3920 | |
---|
3672 | 3921 | security_netlbl_cache_add(secattr, *sid); |
---|
3673 | | - |
---|
3674 | | - ebitmap_destroy(&ctx_new.range.level[0].cat); |
---|
3675 | 3922 | } else |
---|
3676 | 3923 | *sid = SECSID_NULL; |
---|
3677 | 3924 | |
---|
3678 | | - read_unlock(&state->ss->policy_rwlock); |
---|
3679 | | - return 0; |
---|
3680 | | -out_free: |
---|
3681 | | - ebitmap_destroy(&ctx_new.range.level[0].cat); |
---|
3682 | 3925 | out: |
---|
3683 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 3926 | + rcu_read_unlock(); |
---|
3684 | 3927 | return rc; |
---|
3685 | 3928 | } |
---|
3686 | 3929 | |
---|
.. | .. |
---|
3697 | 3940 | int security_netlbl_sid_to_secattr(struct selinux_state *state, |
---|
3698 | 3941 | u32 sid, struct netlbl_lsm_secattr *secattr) |
---|
3699 | 3942 | { |
---|
3700 | | - struct policydb *policydb = &state->ss->policydb; |
---|
| 3943 | + struct selinux_policy *policy; |
---|
| 3944 | + struct policydb *policydb; |
---|
3701 | 3945 | int rc; |
---|
3702 | 3946 | struct context *ctx; |
---|
3703 | 3947 | |
---|
3704 | | - if (!state->initialized) |
---|
| 3948 | + if (!selinux_initialized(state)) |
---|
3705 | 3949 | return 0; |
---|
3706 | 3950 | |
---|
3707 | | - read_lock(&state->ss->policy_rwlock); |
---|
| 3951 | + rcu_read_lock(); |
---|
| 3952 | + policy = rcu_dereference(state->policy); |
---|
| 3953 | + policydb = &policy->policydb; |
---|
3708 | 3954 | |
---|
3709 | 3955 | rc = -ENOENT; |
---|
3710 | | - ctx = sidtab_search(state->ss->sidtab, sid); |
---|
| 3956 | + ctx = sidtab_search(policy->sidtab, sid); |
---|
3711 | 3957 | if (ctx == NULL) |
---|
3712 | 3958 | goto out; |
---|
3713 | 3959 | |
---|
.. | .. |
---|
3722 | 3968 | mls_export_netlbl_lvl(policydb, ctx, secattr); |
---|
3723 | 3969 | rc = mls_export_netlbl_cat(policydb, ctx, secattr); |
---|
3724 | 3970 | out: |
---|
3725 | | - read_unlock(&state->ss->policy_rwlock); |
---|
| 3971 | + rcu_read_unlock(); |
---|
3726 | 3972 | return rc; |
---|
3727 | 3973 | } |
---|
3728 | 3974 | #endif /* CONFIG_NETLABEL */ |
---|
.. | .. |
---|
3736 | 3982 | int security_read_policy(struct selinux_state *state, |
---|
3737 | 3983 | void **data, size_t *len) |
---|
3738 | 3984 | { |
---|
3739 | | - struct policydb *policydb = &state->ss->policydb; |
---|
| 3985 | + struct selinux_policy *policy; |
---|
3740 | 3986 | int rc; |
---|
3741 | 3987 | struct policy_file fp; |
---|
3742 | 3988 | |
---|
3743 | | - if (!state->initialized) |
---|
| 3989 | + policy = rcu_dereference_protected( |
---|
| 3990 | + state->policy, lockdep_is_held(&state->policy_mutex)); |
---|
| 3991 | + if (!policy) |
---|
3744 | 3992 | return -EINVAL; |
---|
3745 | 3993 | |
---|
3746 | | - *len = security_policydb_len(state); |
---|
3747 | | - |
---|
| 3994 | + *len = policy->policydb.len; |
---|
3748 | 3995 | *data = vmalloc_user(*len); |
---|
3749 | 3996 | if (!*data) |
---|
3750 | 3997 | return -ENOMEM; |
---|
.. | .. |
---|
3752 | 3999 | fp.data = *data; |
---|
3753 | 4000 | fp.len = *len; |
---|
3754 | 4001 | |
---|
3755 | | - read_lock(&state->ss->policy_rwlock); |
---|
3756 | | - rc = policydb_write(policydb, &fp); |
---|
3757 | | - read_unlock(&state->ss->policy_rwlock); |
---|
3758 | | - |
---|
| 4002 | + rc = policydb_write(&policy->policydb, &fp); |
---|
3759 | 4003 | if (rc) |
---|
3760 | 4004 | return rc; |
---|
3761 | 4005 | |
---|