| .. | .. |
|---|
| 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 | |
|---|