summaryrefslogtreecommitdiffstats
path: root/security/selinux
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-01-05 16:25:58 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2019-01-05 16:25:58 -0500
commit505b050fdf42097883b2d37b8e796e1f11dbef50 (patch)
tree21f5b43505a5771d13533ac675c785a9bf480fdc /security/selinux
parent9b286efeb5eb5aaa2712873fc1f928b2f879dbde (diff)
parent718c43038f287e843c2f63d946977de90014cb11 (diff)
Merge branch 'mount.part1' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs mount API prep from Al Viro: "Mount API prereqs. Mostly that's LSM mount options cleanups. There are several minor fixes in there, but nothing earth-shattering (leaks on failure exits, mostly)" * 'mount.part1' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (27 commits) mount_fs: suppress MAC on MS_SUBMOUNT as well as MS_KERNMOUNT smack: rewrite smack_sb_eat_lsm_opts() smack: get rid of match_token() smack: take the guts of smack_parse_opts_str() into a new helper LSM: new method: ->sb_add_mnt_opt() selinux: rewrite selinux_sb_eat_lsm_opts() selinux: regularize Opt_... names a bit selinux: switch away from match_token() selinux: new helper - selinux_add_opt() LSM: bury struct security_mnt_opts smack: switch to private smack_mnt_opts selinux: switch to private struct selinux_mnt_opts LSM: hide struct security_mnt_opts from any generic code selinux: kill selinux_sb_get_mnt_opts() LSM: turn sb_eat_lsm_opts() into a method nfs_remount(): don't leak, don't ignore LSM options quietly btrfs: sanitize security_mnt_opts use selinux; don't open-code a loop in sb_finish_set_opts() LSM: split ->sb_set_mnt_opts() out of ->sb_kern_mount() new helper: security_sb_eat_lsm_opts() ...
Diffstat (limited to 'security/selinux')
-rw-r--r--security/selinux/hooks.c799
1 files changed, 293 insertions, 506 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 0f27db6d94a9..f0e36c3492ba 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -88,6 +88,7 @@
88#include <linux/msg.h> 88#include <linux/msg.h>
89#include <linux/shm.h> 89#include <linux/shm.h>
90#include <linux/bpf.h> 90#include <linux/bpf.h>
91#include <uapi/linux/mount.h>
91 92
92#include "avc.h" 93#include "avc.h"
93#include "objsec.h" 94#include "objsec.h"
@@ -432,6 +433,20 @@ static void superblock_free_security(struct super_block *sb)
432 kfree(sbsec); 433 kfree(sbsec);
433} 434}
434 435
436struct selinux_mnt_opts {
437 const char *fscontext, *context, *rootcontext, *defcontext;
438};
439
440static void selinux_free_mnt_opts(void *mnt_opts)
441{
442 struct selinux_mnt_opts *opts = mnt_opts;
443 kfree(opts->fscontext);
444 kfree(opts->context);
445 kfree(opts->rootcontext);
446 kfree(opts->defcontext);
447 kfree(opts);
448}
449
435static inline int inode_doinit(struct inode *inode) 450static inline int inode_doinit(struct inode *inode)
436{ 451{
437 return inode_doinit_with_dentry(inode, NULL); 452 return inode_doinit_with_dentry(inode, NULL);
@@ -443,20 +458,42 @@ enum {
443 Opt_fscontext = 2, 458 Opt_fscontext = 2,
444 Opt_defcontext = 3, 459 Opt_defcontext = 3,
445 Opt_rootcontext = 4, 460 Opt_rootcontext = 4,
446 Opt_labelsupport = 5, 461 Opt_seclabel = 5,
447 Opt_nextmntopt = 6,
448}; 462};
449 463
450#define NUM_SEL_MNT_OPTS (Opt_nextmntopt - 1) 464#define A(s, has_arg) {#s, sizeof(#s) - 1, Opt_##s, has_arg}
451 465static struct {
452static const match_table_t tokens = { 466 const char *name;
453 {Opt_context, CONTEXT_STR "%s"}, 467 int len;
454 {Opt_fscontext, FSCONTEXT_STR "%s"}, 468 int opt;
455 {Opt_defcontext, DEFCONTEXT_STR "%s"}, 469 bool has_arg;
456 {Opt_rootcontext, ROOTCONTEXT_STR "%s"}, 470} tokens[] = {
457 {Opt_labelsupport, LABELSUPP_STR}, 471 A(context, true),
458 {Opt_error, NULL}, 472 A(fscontext, true),
473 A(defcontext, true),
474 A(rootcontext, true),
475 A(seclabel, false),
459}; 476};
477#undef A
478
479static int match_opt_prefix(char *s, int l, char **arg)
480{
481 int i;
482
483 for (i = 0; i < ARRAY_SIZE(tokens); i++) {
484 size_t len = tokens[i].len;
485 if (len > l || memcmp(s, tokens[i].name, len))
486 continue;
487 if (tokens[i].has_arg) {
488 if (len == l || s[len] != '=')
489 continue;
490 *arg = s + len + 1;
491 } else if (len != l)
492 continue;
493 return tokens[i].opt;
494 }
495 return Opt_error;
496}
460 497
461#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" 498#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
462 499
@@ -570,10 +607,9 @@ static int sb_finish_set_opts(struct super_block *sb)
570 during get_sb by a pseudo filesystem that directly 607 during get_sb by a pseudo filesystem that directly
571 populates itself. */ 608 populates itself. */
572 spin_lock(&sbsec->isec_lock); 609 spin_lock(&sbsec->isec_lock);
573next_inode: 610 while (!list_empty(&sbsec->isec_head)) {
574 if (!list_empty(&sbsec->isec_head)) {
575 struct inode_security_struct *isec = 611 struct inode_security_struct *isec =
576 list_entry(sbsec->isec_head.next, 612 list_first_entry(&sbsec->isec_head,
577 struct inode_security_struct, list); 613 struct inode_security_struct, list);
578 struct inode *inode = isec->inode; 614 struct inode *inode = isec->inode;
579 list_del_init(&isec->list); 615 list_del_init(&isec->list);
@@ -585,112 +621,12 @@ next_inode:
585 iput(inode); 621 iput(inode);
586 } 622 }
587 spin_lock(&sbsec->isec_lock); 623 spin_lock(&sbsec->isec_lock);
588 goto next_inode;
589 } 624 }
590 spin_unlock(&sbsec->isec_lock); 625 spin_unlock(&sbsec->isec_lock);
591out: 626out:
592 return rc; 627 return rc;
593} 628}
594 629
595/*
596 * This function should allow an FS to ask what it's mount security
597 * options were so it can use those later for submounts, displaying
598 * mount options, or whatever.
599 */
600static int selinux_get_mnt_opts(const struct super_block *sb,
601 struct security_mnt_opts *opts)
602{
603 int rc = 0, i;
604 struct superblock_security_struct *sbsec = sb->s_security;
605 char *context = NULL;
606 u32 len;
607 char tmp;
608
609 security_init_mnt_opts(opts);
610
611 if (!(sbsec->flags & SE_SBINITIALIZED))
612 return -EINVAL;
613
614 if (!selinux_state.initialized)
615 return -EINVAL;
616
617 /* make sure we always check enough bits to cover the mask */
618 BUILD_BUG_ON(SE_MNTMASK >= (1 << NUM_SEL_MNT_OPTS));
619
620 tmp = sbsec->flags & SE_MNTMASK;
621 /* count the number of mount options for this sb */
622 for (i = 0; i < NUM_SEL_MNT_OPTS; i++) {
623 if (tmp & 0x01)
624 opts->num_mnt_opts++;
625 tmp >>= 1;
626 }
627 /* Check if the Label support flag is set */
628 if (sbsec->flags & SBLABEL_MNT)
629 opts->num_mnt_opts++;
630
631 opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
632 if (!opts->mnt_opts) {
633 rc = -ENOMEM;
634 goto out_free;
635 }
636
637 opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
638 if (!opts->mnt_opts_flags) {
639 rc = -ENOMEM;
640 goto out_free;
641 }
642
643 i = 0;
644 if (sbsec->flags & FSCONTEXT_MNT) {
645 rc = security_sid_to_context(&selinux_state, sbsec->sid,
646 &context, &len);
647 if (rc)
648 goto out_free;
649 opts->mnt_opts[i] = context;
650 opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
651 }
652 if (sbsec->flags & CONTEXT_MNT) {
653 rc = security_sid_to_context(&selinux_state,
654 sbsec->mntpoint_sid,
655 &context, &len);
656 if (rc)
657 goto out_free;
658 opts->mnt_opts[i] = context;
659 opts->mnt_opts_flags[i++] = CONTEXT_MNT;
660 }
661 if (sbsec->flags & DEFCONTEXT_MNT) {
662 rc = security_sid_to_context(&selinux_state, sbsec->def_sid,
663 &context, &len);
664 if (rc)
665 goto out_free;
666 opts->mnt_opts[i] = context;
667 opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
668 }
669 if (sbsec->flags & ROOTCONTEXT_MNT) {
670 struct dentry *root = sbsec->sb->s_root;
671 struct inode_security_struct *isec = backing_inode_security(root);
672
673 rc = security_sid_to_context(&selinux_state, isec->sid,
674 &context, &len);
675 if (rc)
676 goto out_free;
677 opts->mnt_opts[i] = context;
678 opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
679 }
680 if (sbsec->flags & SBLABEL_MNT) {
681 opts->mnt_opts[i] = NULL;
682 opts->mnt_opts_flags[i++] = SBLABEL_MNT;
683 }
684
685 BUG_ON(i != opts->num_mnt_opts);
686
687 return 0;
688
689out_free:
690 security_free_mnt_opts(opts);
691 return rc;
692}
693
694static int bad_option(struct superblock_security_struct *sbsec, char flag, 630static int bad_option(struct superblock_security_struct *sbsec, char flag,
695 u32 old_sid, u32 new_sid) 631 u32 old_sid, u32 new_sid)
696{ 632{
@@ -711,31 +647,39 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
711 return 0; 647 return 0;
712} 648}
713 649
650static int parse_sid(struct super_block *sb, const char *s, u32 *sid)
651{
652 int rc = security_context_str_to_sid(&selinux_state, s,
653 sid, GFP_KERNEL);
654 if (rc)
655 pr_warn("SELinux: security_context_str_to_sid"
656 "(%s) failed for (dev %s, type %s) errno=%d\n",
657 s, sb->s_id, sb->s_type->name, rc);
658 return rc;
659}
660
714/* 661/*
715 * Allow filesystems with binary mount data to explicitly set mount point 662 * Allow filesystems with binary mount data to explicitly set mount point
716 * labeling information. 663 * labeling information.
717 */ 664 */
718static int selinux_set_mnt_opts(struct super_block *sb, 665static int selinux_set_mnt_opts(struct super_block *sb,
719 struct security_mnt_opts *opts, 666 void *mnt_opts,
720 unsigned long kern_flags, 667 unsigned long kern_flags,
721 unsigned long *set_kern_flags) 668 unsigned long *set_kern_flags)
722{ 669{
723 const struct cred *cred = current_cred(); 670 const struct cred *cred = current_cred();
724 int rc = 0, i;
725 struct superblock_security_struct *sbsec = sb->s_security; 671 struct superblock_security_struct *sbsec = sb->s_security;
726 const char *name = sb->s_type->name;
727 struct dentry *root = sbsec->sb->s_root; 672 struct dentry *root = sbsec->sb->s_root;
673 struct selinux_mnt_opts *opts = mnt_opts;
728 struct inode_security_struct *root_isec; 674 struct inode_security_struct *root_isec;
729 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; 675 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
730 u32 defcontext_sid = 0; 676 u32 defcontext_sid = 0;
731 char **mount_options = opts->mnt_opts; 677 int rc = 0;
732 int *flags = opts->mnt_opts_flags;
733 int num_opts = opts->num_mnt_opts;
734 678
735 mutex_lock(&sbsec->lock); 679 mutex_lock(&sbsec->lock);
736 680
737 if (!selinux_state.initialized) { 681 if (!selinux_state.initialized) {
738 if (!num_opts) { 682 if (!opts) {
739 /* Defer initialization until selinux_complete_init, 683 /* Defer initialization until selinux_complete_init,
740 after the initial policy is loaded and the security 684 after the initial policy is loaded and the security
741 server is ready to handle calls. */ 685 server is ready to handle calls. */
@@ -765,7 +709,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
765 * will be used for both mounts) 709 * will be used for both mounts)
766 */ 710 */
767 if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) 711 if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
768 && (num_opts == 0)) 712 && !opts)
769 goto out; 713 goto out;
770 714
771 root_isec = backing_inode_security_novalidate(root); 715 root_isec = backing_inode_security_novalidate(root);
@@ -775,68 +719,48 @@ static int selinux_set_mnt_opts(struct super_block *sb,
775 * also check if someone is trying to mount the same sb more 719 * also check if someone is trying to mount the same sb more
776 * than once with different security options. 720 * than once with different security options.
777 */ 721 */
778 for (i = 0; i < num_opts; i++) { 722 if (opts) {
779 u32 sid; 723 if (opts->fscontext) {
780 724 rc = parse_sid(sb, opts->fscontext, &fscontext_sid);
781 if (flags[i] == SBLABEL_MNT) 725 if (rc)
782 continue; 726 goto out;
783 rc = security_context_str_to_sid(&selinux_state,
784 mount_options[i], &sid,
785 GFP_KERNEL);
786 if (rc) {
787 pr_warn("SELinux: security_context_str_to_sid"
788 "(%s) failed for (dev %s, type %s) errno=%d\n",
789 mount_options[i], sb->s_id, name, rc);
790 goto out;
791 }
792 switch (flags[i]) {
793 case FSCONTEXT_MNT:
794 fscontext_sid = sid;
795
796 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, 727 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
797 fscontext_sid)) 728 fscontext_sid))
798 goto out_double_mount; 729 goto out_double_mount;
799
800 sbsec->flags |= FSCONTEXT_MNT; 730 sbsec->flags |= FSCONTEXT_MNT;
801 break; 731 }
802 case CONTEXT_MNT: 732 if (opts->context) {
803 context_sid = sid; 733 rc = parse_sid(sb, opts->context, &context_sid);
804 734 if (rc)
735 goto out;
805 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, 736 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
806 context_sid)) 737 context_sid))
807 goto out_double_mount; 738 goto out_double_mount;
808
809 sbsec->flags |= CONTEXT_MNT; 739 sbsec->flags |= CONTEXT_MNT;
810 break; 740 }
811 case ROOTCONTEXT_MNT: 741 if (opts->rootcontext) {
812 rootcontext_sid = sid; 742 rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid);
813 743 if (rc)
744 goto out;
814 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, 745 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
815 rootcontext_sid)) 746 rootcontext_sid))
816 goto out_double_mount; 747 goto out_double_mount;
817
818 sbsec->flags |= ROOTCONTEXT_MNT; 748 sbsec->flags |= ROOTCONTEXT_MNT;
819 749 }
820 break; 750 if (opts->defcontext) {
821 case DEFCONTEXT_MNT: 751 rc = parse_sid(sb, opts->defcontext, &defcontext_sid);
822 defcontext_sid = sid; 752 if (rc)
823 753 goto out;
824 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, 754 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
825 defcontext_sid)) 755 defcontext_sid))
826 goto out_double_mount; 756 goto out_double_mount;
827
828 sbsec->flags |= DEFCONTEXT_MNT; 757 sbsec->flags |= DEFCONTEXT_MNT;
829
830 break;
831 default:
832 rc = -EINVAL;
833 goto out;
834 } 758 }
835 } 759 }
836 760
837 if (sbsec->flags & SE_SBINITIALIZED) { 761 if (sbsec->flags & SE_SBINITIALIZED) {
838 /* previously mounted with options, but not on this attempt? */ 762 /* previously mounted with options, but not on this attempt? */
839 if ((sbsec->flags & SE_MNTMASK) && !num_opts) 763 if ((sbsec->flags & SE_MNTMASK) && !opts)
840 goto out_double_mount; 764 goto out_double_mount;
841 rc = 0; 765 rc = 0;
842 goto out; 766 goto out;
@@ -969,7 +893,8 @@ out:
969out_double_mount: 893out_double_mount:
970 rc = -EINVAL; 894 rc = -EINVAL;
971 pr_warn("SELinux: mount invalid. Same superblock, different " 895 pr_warn("SELinux: mount invalid. Same superblock, different "
972 "security settings for (dev %s, type %s)\n", sb->s_id, name); 896 "security settings for (dev %s, type %s)\n", sb->s_id,
897 sb->s_type->name);
973 goto out; 898 goto out;
974} 899}
975 900
@@ -1081,218 +1006,145 @@ out:
1081 return rc; 1006 return rc;
1082} 1007}
1083 1008
1084static int selinux_parse_opts_str(char *options, 1009static int selinux_add_opt(int token, const char *s, void **mnt_opts)
1085 struct security_mnt_opts *opts)
1086{ 1010{
1087 char *p; 1011 struct selinux_mnt_opts *opts = *mnt_opts;
1088 char *context = NULL, *defcontext = NULL;
1089 char *fscontext = NULL, *rootcontext = NULL;
1090 int rc, num_mnt_opts = 0;
1091
1092 opts->num_mnt_opts = 0;
1093 1012
1094 /* Standard string-based options. */ 1013 if (token == Opt_seclabel) /* eaten and completely ignored */
1095 while ((p = strsep(&options, "|")) != NULL) { 1014 return 0;
1096 int token;
1097 substring_t args[MAX_OPT_ARGS];
1098
1099 if (!*p)
1100 continue;
1101
1102 token = match_token(p, tokens, args);
1103
1104 switch (token) {
1105 case Opt_context:
1106 if (context || defcontext) {
1107 rc = -EINVAL;
1108 pr_warn(SEL_MOUNT_FAIL_MSG);
1109 goto out_err;
1110 }
1111 context = match_strdup(&args[0]);
1112 if (!context) {
1113 rc = -ENOMEM;
1114 goto out_err;
1115 }
1116 break;
1117
1118 case Opt_fscontext:
1119 if (fscontext) {
1120 rc = -EINVAL;
1121 pr_warn(SEL_MOUNT_FAIL_MSG);
1122 goto out_err;
1123 }
1124 fscontext = match_strdup(&args[0]);
1125 if (!fscontext) {
1126 rc = -ENOMEM;
1127 goto out_err;
1128 }
1129 break;
1130
1131 case Opt_rootcontext:
1132 if (rootcontext) {
1133 rc = -EINVAL;
1134 pr_warn(SEL_MOUNT_FAIL_MSG);
1135 goto out_err;
1136 }
1137 rootcontext = match_strdup(&args[0]);
1138 if (!rootcontext) {
1139 rc = -ENOMEM;
1140 goto out_err;
1141 }
1142 break;
1143
1144 case Opt_defcontext:
1145 if (context || defcontext) {
1146 rc = -EINVAL;
1147 pr_warn(SEL_MOUNT_FAIL_MSG);
1148 goto out_err;
1149 }
1150 defcontext = match_strdup(&args[0]);
1151 if (!defcontext) {
1152 rc = -ENOMEM;
1153 goto out_err;
1154 }
1155 break;
1156 case Opt_labelsupport:
1157 break;
1158 default:
1159 rc = -EINVAL;
1160 pr_warn("SELinux: unknown mount option\n");
1161 goto out_err;
1162
1163 }
1164 }
1165
1166 rc = -ENOMEM;
1167 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_KERNEL);
1168 if (!opts->mnt_opts)
1169 goto out_err;
1170
1171 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int),
1172 GFP_KERNEL);
1173 if (!opts->mnt_opts_flags)
1174 goto out_err;
1175 1015
1176 if (fscontext) { 1016 if (!opts) {
1177 opts->mnt_opts[num_mnt_opts] = fscontext; 1017 opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
1178 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT; 1018 if (!opts)
1179 } 1019 return -ENOMEM;
1180 if (context) { 1020 *mnt_opts = opts;
1181 opts->mnt_opts[num_mnt_opts] = context;
1182 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
1183 }
1184 if (rootcontext) {
1185 opts->mnt_opts[num_mnt_opts] = rootcontext;
1186 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
1187 } 1021 }
1188 if (defcontext) { 1022 if (!s)
1189 opts->mnt_opts[num_mnt_opts] = defcontext; 1023 return -ENOMEM;
1190 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT; 1024 switch (token) {
1025 case Opt_context:
1026 if (opts->context || opts->defcontext)
1027 goto Einval;
1028 opts->context = s;
1029 break;
1030 case Opt_fscontext:
1031 if (opts->fscontext)
1032 goto Einval;
1033 opts->fscontext = s;
1034 break;
1035 case Opt_rootcontext:
1036 if (opts->rootcontext)
1037 goto Einval;
1038 opts->rootcontext = s;
1039 break;
1040 case Opt_defcontext:
1041 if (opts->context || opts->defcontext)
1042 goto Einval;
1043 opts->defcontext = s;
1044 break;
1191 } 1045 }
1192
1193 opts->num_mnt_opts = num_mnt_opts;
1194 return 0; 1046 return 0;
1195 1047Einval:
1196out_err: 1048 pr_warn(SEL_MOUNT_FAIL_MSG);
1197 security_free_mnt_opts(opts); 1049 return -EINVAL;
1198 kfree(context);
1199 kfree(defcontext);
1200 kfree(fscontext);
1201 kfree(rootcontext);
1202 return rc;
1203} 1050}
1204/*
1205 * string mount options parsing and call set the sbsec
1206 */
1207static int superblock_doinit(struct super_block *sb, void *data)
1208{
1209 int rc = 0;
1210 char *options = data;
1211 struct security_mnt_opts opts;
1212
1213 security_init_mnt_opts(&opts);
1214
1215 if (!data)
1216 goto out;
1217 1051
1218 BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA); 1052static int selinux_add_mnt_opt(const char *option, const char *val, int len,
1053 void **mnt_opts)
1054{
1055 int token = Opt_error;
1056 int rc, i;
1219 1057
1220 rc = selinux_parse_opts_str(options, &opts); 1058 for (i = 0; i < ARRAY_SIZE(tokens); i++) {
1221 if (rc) 1059 if (strcmp(option, tokens[i].name) == 0) {
1222 goto out_err; 1060 token = tokens[i].opt;
1061 break;
1062 }
1063 }
1223 1064
1224out: 1065 if (token == Opt_error)
1225 rc = selinux_set_mnt_opts(sb, &opts, 0, NULL); 1066 return -EINVAL;
1226 1067
1227out_err: 1068 if (token != Opt_seclabel)
1228 security_free_mnt_opts(&opts); 1069 val = kmemdup_nul(val, len, GFP_KERNEL);
1070 rc = selinux_add_opt(token, val, mnt_opts);
1071 if (unlikely(rc)) {
1072 kfree(val);
1073 if (*mnt_opts) {
1074 selinux_free_mnt_opts(*mnt_opts);
1075 *mnt_opts = NULL;
1076 }
1077 }
1229 return rc; 1078 return rc;
1230} 1079}
1231 1080
1232static void selinux_write_opts(struct seq_file *m, 1081static int show_sid(struct seq_file *m, u32 sid)
1233 struct security_mnt_opts *opts)
1234{ 1082{
1235 int i; 1083 char *context = NULL;
1236 char *prefix; 1084 u32 len;
1237 1085 int rc;
1238 for (i = 0; i < opts->num_mnt_opts; i++) {
1239 char *has_comma;
1240 1086
1241 if (opts->mnt_opts[i]) 1087 rc = security_sid_to_context(&selinux_state, sid,
1242 has_comma = strchr(opts->mnt_opts[i], ','); 1088 &context, &len);
1243 else 1089 if (!rc) {
1244 has_comma = NULL; 1090 bool has_comma = context && strchr(context, ',');
1245 1091
1246 switch (opts->mnt_opts_flags[i]) {
1247 case CONTEXT_MNT:
1248 prefix = CONTEXT_STR;
1249 break;
1250 case FSCONTEXT_MNT:
1251 prefix = FSCONTEXT_STR;
1252 break;
1253 case ROOTCONTEXT_MNT:
1254 prefix = ROOTCONTEXT_STR;
1255 break;
1256 case DEFCONTEXT_MNT:
1257 prefix = DEFCONTEXT_STR;
1258 break;
1259 case SBLABEL_MNT:
1260 seq_putc(m, ',');
1261 seq_puts(m, LABELSUPP_STR);
1262 continue;
1263 default:
1264 BUG();
1265 return;
1266 };
1267 /* we need a comma before each option */
1268 seq_putc(m, ',');
1269 seq_puts(m, prefix);
1270 if (has_comma) 1092 if (has_comma)
1271 seq_putc(m, '\"'); 1093 seq_putc(m, '\"');
1272 seq_escape(m, opts->mnt_opts[i], "\"\n\\"); 1094 seq_escape(m, context, "\"\n\\");
1273 if (has_comma) 1095 if (has_comma)
1274 seq_putc(m, '\"'); 1096 seq_putc(m, '\"');
1275 } 1097 }
1098 kfree(context);
1099 return rc;
1276} 1100}
1277 1101
1278static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb) 1102static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
1279{ 1103{
1280 struct security_mnt_opts opts; 1104 struct superblock_security_struct *sbsec = sb->s_security;
1281 int rc; 1105 int rc;
1282 1106
1283 rc = selinux_get_mnt_opts(sb, &opts); 1107 if (!(sbsec->flags & SE_SBINITIALIZED))
1284 if (rc) { 1108 return 0;
1285 /* before policy load we may get EINVAL, don't show anything */
1286 if (rc == -EINVAL)
1287 rc = 0;
1288 return rc;
1289 }
1290
1291 selinux_write_opts(m, &opts);
1292 1109
1293 security_free_mnt_opts(&opts); 1110 if (!selinux_state.initialized)
1111 return 0;
1294 1112
1295 return rc; 1113 if (sbsec->flags & FSCONTEXT_MNT) {
1114 seq_putc(m, ',');
1115 seq_puts(m, FSCONTEXT_STR);
1116 rc = show_sid(m, sbsec->sid);
1117 if (rc)
1118 return rc;
1119 }
1120 if (sbsec->flags & CONTEXT_MNT) {
1121 seq_putc(m, ',');
1122 seq_puts(m, CONTEXT_STR);
1123 rc = show_sid(m, sbsec->mntpoint_sid);
1124 if (rc)
1125 return rc;
1126 }
1127 if (sbsec->flags & DEFCONTEXT_MNT) {
1128 seq_putc(m, ',');
1129 seq_puts(m, DEFCONTEXT_STR);
1130 rc = show_sid(m, sbsec->def_sid);
1131 if (rc)
1132 return rc;
1133 }
1134 if (sbsec->flags & ROOTCONTEXT_MNT) {
1135 struct dentry *root = sbsec->sb->s_root;
1136 struct inode_security_struct *isec = backing_inode_security(root);
1137 seq_putc(m, ',');
1138 seq_puts(m, ROOTCONTEXT_STR);
1139 rc = show_sid(m, isec->sid);
1140 if (rc)
1141 return rc;
1142 }
1143 if (sbsec->flags & SBLABEL_MNT) {
1144 seq_putc(m, ',');
1145 seq_puts(m, LABELSUPP_STR);
1146 }
1147 return 0;
1296} 1148}
1297 1149
1298static inline u16 inode_mode_to_security_class(umode_t mode) 1150static inline u16 inode_mode_to_security_class(umode_t mode)
@@ -2747,195 +2599,129 @@ static void selinux_sb_free_security(struct super_block *sb)
2747 superblock_free_security(sb); 2599 superblock_free_security(sb);
2748} 2600}
2749 2601
2750static inline int match_prefix(char *prefix, int plen, char *option, int olen) 2602static inline int opt_len(const char *s)
2751{ 2603{
2752 if (plen > olen) 2604 bool open_quote = false;
2753 return 0; 2605 int len;
2754 2606 char c;
2755 return !memcmp(prefix, option, plen);
2756}
2757
2758static inline int selinux_option(char *option, int len)
2759{
2760 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2761 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2762 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
2763 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
2764 match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
2765}
2766 2607
2767static inline void take_option(char **to, char *from, int *first, int len) 2608 for (len = 0; (c = s[len]) != '\0'; len++) {
2768{ 2609 if (c == '"')
2769 if (!*first) { 2610 open_quote = !open_quote;
2770 **to = ','; 2611 if (c == ',' && !open_quote)
2771 *to += 1; 2612 break;
2772 } else
2773 *first = 0;
2774 memcpy(*to, from, len);
2775 *to += len;
2776}
2777
2778static inline void take_selinux_option(char **to, char *from, int *first,
2779 int len)
2780{
2781 int current_size = 0;
2782
2783 if (!*first) {
2784 **to = '|';
2785 *to += 1;
2786 } else
2787 *first = 0;
2788
2789 while (current_size < len) {
2790 if (*from != '"') {
2791 **to = *from;
2792 *to += 1;
2793 }
2794 from += 1;
2795 current_size += 1;
2796 } 2613 }
2614 return len;
2797} 2615}
2798 2616
2799static int selinux_sb_copy_data(char *orig, char *copy) 2617static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
2800{ 2618{
2801 int fnosec, fsec, rc = 0; 2619 char *from = options;
2802 char *in_save, *in_curr, *in_end; 2620 char *to = options;
2803 char *sec_curr, *nosec_save, *nosec; 2621 bool first = true;
2804 int open_quote = 0;
2805
2806 in_curr = orig;
2807 sec_curr = copy;
2808 2622
2809 nosec = (char *)get_zeroed_page(GFP_KERNEL); 2623 while (1) {
2810 if (!nosec) { 2624 int len = opt_len(from);
2811 rc = -ENOMEM; 2625 int token, rc;
2812 goto out; 2626 char *arg = NULL;
2813 }
2814 2627
2815 nosec_save = nosec; 2628 token = match_opt_prefix(from, len, &arg);
2816 fnosec = fsec = 1;
2817 in_save = in_end = orig;
2818 2629
2819 do { 2630 if (token != Opt_error) {
2820 if (*in_end == '"') 2631 char *p, *q;
2821 open_quote = !open_quote;
2822 if ((*in_end == ',' && open_quote == 0) ||
2823 *in_end == '\0') {
2824 int len = in_end - in_curr;
2825
2826 if (selinux_option(in_curr, len))
2827 take_selinux_option(&sec_curr, in_curr, &fsec, len);
2828 else
2829 take_option(&nosec, in_curr, &fnosec, len);
2830 2632
2831 in_curr = in_end + 1; 2633 /* strip quotes */
2634 if (arg) {
2635 for (p = q = arg; p < from + len; p++) {
2636 char c = *p;
2637 if (c != '"')
2638 *q++ = c;
2639 }
2640 arg = kmemdup_nul(arg, q - arg, GFP_KERNEL);
2641 }
2642 rc = selinux_add_opt(token, arg, mnt_opts);
2643 if (unlikely(rc)) {
2644 kfree(arg);
2645 if (*mnt_opts) {
2646 selinux_free_mnt_opts(*mnt_opts);
2647 *mnt_opts = NULL;
2648 }
2649 return rc;
2650 }
2651 } else {
2652 if (!first) { // copy with preceding comma
2653 from--;
2654 len++;
2655 }
2656 if (to != from)
2657 memmove(to, from, len);
2658 to += len;
2659 first = false;
2832 } 2660 }
2833 } while (*in_end++); 2661 if (!from[len])
2834 2662 break;
2835 strcpy(in_save, nosec_save); 2663 from += len + 1;
2836 free_page((unsigned long)nosec_save); 2664 }
2837out: 2665 *to = '\0';
2838 return rc; 2666 return 0;
2839} 2667}
2840 2668
2841static int selinux_sb_remount(struct super_block *sb, void *data) 2669static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
2842{ 2670{
2843 int rc, i, *flags; 2671 struct selinux_mnt_opts *opts = mnt_opts;
2844 struct security_mnt_opts opts;
2845 char *secdata, **mount_options;
2846 struct superblock_security_struct *sbsec = sb->s_security; 2672 struct superblock_security_struct *sbsec = sb->s_security;
2673 u32 sid;
2674 int rc;
2847 2675
2848 if (!(sbsec->flags & SE_SBINITIALIZED)) 2676 if (!(sbsec->flags & SE_SBINITIALIZED))
2849 return 0; 2677 return 0;
2850 2678
2851 if (!data) 2679 if (!opts)
2852 return 0; 2680 return 0;
2853 2681
2854 if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) 2682 if (opts->fscontext) {
2855 return 0; 2683 rc = parse_sid(sb, opts->fscontext, &sid);
2856 2684 if (rc)
2857 security_init_mnt_opts(&opts); 2685 return rc;
2858 secdata = alloc_secdata(); 2686 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
2859 if (!secdata) 2687 goto out_bad_option;
2860 return -ENOMEM;
2861 rc = selinux_sb_copy_data(data, secdata);
2862 if (rc)
2863 goto out_free_secdata;
2864
2865 rc = selinux_parse_opts_str(secdata, &opts);
2866 if (rc)
2867 goto out_free_secdata;
2868
2869 mount_options = opts.mnt_opts;
2870 flags = opts.mnt_opts_flags;
2871
2872 for (i = 0; i < opts.num_mnt_opts; i++) {
2873 u32 sid;
2874
2875 if (flags[i] == SBLABEL_MNT)
2876 continue;
2877 rc = security_context_str_to_sid(&selinux_state,
2878 mount_options[i], &sid,
2879 GFP_KERNEL);
2880 if (rc) {
2881 pr_warn("SELinux: security_context_str_to_sid"
2882 "(%s) failed for (dev %s, type %s) errno=%d\n",
2883 mount_options[i], sb->s_id, sb->s_type->name, rc);
2884 goto out_free_opts;
2885 }
2886 rc = -EINVAL;
2887 switch (flags[i]) {
2888 case FSCONTEXT_MNT:
2889 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
2890 goto out_bad_option;
2891 break;
2892 case CONTEXT_MNT:
2893 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
2894 goto out_bad_option;
2895 break;
2896 case ROOTCONTEXT_MNT: {
2897 struct inode_security_struct *root_isec;
2898 root_isec = backing_inode_security(sb->s_root);
2899
2900 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
2901 goto out_bad_option;
2902 break;
2903 }
2904 case DEFCONTEXT_MNT:
2905 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
2906 goto out_bad_option;
2907 break;
2908 default:
2909 goto out_free_opts;
2910 }
2911 } 2688 }
2689 if (opts->context) {
2690 rc = parse_sid(sb, opts->context, &sid);
2691 if (rc)
2692 return rc;
2693 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
2694 goto out_bad_option;
2695 }
2696 if (opts->rootcontext) {
2697 struct inode_security_struct *root_isec;
2698 root_isec = backing_inode_security(sb->s_root);
2699 rc = parse_sid(sb, opts->rootcontext, &sid);
2700 if (rc)
2701 return rc;
2702 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
2703 goto out_bad_option;
2704 }
2705 if (opts->defcontext) {
2706 rc = parse_sid(sb, opts->defcontext, &sid);
2707 if (rc)
2708 return rc;
2709 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
2710 goto out_bad_option;
2711 }
2712 return 0;
2912 2713
2913 rc = 0;
2914out_free_opts:
2915 security_free_mnt_opts(&opts);
2916out_free_secdata:
2917 free_secdata(secdata);
2918 return rc;
2919out_bad_option: 2714out_bad_option:
2920 pr_warn("SELinux: unable to change security options " 2715 pr_warn("SELinux: unable to change security options "
2921 "during remount (dev %s, type=%s)\n", sb->s_id, 2716 "during remount (dev %s, type=%s)\n", sb->s_id,
2922 sb->s_type->name); 2717 sb->s_type->name);
2923 goto out_free_opts; 2718 return -EINVAL;
2924} 2719}
2925 2720
2926static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) 2721static int selinux_sb_kern_mount(struct super_block *sb)
2927{ 2722{
2928 const struct cred *cred = current_cred(); 2723 const struct cred *cred = current_cred();
2929 struct common_audit_data ad; 2724 struct common_audit_data ad;
2930 int rc;
2931
2932 rc = superblock_doinit(sb, data);
2933 if (rc)
2934 return rc;
2935
2936 /* Allow all mounts performed by the kernel */
2937 if (flags & (MS_KERNMOUNT | MS_SUBMOUNT))
2938 return 0;
2939 2725
2940 ad.type = LSM_AUDIT_DATA_DENTRY; 2726 ad.type = LSM_AUDIT_DATA_DENTRY;
2941 ad.u.dentry = sb->s_root; 2727 ad.u.dentry = sb->s_root;
@@ -6926,7 +6712,8 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
6926 6712
6927 LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security), 6713 LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
6928 LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security), 6714 LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
6929 LSM_HOOK_INIT(sb_copy_data, selinux_sb_copy_data), 6715 LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts),
6716 LSM_HOOK_INIT(sb_free_mnt_opts, selinux_free_mnt_opts),
6930 LSM_HOOK_INIT(sb_remount, selinux_sb_remount), 6717 LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
6931 LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount), 6718 LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
6932 LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options), 6719 LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options),
@@ -6935,7 +6722,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
6935 LSM_HOOK_INIT(sb_umount, selinux_umount), 6722 LSM_HOOK_INIT(sb_umount, selinux_umount),
6936 LSM_HOOK_INIT(sb_set_mnt_opts, selinux_set_mnt_opts), 6723 LSM_HOOK_INIT(sb_set_mnt_opts, selinux_set_mnt_opts),
6937 LSM_HOOK_INIT(sb_clone_mnt_opts, selinux_sb_clone_mnt_opts), 6724 LSM_HOOK_INIT(sb_clone_mnt_opts, selinux_sb_clone_mnt_opts),
6938 LSM_HOOK_INIT(sb_parse_opts_str, selinux_parse_opts_str), 6725 LSM_HOOK_INIT(sb_add_mnt_opt, selinux_add_mnt_opt),
6939 6726
6940 LSM_HOOK_INIT(dentry_init_security, selinux_dentry_init_security), 6727 LSM_HOOK_INIT(dentry_init_security, selinux_dentry_init_security),
6941 LSM_HOOK_INIT(dentry_create_files_as, selinux_dentry_create_files_as), 6728 LSM_HOOK_INIT(dentry_create_files_as, selinux_dentry_create_files_as),
@@ -7196,7 +6983,7 @@ static __init int selinux_init(void)
7196 6983
7197static void delayed_superblock_init(struct super_block *sb, void *unused) 6984static void delayed_superblock_init(struct super_block *sb, void *unused)
7198{ 6985{
7199 superblock_doinit(sb, NULL); 6986 selinux_set_mnt_opts(sb, NULL, 0, NULL);
7200} 6987}
7201 6988
7202void selinux_complete_init(void) 6989void selinux_complete_init(void)