diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-01-05 16:25:58 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-01-05 16:25:58 -0500 |
commit | 505b050fdf42097883b2d37b8e796e1f11dbef50 (patch) | |
tree | 21f5b43505a5771d13533ac675c785a9bf480fdc /security/selinux | |
parent | 9b286efeb5eb5aaa2712873fc1f928b2f879dbde (diff) | |
parent | 718c43038f287e843c2f63d946977de90014cb11 (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.c | 799 |
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 | ||
436 | struct selinux_mnt_opts { | ||
437 | const char *fscontext, *context, *rootcontext, *defcontext; | ||
438 | }; | ||
439 | |||
440 | static 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 | |||
435 | static inline int inode_doinit(struct inode *inode) | 450 | static 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 | 465 | static struct { | |
452 | static 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 | |||
479 | static 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); |
573 | next_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); |
591 | out: | 626 | out: |
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 | */ | ||
600 | static 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 | |||
689 | out_free: | ||
690 | security_free_mnt_opts(opts); | ||
691 | return rc; | ||
692 | } | ||
693 | |||
694 | static int bad_option(struct superblock_security_struct *sbsec, char flag, | 630 | static 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 | ||
650 | static 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 | */ |
718 | static int selinux_set_mnt_opts(struct super_block *sb, | 665 | static 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: | |||
969 | out_double_mount: | 893 | out_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 | ||
1084 | static int selinux_parse_opts_str(char *options, | 1009 | static 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 | 1047 | Einval: | |
1196 | out_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 | */ | ||
1207 | static 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); | 1052 | static 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 | ||
1224 | out: | 1065 | if (token == Opt_error) |
1225 | rc = selinux_set_mnt_opts(sb, &opts, 0, NULL); | 1066 | return -EINVAL; |
1226 | 1067 | ||
1227 | out_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 | ||
1232 | static void selinux_write_opts(struct seq_file *m, | 1081 | static 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 | ||
1278 | static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb) | 1102 | static 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 | ||
1298 | static inline u16 inode_mode_to_security_class(umode_t mode) | 1150 | static 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 | ||
2750 | static inline int match_prefix(char *prefix, int plen, char *option, int olen) | 2602 | static 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 | |||
2758 | static 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 | ||
2767 | static 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 | |||
2778 | static 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 | ||
2799 | static int selinux_sb_copy_data(char *orig, char *copy) | 2617 | static 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 | } |
2837 | out: | 2665 | *to = '\0'; |
2838 | return rc; | 2666 | return 0; |
2839 | } | 2667 | } |
2840 | 2668 | ||
2841 | static int selinux_sb_remount(struct super_block *sb, void *data) | 2669 | static 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; | ||
2914 | out_free_opts: | ||
2915 | security_free_mnt_opts(&opts); | ||
2916 | out_free_secdata: | ||
2917 | free_secdata(secdata); | ||
2918 | return rc; | ||
2919 | out_bad_option: | 2714 | out_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 | ||
2926 | static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | 2721 | static 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 | ||
7197 | static void delayed_superblock_init(struct super_block *sb, void *unused) | 6984 | static 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 | ||
7202 | void selinux_complete_init(void) | 6989 | void selinux_complete_init(void) |