diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2018-12-13 15:04:59 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2018-12-21 11:48:45 -0500 |
commit | bd3236557bb256d6491df125e5e9d0393c70e4d2 (patch) | |
tree | 1694eb11ac33095c03868f79055b1d373a5f6c8e /security/selinux | |
parent | 204cc0ccf1d49c6292aeef4c8edd1b3d10ff933c (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.c | 262 |
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 | ||
436 | struct selinux_mnt_opts { | ||
437 | const char *fscontext, *context, *rootcontext, *defcontext; | ||
438 | }; | ||
439 | |||
436 | static void selinux_free_mnt_opts(void *mnt_opts) | 440 | static 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 | ||
628 | static 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: | |||
883 | out_double_mount: | 871 | out_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: | |||
998 | static int selinux_parse_opts_str(char *options, | 987 | static 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 | ||
1118 | out_err: | 1074 | out_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 | ||
2753 | static int selinux_sb_remount(struct super_block *sb, void *mnt_opts) | 2706 | static 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 | ||