summaryrefslogtreecommitdiffstats
path: root/security/selinux
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2018-12-13 15:04:59 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2018-12-21 11:48:45 -0500
commitbd3236557bb256d6491df125e5e9d0393c70e4d2 (patch)
tree1694eb11ac33095c03868f79055b1d373a5f6c8e /security/selinux
parent204cc0ccf1d49c6292aeef4c8edd1b3d10ff933c (diff)
selinux: switch to private struct selinux_mnt_opts
none of the convolutions needed, just 4 strings, TYVM... Reviewed-by: David Howells <dhowells@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'security/selinux')
-rw-r--r--security/selinux/hooks.c262
1 files changed, 101 insertions, 161 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index caf7ca7abfc1..238907d69e8b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -433,16 +433,17 @@ static void superblock_free_security(struct super_block *sb)
433 kfree(sbsec); 433 kfree(sbsec);
434} 434}
435 435
436struct selinux_mnt_opts {
437 const char *fscontext, *context, *rootcontext, *defcontext;
438};
439
436static void selinux_free_mnt_opts(void *mnt_opts) 440static void selinux_free_mnt_opts(void *mnt_opts)
437{ 441{
438 struct security_mnt_opts *opts = mnt_opts; 442 struct selinux_mnt_opts *opts = mnt_opts;
439 int i; 443 kfree(opts->fscontext);
440 444 kfree(opts->context);
441 if (opts->mnt_opts) 445 kfree(opts->rootcontext);
442 for (i = 0; i < opts->num_mnt_opts; i++) 446 kfree(opts->defcontext);
443 kfree(opts->mnt_opts[i]);
444 kfree(opts->mnt_opts);
445 kfree(opts->mnt_opts_flags);
446 kfree(opts); 447 kfree(opts);
447} 448}
448 449
@@ -624,6 +625,17 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
624 return 0; 625 return 0;
625} 626}
626 627
628static int parse_sid(struct super_block *sb, const char *s, u32 *sid)
629{
630 int rc = security_context_str_to_sid(&selinux_state, s,
631 sid, GFP_KERNEL);
632 if (rc)
633 pr_warn("SELinux: security_context_str_to_sid"
634 "(%s) failed for (dev %s, type %s) errno=%d\n",
635 s, sb->s_id, sb->s_type->name, rc);
636 return rc;
637}
638
627/* 639/*
628 * Allow filesystems with binary mount data to explicitly set mount point 640 * Allow filesystems with binary mount data to explicitly set mount point
629 * labeling information. 641 * labeling information.
@@ -634,22 +646,18 @@ static int selinux_set_mnt_opts(struct super_block *sb,
634 unsigned long *set_kern_flags) 646 unsigned long *set_kern_flags)
635{ 647{
636 const struct cred *cred = current_cred(); 648 const struct cred *cred = current_cred();
637 int rc = 0, i;
638 struct superblock_security_struct *sbsec = sb->s_security; 649 struct superblock_security_struct *sbsec = sb->s_security;
639 const char *name = sb->s_type->name;
640 struct dentry *root = sbsec->sb->s_root; 650 struct dentry *root = sbsec->sb->s_root;
651 struct selinux_mnt_opts *opts = mnt_opts;
641 struct inode_security_struct *root_isec; 652 struct inode_security_struct *root_isec;
642 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; 653 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
643 u32 defcontext_sid = 0; 654 u32 defcontext_sid = 0;
644 struct security_mnt_opts *opts = mnt_opts; 655 int rc = 0;
645 char **mount_options = opts ? opts->mnt_opts : NULL;
646 int *flags = opts ? opts->mnt_opts_flags : NULL;
647 int num_opts = opts ? opts->num_mnt_opts : 0;
648 656
649 mutex_lock(&sbsec->lock); 657 mutex_lock(&sbsec->lock);
650 658
651 if (!selinux_state.initialized) { 659 if (!selinux_state.initialized) {
652 if (!num_opts) { 660 if (!opts) {
653 /* Defer initialization until selinux_complete_init, 661 /* Defer initialization until selinux_complete_init,
654 after the initial policy is loaded and the security 662 after the initial policy is loaded and the security
655 server is ready to handle calls. */ 663 server is ready to handle calls. */
@@ -679,7 +687,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
679 * will be used for both mounts) 687 * will be used for both mounts)
680 */ 688 */
681 if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) 689 if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
682 && (num_opts == 0)) 690 && !opts)
683 goto out; 691 goto out;
684 692
685 root_isec = backing_inode_security_novalidate(root); 693 root_isec = backing_inode_security_novalidate(root);
@@ -689,68 +697,48 @@ static int selinux_set_mnt_opts(struct super_block *sb,
689 * also check if someone is trying to mount the same sb more 697 * also check if someone is trying to mount the same sb more
690 * than once with different security options. 698 * than once with different security options.
691 */ 699 */
692 for (i = 0; i < num_opts; i++) { 700 if (opts) {
693 u32 sid; 701 if (opts->fscontext) {
694 702 rc = parse_sid(sb, opts->fscontext, &fscontext_sid);
695 if (flags[i] == SBLABEL_MNT) 703 if (rc)
696 continue; 704 goto out;
697 rc = security_context_str_to_sid(&selinux_state,
698 mount_options[i], &sid,
699 GFP_KERNEL);
700 if (rc) {
701 pr_warn("SELinux: security_context_str_to_sid"
702 "(%s) failed for (dev %s, type %s) errno=%d\n",
703 mount_options[i], sb->s_id, name, rc);
704 goto out;
705 }
706 switch (flags[i]) {
707 case FSCONTEXT_MNT:
708 fscontext_sid = sid;
709
710 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, 705 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
711 fscontext_sid)) 706 fscontext_sid))
712 goto out_double_mount; 707 goto out_double_mount;
713
714 sbsec->flags |= FSCONTEXT_MNT; 708 sbsec->flags |= FSCONTEXT_MNT;
715 break; 709 }
716 case CONTEXT_MNT: 710 if (opts->context) {
717 context_sid = sid; 711 rc = parse_sid(sb, opts->context, &context_sid);
718 712 if (rc)
713 goto out;
719 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, 714 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
720 context_sid)) 715 context_sid))
721 goto out_double_mount; 716 goto out_double_mount;
722
723 sbsec->flags |= CONTEXT_MNT; 717 sbsec->flags |= CONTEXT_MNT;
724 break; 718 }
725 case ROOTCONTEXT_MNT: 719 if (opts->rootcontext) {
726 rootcontext_sid = sid; 720 rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid);
727 721 if (rc)
722 goto out;
728 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, 723 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
729 rootcontext_sid)) 724 rootcontext_sid))
730 goto out_double_mount; 725 goto out_double_mount;
731
732 sbsec->flags |= ROOTCONTEXT_MNT; 726 sbsec->flags |= ROOTCONTEXT_MNT;
733 727 }
734 break; 728 if (opts->defcontext) {
735 case DEFCONTEXT_MNT: 729 rc = parse_sid(sb, opts->defcontext, &defcontext_sid);
736 defcontext_sid = sid; 730 if (rc)
737 731 goto out;
738 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, 732 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
739 defcontext_sid)) 733 defcontext_sid))
740 goto out_double_mount; 734 goto out_double_mount;
741
742 sbsec->flags |= DEFCONTEXT_MNT; 735 sbsec->flags |= DEFCONTEXT_MNT;
743
744 break;
745 default:
746 rc = -EINVAL;
747 goto out;
748 } 736 }
749 } 737 }
750 738
751 if (sbsec->flags & SE_SBINITIALIZED) { 739 if (sbsec->flags & SE_SBINITIALIZED) {
752 /* previously mounted with options, but not on this attempt? */ 740 /* previously mounted with options, but not on this attempt? */
753 if ((sbsec->flags & SE_MNTMASK) && !num_opts) 741 if ((sbsec->flags & SE_MNTMASK) && !opts)
754 goto out_double_mount; 742 goto out_double_mount;
755 rc = 0; 743 rc = 0;
756 goto out; 744 goto out;
@@ -883,7 +871,8 @@ out:
883out_double_mount: 871out_double_mount:
884 rc = -EINVAL; 872 rc = -EINVAL;
885 pr_warn("SELinux: mount invalid. Same superblock, different " 873 pr_warn("SELinux: mount invalid. Same superblock, different "
886 "security settings for (dev %s, type %s)\n", sb->s_id, name); 874 "security settings for (dev %s, type %s)\n", sb->s_id,
875 sb->s_type->name);
887 goto out; 876 goto out;
888} 877}
889 878
@@ -998,20 +987,9 @@ out:
998static int selinux_parse_opts_str(char *options, 987static int selinux_parse_opts_str(char *options,
999 void **mnt_opts) 988 void **mnt_opts)
1000{ 989{
990 struct selinux_mnt_opts *opts = *mnt_opts;
1001 char *p; 991 char *p;
1002 char *context = NULL, *defcontext = NULL; 992 int rc;
1003 char *fscontext = NULL, *rootcontext = NULL;
1004 int rc, num_mnt_opts = 0;
1005 struct security_mnt_opts *opts = *mnt_opts;
1006
1007 if (!opts) {
1008 opts = kzalloc(sizeof(struct security_mnt_opts), GFP_KERNEL);
1009 *mnt_opts = opts;
1010 if (!opts)
1011 return -ENOMEM;
1012 }
1013
1014 opts->num_mnt_opts = 0;
1015 993
1016 /* Standard string-based options. */ 994 /* Standard string-based options. */
1017 while ((p = strsep(&options, "|")) != NULL) { 995 while ((p = strsep(&options, "|")) != NULL) {
@@ -1023,54 +1001,60 @@ static int selinux_parse_opts_str(char *options,
1023 1001
1024 token = match_token(p, tokens, args); 1002 token = match_token(p, tokens, args);
1025 1003
1004 if (!opts) {
1005 opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
1006 if (!opts)
1007 return -ENOMEM;
1008 }
1009
1026 switch (token) { 1010 switch (token) {
1027 case Opt_context: 1011 case Opt_context:
1028 if (context || defcontext) { 1012 if (opts->context || opts->defcontext) {
1029 rc = -EINVAL; 1013 rc = -EINVAL;
1030 pr_warn(SEL_MOUNT_FAIL_MSG); 1014 pr_warn(SEL_MOUNT_FAIL_MSG);
1031 goto out_err; 1015 goto out_err;
1032 } 1016 }
1033 context = match_strdup(&args[0]); 1017 opts->context = match_strdup(&args[0]);
1034 if (!context) { 1018 if (!opts->context) {
1035 rc = -ENOMEM; 1019 rc = -ENOMEM;
1036 goto out_err; 1020 goto out_err;
1037 } 1021 }
1038 break; 1022 break;
1039 1023
1040 case Opt_fscontext: 1024 case Opt_fscontext:
1041 if (fscontext) { 1025 if (opts->fscontext) {
1042 rc = -EINVAL; 1026 rc = -EINVAL;
1043 pr_warn(SEL_MOUNT_FAIL_MSG); 1027 pr_warn(SEL_MOUNT_FAIL_MSG);
1044 goto out_err; 1028 goto out_err;
1045 } 1029 }
1046 fscontext = match_strdup(&args[0]); 1030 opts->fscontext = match_strdup(&args[0]);
1047 if (!fscontext) { 1031 if (!opts->fscontext) {
1048 rc = -ENOMEM; 1032 rc = -ENOMEM;
1049 goto out_err; 1033 goto out_err;
1050 } 1034 }
1051 break; 1035 break;
1052 1036
1053 case Opt_rootcontext: 1037 case Opt_rootcontext:
1054 if (rootcontext) { 1038 if (opts->rootcontext) {
1055 rc = -EINVAL; 1039 rc = -EINVAL;
1056 pr_warn(SEL_MOUNT_FAIL_MSG); 1040 pr_warn(SEL_MOUNT_FAIL_MSG);
1057 goto out_err; 1041 goto out_err;
1058 } 1042 }
1059 rootcontext = match_strdup(&args[0]); 1043 opts->rootcontext = match_strdup(&args[0]);
1060 if (!rootcontext) { 1044 if (!opts->rootcontext) {
1061 rc = -ENOMEM; 1045 rc = -ENOMEM;
1062 goto out_err; 1046 goto out_err;
1063 } 1047 }
1064 break; 1048 break;
1065 1049
1066 case Opt_defcontext: 1050 case Opt_defcontext:
1067 if (context || defcontext) { 1051 if (opts->context || opts->defcontext) {
1068 rc = -EINVAL; 1052 rc = -EINVAL;
1069 pr_warn(SEL_MOUNT_FAIL_MSG); 1053 pr_warn(SEL_MOUNT_FAIL_MSG);
1070 goto out_err; 1054 goto out_err;
1071 } 1055 }
1072 defcontext = match_strdup(&args[0]); 1056 opts->defcontext = match_strdup(&args[0]);
1073 if (!defcontext) { 1057 if (!opts->defcontext) {
1074 rc = -ENOMEM; 1058 rc = -ENOMEM;
1075 goto out_err; 1059 goto out_err;
1076 } 1060 }
@@ -1084,43 +1068,12 @@ static int selinux_parse_opts_str(char *options,
1084 1068
1085 } 1069 }
1086 } 1070 }
1087 1071 *mnt_opts = opts;
1088 rc = -ENOMEM;
1089 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_KERNEL);
1090 if (!opts->mnt_opts)
1091 goto out_err;
1092
1093 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int),
1094 GFP_KERNEL);
1095 if (!opts->mnt_opts_flags)
1096 goto out_err;
1097
1098 if (fscontext) {
1099 opts->mnt_opts[num_mnt_opts] = fscontext;
1100 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
1101 }
1102 if (context) {
1103 opts->mnt_opts[num_mnt_opts] = context;
1104 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
1105 }
1106 if (rootcontext) {
1107 opts->mnt_opts[num_mnt_opts] = rootcontext;
1108 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
1109 }
1110 if (defcontext) {
1111 opts->mnt_opts[num_mnt_opts] = defcontext;
1112 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
1113 }
1114
1115 opts->num_mnt_opts = num_mnt_opts;
1116 return 0; 1072 return 0;
1117 1073
1118out_err: 1074out_err:
1119 security_free_mnt_opts(mnt_opts); 1075 if (opts)
1120 kfree(context); 1076 selinux_free_mnt_opts(opts);
1121 kfree(defcontext);
1122 kfree(fscontext);
1123 kfree(rootcontext);
1124 return rc; 1077 return rc;
1125} 1078}
1126 1079
@@ -2752,10 +2705,10 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
2752 2705
2753static int selinux_sb_remount(struct super_block *sb, void *mnt_opts) 2706static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
2754{ 2707{
2755 struct security_mnt_opts *opts = mnt_opts; 2708 struct selinux_mnt_opts *opts = mnt_opts;
2756 int i, *flags;
2757 char **mount_options;
2758 struct superblock_security_struct *sbsec = sb->s_security; 2709 struct superblock_security_struct *sbsec = sb->s_security;
2710 u32 sid;
2711 int rc;
2759 2712
2760 if (!(sbsec->flags & SE_SBINITIALIZED)) 2713 if (!(sbsec->flags & SE_SBINITIALIZED))
2761 return 0; 2714 return 0;
@@ -2763,48 +2716,35 @@ static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
2763 if (!opts) 2716 if (!opts)
2764 return 0; 2717 return 0;
2765 2718
2766 mount_options = opts->mnt_opts; 2719 if (opts->fscontext) {
2767 flags = opts->mnt_opts_flags; 2720 rc = parse_sid(sb, opts->fscontext, &sid);
2768 2721 if (rc)
2769 for (i = 0; i < opts->num_mnt_opts; i++) {
2770 u32 sid;
2771 int rc;
2772
2773 if (flags[i] == SBLABEL_MNT)
2774 continue;
2775 rc = security_context_str_to_sid(&selinux_state,
2776 mount_options[i], &sid,
2777 GFP_KERNEL);
2778 if (rc) {
2779 pr_warn("SELinux: security_context_str_to_sid"
2780 "(%s) failed for (dev %s, type %s) errno=%d\n",
2781 mount_options[i], sb->s_id, sb->s_type->name, rc);
2782 return rc; 2722 return rc;
2783 } 2723 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
2784 switch (flags[i]) { 2724 goto out_bad_option;
2785 case FSCONTEXT_MNT: 2725 }
2786 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid)) 2726 if (opts->context) {
2787 goto out_bad_option; 2727 rc = parse_sid(sb, opts->context, &sid);
2788 break; 2728 if (rc)
2789 case CONTEXT_MNT: 2729 return rc;
2790 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid)) 2730 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
2791 goto out_bad_option; 2731 goto out_bad_option;
2792 break; 2732 }
2793 case ROOTCONTEXT_MNT: { 2733 if (opts->rootcontext) {
2794 struct inode_security_struct *root_isec; 2734 struct inode_security_struct *root_isec;
2795 root_isec = backing_inode_security(sb->s_root); 2735 root_isec = backing_inode_security(sb->s_root);
2796 2736 rc = parse_sid(sb, opts->rootcontext, &sid);
2797 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid)) 2737 if (rc)
2798 goto out_bad_option; 2738 return rc;
2799 break; 2739 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
2800 } 2740 goto out_bad_option;
2801 case DEFCONTEXT_MNT: 2741 }
2802 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) 2742 if (opts->defcontext) {
2803 goto out_bad_option; 2743 rc = parse_sid(sb, opts->defcontext, &sid);
2804 break; 2744 if (rc)
2805 default: 2745 return rc;
2806 return -EINVAL; 2746 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
2807 } 2747 goto out_bad_option;
2808 } 2748 }
2809 return 0; 2749 return 0;
2810 2750