diff options
Diffstat (limited to 'security/selinux')
-rw-r--r-- | security/selinux/hooks.c | 244 | ||||
-rw-r--r-- | security/selinux/include/audit.h | 4 | ||||
-rw-r--r-- | security/selinux/include/avc.h | 15 | ||||
-rw-r--r-- | security/selinux/include/objsec.h | 1 | ||||
-rw-r--r-- | security/selinux/include/security.h | 7 | ||||
-rw-r--r-- | security/selinux/netnode.c | 1 | ||||
-rw-r--r-- | security/selinux/netport.c | 3 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 15 | ||||
-rw-r--r-- | security/selinux/ss/avtab.c | 2 | ||||
-rw-r--r-- | security/selinux/ss/context.h | 27 | ||||
-rw-r--r-- | security/selinux/ss/mls.c | 19 | ||||
-rw-r--r-- | security/selinux/ss/mls.h | 3 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 15 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 450 | ||||
-rw-r--r-- | security/selinux/ss/sidtab.c | 76 | ||||
-rw-r--r-- | security/selinux/ss/sidtab.h | 7 |
16 files changed, 530 insertions, 359 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 1c864c0efe2b..91200feb3f9c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -9,7 +9,8 @@ | |||
9 | * James Morris <jmorris@redhat.com> | 9 | * James Morris <jmorris@redhat.com> |
10 | * | 10 | * |
11 | * Copyright (C) 2001,2002 Networks Associates Technology, Inc. | 11 | * Copyright (C) 2001,2002 Networks Associates Technology, Inc. |
12 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> | 12 | * Copyright (C) 2003-2008 Red Hat, Inc., James Morris <jmorris@redhat.com> |
13 | * Eric Paris <eparis@redhat.com> | ||
13 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. | 14 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. |
14 | * <dgoeddel@trustedcs.com> | 15 | * <dgoeddel@trustedcs.com> |
15 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. | 16 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. |
@@ -42,9 +43,7 @@ | |||
42 | #include <linux/fdtable.h> | 43 | #include <linux/fdtable.h> |
43 | #include <linux/namei.h> | 44 | #include <linux/namei.h> |
44 | #include <linux/mount.h> | 45 | #include <linux/mount.h> |
45 | #include <linux/ext2_fs.h> | ||
46 | #include <linux/proc_fs.h> | 46 | #include <linux/proc_fs.h> |
47 | #include <linux/kd.h> | ||
48 | #include <linux/netfilter_ipv4.h> | 47 | #include <linux/netfilter_ipv4.h> |
49 | #include <linux/netfilter_ipv6.h> | 48 | #include <linux/netfilter_ipv6.h> |
50 | #include <linux/tty.h> | 49 | #include <linux/tty.h> |
@@ -53,7 +52,7 @@ | |||
53 | #include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */ | 52 | #include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */ |
54 | #include <net/net_namespace.h> | 53 | #include <net/net_namespace.h> |
55 | #include <net/netlabel.h> | 54 | #include <net/netlabel.h> |
56 | #include <asm/uaccess.h> | 55 | #include <linux/uaccess.h> |
57 | #include <asm/ioctls.h> | 56 | #include <asm/ioctls.h> |
58 | #include <asm/atomic.h> | 57 | #include <asm/atomic.h> |
59 | #include <linux/bitops.h> | 58 | #include <linux/bitops.h> |
@@ -104,7 +103,9 @@ int selinux_enforcing; | |||
104 | 103 | ||
105 | static int __init enforcing_setup(char *str) | 104 | static int __init enforcing_setup(char *str) |
106 | { | 105 | { |
107 | selinux_enforcing = simple_strtol(str, NULL, 0); | 106 | unsigned long enforcing; |
107 | if (!strict_strtoul(str, 0, &enforcing)) | ||
108 | selinux_enforcing = enforcing ? 1 : 0; | ||
108 | return 1; | 109 | return 1; |
109 | } | 110 | } |
110 | __setup("enforcing=", enforcing_setup); | 111 | __setup("enforcing=", enforcing_setup); |
@@ -115,7 +116,9 @@ int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE; | |||
115 | 116 | ||
116 | static int __init selinux_enabled_setup(char *str) | 117 | static int __init selinux_enabled_setup(char *str) |
117 | { | 118 | { |
118 | selinux_enabled = simple_strtol(str, NULL, 0); | 119 | unsigned long enabled; |
120 | if (!strict_strtoul(str, 0, &enabled)) | ||
121 | selinux_enabled = enabled ? 1 : 0; | ||
119 | return 1; | 122 | return 1; |
120 | } | 123 | } |
121 | __setup("selinux=", selinux_enabled_setup); | 124 | __setup("selinux=", selinux_enabled_setup); |
@@ -123,13 +126,11 @@ __setup("selinux=", selinux_enabled_setup); | |||
123 | int selinux_enabled = 1; | 126 | int selinux_enabled = 1; |
124 | #endif | 127 | #endif |
125 | 128 | ||
126 | /* Original (dummy) security module. */ | ||
127 | static struct security_operations *original_ops; | ||
128 | 129 | ||
129 | /* Minimal support for a secondary security module, | 130 | /* |
130 | just to allow the use of the dummy or capability modules. | 131 | * Minimal support for a secondary security module, |
131 | The owlsm module can alternatively be used as a secondary | 132 | * just to allow the use of the capability module. |
132 | module as long as CONFIG_OWLSM_FD is not enabled. */ | 133 | */ |
133 | static struct security_operations *secondary_ops; | 134 | static struct security_operations *secondary_ops; |
134 | 135 | ||
135 | /* Lists of inode and superblock security structures initialized | 136 | /* Lists of inode and superblock security structures initialized |
@@ -554,13 +555,15 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
554 | struct task_security_struct *tsec = current->security; | 555 | struct task_security_struct *tsec = current->security; |
555 | struct superblock_security_struct *sbsec = sb->s_security; | 556 | struct superblock_security_struct *sbsec = sb->s_security; |
556 | const char *name = sb->s_type->name; | 557 | const char *name = sb->s_type->name; |
557 | struct inode *inode = sbsec->sb->s_root->d_inode; | 558 | struct dentry *root = sb->s_root; |
558 | struct inode_security_struct *root_isec = inode->i_security; | 559 | struct inode *root_inode = root->d_inode; |
560 | struct inode_security_struct *root_isec = root_inode->i_security; | ||
559 | u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; | 561 | u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; |
560 | u32 defcontext_sid = 0; | 562 | u32 defcontext_sid = 0; |
561 | char **mount_options = opts->mnt_opts; | 563 | char **mount_options = opts->mnt_opts; |
562 | int *flags = opts->mnt_opts_flags; | 564 | int *flags = opts->mnt_opts_flags; |
563 | int num_opts = opts->num_mnt_opts; | 565 | int num_opts = opts->num_mnt_opts; |
566 | bool can_xattr = false; | ||
564 | 567 | ||
565 | mutex_lock(&sbsec->lock); | 568 | mutex_lock(&sbsec->lock); |
566 | 569 | ||
@@ -594,7 +597,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
594 | */ | 597 | */ |
595 | if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) | 598 | if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) |
596 | && (num_opts == 0)) | 599 | && (num_opts == 0)) |
597 | goto out; | 600 | goto out; |
598 | 601 | ||
599 | /* | 602 | /* |
600 | * parse the mount options, check if they are valid sids. | 603 | * parse the mount options, check if they are valid sids. |
@@ -664,14 +667,24 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
664 | goto out; | 667 | goto out; |
665 | } | 668 | } |
666 | 669 | ||
667 | if (strcmp(sb->s_type->name, "proc") == 0) | 670 | if (strcmp(name, "proc") == 0) |
668 | sbsec->proc = 1; | 671 | sbsec->proc = 1; |
669 | 672 | ||
673 | /* | ||
674 | * test if the fs supports xattrs, fs_use might make use of this if the | ||
675 | * fs has no definition in policy. | ||
676 | */ | ||
677 | if (root_inode->i_op->getxattr) { | ||
678 | rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0); | ||
679 | if (rc >= 0 || rc == -ENODATA) | ||
680 | can_xattr = true; | ||
681 | } | ||
682 | |||
670 | /* Determine the labeling behavior to use for this filesystem type. */ | 683 | /* Determine the labeling behavior to use for this filesystem type. */ |
671 | rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid); | 684 | rc = security_fs_use(name, &sbsec->behavior, &sbsec->sid, can_xattr); |
672 | if (rc) { | 685 | if (rc) { |
673 | printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", | 686 | printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", |
674 | __func__, sb->s_type->name, rc); | 687 | __func__, name, rc); |
675 | goto out; | 688 | goto out; |
676 | } | 689 | } |
677 | 690 | ||
@@ -956,6 +969,57 @@ out_err: | |||
956 | return rc; | 969 | return rc; |
957 | } | 970 | } |
958 | 971 | ||
972 | void selinux_write_opts(struct seq_file *m, struct security_mnt_opts *opts) | ||
973 | { | ||
974 | int i; | ||
975 | char *prefix; | ||
976 | |||
977 | for (i = 0; i < opts->num_mnt_opts; i++) { | ||
978 | char *has_comma = strchr(opts->mnt_opts[i], ','); | ||
979 | |||
980 | switch (opts->mnt_opts_flags[i]) { | ||
981 | case CONTEXT_MNT: | ||
982 | prefix = CONTEXT_STR; | ||
983 | break; | ||
984 | case FSCONTEXT_MNT: | ||
985 | prefix = FSCONTEXT_STR; | ||
986 | break; | ||
987 | case ROOTCONTEXT_MNT: | ||
988 | prefix = ROOTCONTEXT_STR; | ||
989 | break; | ||
990 | case DEFCONTEXT_MNT: | ||
991 | prefix = DEFCONTEXT_STR; | ||
992 | break; | ||
993 | default: | ||
994 | BUG(); | ||
995 | }; | ||
996 | /* we need a comma before each option */ | ||
997 | seq_putc(m, ','); | ||
998 | seq_puts(m, prefix); | ||
999 | if (has_comma) | ||
1000 | seq_putc(m, '\"'); | ||
1001 | seq_puts(m, opts->mnt_opts[i]); | ||
1002 | if (has_comma) | ||
1003 | seq_putc(m, '\"'); | ||
1004 | } | ||
1005 | } | ||
1006 | |||
1007 | static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb) | ||
1008 | { | ||
1009 | struct security_mnt_opts opts; | ||
1010 | int rc; | ||
1011 | |||
1012 | rc = selinux_get_mnt_opts(sb, &opts); | ||
1013 | if (rc) | ||
1014 | return rc; | ||
1015 | |||
1016 | selinux_write_opts(m, &opts); | ||
1017 | |||
1018 | security_free_mnt_opts(&opts); | ||
1019 | |||
1020 | return rc; | ||
1021 | } | ||
1022 | |||
959 | static inline u16 inode_mode_to_security_class(umode_t mode) | 1023 | static inline u16 inode_mode_to_security_class(umode_t mode) |
960 | { | 1024 | { |
961 | switch (mode & S_IFMT) { | 1025 | switch (mode & S_IFMT) { |
@@ -1682,14 +1746,23 @@ static inline u32 file_to_av(struct file *file) | |||
1682 | 1746 | ||
1683 | /* Hook functions begin here. */ | 1747 | /* Hook functions begin here. */ |
1684 | 1748 | ||
1685 | static int selinux_ptrace(struct task_struct *parent, struct task_struct *child) | 1749 | static int selinux_ptrace(struct task_struct *parent, |
1750 | struct task_struct *child, | ||
1751 | unsigned int mode) | ||
1686 | { | 1752 | { |
1687 | int rc; | 1753 | int rc; |
1688 | 1754 | ||
1689 | rc = secondary_ops->ptrace(parent, child); | 1755 | rc = secondary_ops->ptrace(parent, child, mode); |
1690 | if (rc) | 1756 | if (rc) |
1691 | return rc; | 1757 | return rc; |
1692 | 1758 | ||
1759 | if (mode == PTRACE_MODE_READ) { | ||
1760 | struct task_security_struct *tsec = parent->security; | ||
1761 | struct task_security_struct *csec = child->security; | ||
1762 | return avc_has_perm(tsec->sid, csec->sid, | ||
1763 | SECCLASS_FILE, FILE__READ, NULL); | ||
1764 | } | ||
1765 | |||
1693 | return task_has_perm(parent, child, PROCESS__PTRACE); | 1766 | return task_has_perm(parent, child, PROCESS__PTRACE); |
1694 | } | 1767 | } |
1695 | 1768 | ||
@@ -2495,7 +2568,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
2495 | } | 2568 | } |
2496 | 2569 | ||
2497 | if (value && len) { | 2570 | if (value && len) { |
2498 | rc = security_sid_to_context(newsid, &context, &clen); | 2571 | rc = security_sid_to_context_force(newsid, &context, &clen); |
2499 | if (rc) { | 2572 | if (rc) { |
2500 | kfree(namep); | 2573 | kfree(namep); |
2501 | return rc; | 2574 | return rc; |
@@ -2669,6 +2742,11 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
2669 | return rc; | 2742 | return rc; |
2670 | 2743 | ||
2671 | rc = security_context_to_sid(value, size, &newsid); | 2744 | rc = security_context_to_sid(value, size, &newsid); |
2745 | if (rc == -EINVAL) { | ||
2746 | if (!capable(CAP_MAC_ADMIN)) | ||
2747 | return rc; | ||
2748 | rc = security_context_to_sid_force(value, size, &newsid); | ||
2749 | } | ||
2672 | if (rc) | 2750 | if (rc) |
2673 | return rc; | 2751 | return rc; |
2674 | 2752 | ||
@@ -2690,7 +2768,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
2690 | } | 2768 | } |
2691 | 2769 | ||
2692 | static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, | 2770 | static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, |
2693 | const void *value, size_t size, | 2771 | const void *value, size_t size, |
2694 | int flags) | 2772 | int flags) |
2695 | { | 2773 | { |
2696 | struct inode *inode = dentry->d_inode; | 2774 | struct inode *inode = dentry->d_inode; |
@@ -2703,10 +2781,11 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, | |||
2703 | return; | 2781 | return; |
2704 | } | 2782 | } |
2705 | 2783 | ||
2706 | rc = security_context_to_sid(value, size, &newsid); | 2784 | rc = security_context_to_sid_force(value, size, &newsid); |
2707 | if (rc) { | 2785 | if (rc) { |
2708 | printk(KERN_WARNING "%s: unable to obtain SID for context " | 2786 | printk(KERN_ERR "SELinux: unable to map context to SID" |
2709 | "%s, rc=%d\n", __func__, (char *)value, -rc); | 2787 | "for (%s, %lu), rc=%d\n", |
2788 | inode->i_sb->s_id, inode->i_ino, -rc); | ||
2710 | return; | 2789 | return; |
2711 | } | 2790 | } |
2712 | 2791 | ||
@@ -2735,9 +2814,7 @@ static int selinux_inode_removexattr(struct dentry *dentry, const char *name) | |||
2735 | } | 2814 | } |
2736 | 2815 | ||
2737 | /* | 2816 | /* |
2738 | * Copy the in-core inode security context value to the user. If the | 2817 | * Copy the inode security context value to the user. |
2739 | * getxattr() prior to this succeeded, check to see if we need to | ||
2740 | * canonicalize the value to be finally returned to the user. | ||
2741 | * | 2818 | * |
2742 | * Permission check is handled by selinux_inode_getxattr hook. | 2819 | * Permission check is handled by selinux_inode_getxattr hook. |
2743 | */ | 2820 | */ |
@@ -2746,12 +2823,33 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name | |||
2746 | u32 size; | 2823 | u32 size; |
2747 | int error; | 2824 | int error; |
2748 | char *context = NULL; | 2825 | char *context = NULL; |
2826 | struct task_security_struct *tsec = current->security; | ||
2749 | struct inode_security_struct *isec = inode->i_security; | 2827 | struct inode_security_struct *isec = inode->i_security; |
2750 | 2828 | ||
2751 | if (strcmp(name, XATTR_SELINUX_SUFFIX)) | 2829 | if (strcmp(name, XATTR_SELINUX_SUFFIX)) |
2752 | return -EOPNOTSUPP; | 2830 | return -EOPNOTSUPP; |
2753 | 2831 | ||
2754 | error = security_sid_to_context(isec->sid, &context, &size); | 2832 | /* |
2833 | * If the caller has CAP_MAC_ADMIN, then get the raw context | ||
2834 | * value even if it is not defined by current policy; otherwise, | ||
2835 | * use the in-core value under current policy. | ||
2836 | * Use the non-auditing forms of the permission checks since | ||
2837 | * getxattr may be called by unprivileged processes commonly | ||
2838 | * and lack of permission just means that we fall back to the | ||
2839 | * in-core context value, not a denial. | ||
2840 | */ | ||
2841 | error = secondary_ops->capable(current, CAP_MAC_ADMIN); | ||
2842 | if (!error) | ||
2843 | error = avc_has_perm_noaudit(tsec->sid, tsec->sid, | ||
2844 | SECCLASS_CAPABILITY2, | ||
2845 | CAPABILITY2__MAC_ADMIN, | ||
2846 | 0, | ||
2847 | NULL); | ||
2848 | if (!error) | ||
2849 | error = security_sid_to_context_force(isec->sid, &context, | ||
2850 | &size); | ||
2851 | else | ||
2852 | error = security_sid_to_context(isec->sid, &context, &size); | ||
2755 | if (error) | 2853 | if (error) |
2756 | return error; | 2854 | return error; |
2757 | error = size; | 2855 | error = size; |
@@ -2865,46 +2963,16 @@ static void selinux_file_free_security(struct file *file) | |||
2865 | static int selinux_file_ioctl(struct file *file, unsigned int cmd, | 2963 | static int selinux_file_ioctl(struct file *file, unsigned int cmd, |
2866 | unsigned long arg) | 2964 | unsigned long arg) |
2867 | { | 2965 | { |
2868 | int error = 0; | 2966 | u32 av = 0; |
2869 | |||
2870 | switch (cmd) { | ||
2871 | case FIONREAD: | ||
2872 | /* fall through */ | ||
2873 | case FIBMAP: | ||
2874 | /* fall through */ | ||
2875 | case FIGETBSZ: | ||
2876 | /* fall through */ | ||
2877 | case EXT2_IOC_GETFLAGS: | ||
2878 | /* fall through */ | ||
2879 | case EXT2_IOC_GETVERSION: | ||
2880 | error = file_has_perm(current, file, FILE__GETATTR); | ||
2881 | break; | ||
2882 | |||
2883 | case EXT2_IOC_SETFLAGS: | ||
2884 | /* fall through */ | ||
2885 | case EXT2_IOC_SETVERSION: | ||
2886 | error = file_has_perm(current, file, FILE__SETATTR); | ||
2887 | break; | ||
2888 | |||
2889 | /* sys_ioctl() checks */ | ||
2890 | case FIONBIO: | ||
2891 | /* fall through */ | ||
2892 | case FIOASYNC: | ||
2893 | error = file_has_perm(current, file, 0); | ||
2894 | break; | ||
2895 | 2967 | ||
2896 | case KDSKBENT: | 2968 | if (_IOC_DIR(cmd) & _IOC_WRITE) |
2897 | case KDSKBSENT: | 2969 | av |= FILE__WRITE; |
2898 | error = task_has_capability(current, CAP_SYS_TTY_CONFIG); | 2970 | if (_IOC_DIR(cmd) & _IOC_READ) |
2899 | break; | 2971 | av |= FILE__READ; |
2972 | if (!av) | ||
2973 | av = FILE__IOCTL; | ||
2900 | 2974 | ||
2901 | /* default case assumes that the command will go | 2975 | return file_has_perm(current, file, av); |
2902 | * to the file's ioctl() function. | ||
2903 | */ | ||
2904 | default: | ||
2905 | error = file_has_perm(current, file, FILE__IOCTL); | ||
2906 | } | ||
2907 | return error; | ||
2908 | } | 2976 | } |
2909 | 2977 | ||
2910 | static int file_map_prot_check(struct file *file, unsigned long prot, int shared) | 2978 | static int file_map_prot_check(struct file *file, unsigned long prot, int shared) |
@@ -3663,7 +3731,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
3663 | struct sockaddr_in6 *addr6 = NULL; | 3731 | struct sockaddr_in6 *addr6 = NULL; |
3664 | unsigned short snum; | 3732 | unsigned short snum; |
3665 | struct sock *sk = sock->sk; | 3733 | struct sock *sk = sock->sk; |
3666 | u32 sid, node_perm, addrlen; | 3734 | u32 sid, node_perm; |
3667 | 3735 | ||
3668 | tsec = current->security; | 3736 | tsec = current->security; |
3669 | isec = SOCK_INODE(sock)->i_security; | 3737 | isec = SOCK_INODE(sock)->i_security; |
@@ -3671,12 +3739,10 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
3671 | if (family == PF_INET) { | 3739 | if (family == PF_INET) { |
3672 | addr4 = (struct sockaddr_in *)address; | 3740 | addr4 = (struct sockaddr_in *)address; |
3673 | snum = ntohs(addr4->sin_port); | 3741 | snum = ntohs(addr4->sin_port); |
3674 | addrlen = sizeof(addr4->sin_addr.s_addr); | ||
3675 | addrp = (char *)&addr4->sin_addr.s_addr; | 3742 | addrp = (char *)&addr4->sin_addr.s_addr; |
3676 | } else { | 3743 | } else { |
3677 | addr6 = (struct sockaddr_in6 *)address; | 3744 | addr6 = (struct sockaddr_in6 *)address; |
3678 | snum = ntohs(addr6->sin6_port); | 3745 | snum = ntohs(addr6->sin6_port); |
3679 | addrlen = sizeof(addr6->sin6_addr.s6_addr); | ||
3680 | addrp = (char *)&addr6->sin6_addr.s6_addr; | 3746 | addrp = (char *)&addr6->sin6_addr.s6_addr; |
3681 | } | 3747 | } |
3682 | 3748 | ||
@@ -5047,24 +5113,6 @@ static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) | |||
5047 | *secid = isec->sid; | 5113 | *secid = isec->sid; |
5048 | } | 5114 | } |
5049 | 5115 | ||
5050 | /* module stacking operations */ | ||
5051 | static int selinux_register_security(const char *name, struct security_operations *ops) | ||
5052 | { | ||
5053 | if (secondary_ops != original_ops) { | ||
5054 | printk(KERN_ERR "%s: There is already a secondary security " | ||
5055 | "module registered.\n", __func__); | ||
5056 | return -EINVAL; | ||
5057 | } | ||
5058 | |||
5059 | secondary_ops = ops; | ||
5060 | |||
5061 | printk(KERN_INFO "%s: Registering secondary module %s\n", | ||
5062 | __func__, | ||
5063 | name); | ||
5064 | |||
5065 | return 0; | ||
5066 | } | ||
5067 | |||
5068 | static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode) | 5116 | static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode) |
5069 | { | 5117 | { |
5070 | if (inode) | 5118 | if (inode) |
@@ -5153,6 +5201,12 @@ static int selinux_setprocattr(struct task_struct *p, | |||
5153 | size--; | 5201 | size--; |
5154 | } | 5202 | } |
5155 | error = security_context_to_sid(value, size, &sid); | 5203 | error = security_context_to_sid(value, size, &sid); |
5204 | if (error == -EINVAL && !strcmp(name, "fscreate")) { | ||
5205 | if (!capable(CAP_MAC_ADMIN)) | ||
5206 | return error; | ||
5207 | error = security_context_to_sid_force(value, size, | ||
5208 | &sid); | ||
5209 | } | ||
5156 | if (error) | 5210 | if (error) |
5157 | return error; | 5211 | return error; |
5158 | } | 5212 | } |
@@ -5186,12 +5240,12 @@ static int selinux_setprocattr(struct task_struct *p, | |||
5186 | struct task_struct *g, *t; | 5240 | struct task_struct *g, *t; |
5187 | struct mm_struct *mm = p->mm; | 5241 | struct mm_struct *mm = p->mm; |
5188 | read_lock(&tasklist_lock); | 5242 | read_lock(&tasklist_lock); |
5189 | do_each_thread(g, t) | 5243 | do_each_thread(g, t) { |
5190 | if (t->mm == mm && t != p) { | 5244 | if (t->mm == mm && t != p) { |
5191 | read_unlock(&tasklist_lock); | 5245 | read_unlock(&tasklist_lock); |
5192 | return -EPERM; | 5246 | return -EPERM; |
5193 | } | 5247 | } |
5194 | while_each_thread(g, t); | 5248 | } while_each_thread(g, t); |
5195 | read_unlock(&tasklist_lock); | 5249 | read_unlock(&tasklist_lock); |
5196 | } | 5250 | } |
5197 | 5251 | ||
@@ -5343,10 +5397,10 @@ static struct security_operations selinux_ops = { | |||
5343 | .sb_free_security = selinux_sb_free_security, | 5397 | .sb_free_security = selinux_sb_free_security, |
5344 | .sb_copy_data = selinux_sb_copy_data, | 5398 | .sb_copy_data = selinux_sb_copy_data, |
5345 | .sb_kern_mount = selinux_sb_kern_mount, | 5399 | .sb_kern_mount = selinux_sb_kern_mount, |
5400 | .sb_show_options = selinux_sb_show_options, | ||
5346 | .sb_statfs = selinux_sb_statfs, | 5401 | .sb_statfs = selinux_sb_statfs, |
5347 | .sb_mount = selinux_mount, | 5402 | .sb_mount = selinux_mount, |
5348 | .sb_umount = selinux_umount, | 5403 | .sb_umount = selinux_umount, |
5349 | .sb_get_mnt_opts = selinux_get_mnt_opts, | ||
5350 | .sb_set_mnt_opts = selinux_set_mnt_opts, | 5404 | .sb_set_mnt_opts = selinux_set_mnt_opts, |
5351 | .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts, | 5405 | .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts, |
5352 | .sb_parse_opts_str = selinux_parse_opts_str, | 5406 | .sb_parse_opts_str = selinux_parse_opts_str, |
@@ -5378,7 +5432,7 @@ static struct security_operations selinux_ops = { | |||
5378 | .inode_listsecurity = selinux_inode_listsecurity, | 5432 | .inode_listsecurity = selinux_inode_listsecurity, |
5379 | .inode_need_killpriv = selinux_inode_need_killpriv, | 5433 | .inode_need_killpriv = selinux_inode_need_killpriv, |
5380 | .inode_killpriv = selinux_inode_killpriv, | 5434 | .inode_killpriv = selinux_inode_killpriv, |
5381 | .inode_getsecid = selinux_inode_getsecid, | 5435 | .inode_getsecid = selinux_inode_getsecid, |
5382 | 5436 | ||
5383 | .file_permission = selinux_file_permission, | 5437 | .file_permission = selinux_file_permission, |
5384 | .file_alloc_security = selinux_file_alloc_security, | 5438 | .file_alloc_security = selinux_file_alloc_security, |
@@ -5419,7 +5473,7 @@ static struct security_operations selinux_ops = { | |||
5419 | .task_to_inode = selinux_task_to_inode, | 5473 | .task_to_inode = selinux_task_to_inode, |
5420 | 5474 | ||
5421 | .ipc_permission = selinux_ipc_permission, | 5475 | .ipc_permission = selinux_ipc_permission, |
5422 | .ipc_getsecid = selinux_ipc_getsecid, | 5476 | .ipc_getsecid = selinux_ipc_getsecid, |
5423 | 5477 | ||
5424 | .msg_msg_alloc_security = selinux_msg_msg_alloc_security, | 5478 | .msg_msg_alloc_security = selinux_msg_msg_alloc_security, |
5425 | .msg_msg_free_security = selinux_msg_msg_free_security, | 5479 | .msg_msg_free_security = selinux_msg_msg_free_security, |
@@ -5443,8 +5497,6 @@ static struct security_operations selinux_ops = { | |||
5443 | .sem_semctl = selinux_sem_semctl, | 5497 | .sem_semctl = selinux_sem_semctl, |
5444 | .sem_semop = selinux_sem_semop, | 5498 | .sem_semop = selinux_sem_semop, |
5445 | 5499 | ||
5446 | .register_security = selinux_register_security, | ||
5447 | |||
5448 | .d_instantiate = selinux_d_instantiate, | 5500 | .d_instantiate = selinux_d_instantiate, |
5449 | 5501 | ||
5450 | .getprocattr = selinux_getprocattr, | 5502 | .getprocattr = selinux_getprocattr, |
@@ -5538,7 +5590,7 @@ static __init int selinux_init(void) | |||
5538 | 0, SLAB_PANIC, NULL); | 5590 | 0, SLAB_PANIC, NULL); |
5539 | avc_init(); | 5591 | avc_init(); |
5540 | 5592 | ||
5541 | original_ops = secondary_ops = security_ops; | 5593 | secondary_ops = security_ops; |
5542 | if (!secondary_ops) | 5594 | if (!secondary_ops) |
5543 | panic("SELinux: No initial security operations\n"); | 5595 | panic("SELinux: No initial security operations\n"); |
5544 | if (register_security(&selinux_ops)) | 5596 | if (register_security(&selinux_ops)) |
diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h index 6c8b9ef15579..1bdf973433cc 100644 --- a/security/selinux/include/audit.h +++ b/security/selinux/include/audit.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * SELinux support for the Audit LSM hooks | 2 | * SELinux support for the Audit LSM hooks |
3 | * | 3 | * |
4 | * Most of below header was moved from include/linux/selinux.h which | 4 | * Most of below header was moved from include/linux/selinux.h which |
5 | * is released under below copyrights: | 5 | * is released under below copyrights: |
6 | * | 6 | * |
7 | * Author: James Morris <jmorris@redhat.com> | 7 | * Author: James Morris <jmorris@redhat.com> |
@@ -52,7 +52,7 @@ void selinux_audit_rule_free(void *rule); | |||
52 | * -errno on failure. | 52 | * -errno on failure. |
53 | */ | 53 | */ |
54 | int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule, | 54 | int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule, |
55 | struct audit_context *actx); | 55 | struct audit_context *actx); |
56 | 56 | ||
57 | /** | 57 | /** |
58 | * selinux_audit_rule_known - check to see if rule contains selinux fields. | 58 | * selinux_audit_rule_known - check to see if rule contains selinux fields. |
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 8e23d7a873a4..7b9769f5e775 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h | |||
@@ -75,13 +75,12 @@ struct avc_audit_data { | |||
75 | 75 | ||
76 | /* Initialize an AVC audit data structure. */ | 76 | /* Initialize an AVC audit data structure. */ |
77 | #define AVC_AUDIT_DATA_INIT(_d,_t) \ | 77 | #define AVC_AUDIT_DATA_INIT(_d,_t) \ |
78 | { memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; } | 78 | { memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; } |
79 | 79 | ||
80 | /* | 80 | /* |
81 | * AVC statistics | 81 | * AVC statistics |
82 | */ | 82 | */ |
83 | struct avc_cache_stats | 83 | struct avc_cache_stats { |
84 | { | ||
85 | unsigned int lookups; | 84 | unsigned int lookups; |
86 | unsigned int hits; | 85 | unsigned int hits; |
87 | unsigned int misses; | 86 | unsigned int misses; |
@@ -97,8 +96,8 @@ struct avc_cache_stats | |||
97 | void __init avc_init(void); | 96 | void __init avc_init(void); |
98 | 97 | ||
99 | void avc_audit(u32 ssid, u32 tsid, | 98 | void avc_audit(u32 ssid, u32 tsid, |
100 | u16 tclass, u32 requested, | 99 | u16 tclass, u32 requested, |
101 | struct av_decision *avd, int result, struct avc_audit_data *auditdata); | 100 | struct av_decision *avd, int result, struct avc_audit_data *auditdata); |
102 | 101 | ||
103 | #define AVC_STRICT 1 /* Ignore permissive mode. */ | 102 | #define AVC_STRICT 1 /* Ignore permissive mode. */ |
104 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, | 103 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, |
@@ -107,8 +106,8 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
107 | struct av_decision *avd); | 106 | struct av_decision *avd); |
108 | 107 | ||
109 | int avc_has_perm(u32 ssid, u32 tsid, | 108 | int avc_has_perm(u32 ssid, u32 tsid, |
110 | u16 tclass, u32 requested, | 109 | u16 tclass, u32 requested, |
111 | struct avc_audit_data *auditdata); | 110 | struct avc_audit_data *auditdata); |
112 | 111 | ||
113 | u32 avc_policy_seqno(void); | 112 | u32 avc_policy_seqno(void); |
114 | 113 | ||
@@ -122,7 +121,7 @@ u32 avc_policy_seqno(void); | |||
122 | #define AVC_CALLBACK_AUDITDENY_DISABLE 128 | 121 | #define AVC_CALLBACK_AUDITDENY_DISABLE 128 |
123 | 122 | ||
124 | int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, | 123 | int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, |
125 | u16 tclass, u32 perms, | 124 | u16 tclass, u32 perms, |
126 | u32 *out_retained), | 125 | u32 *out_retained), |
127 | u32 events, u32 ssid, u32 tsid, | 126 | u32 events, u32 ssid, u32 tsid, |
128 | u16 tclass, u32 perms); | 127 | u16 tclass, u32 perms); |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 032c2357dad1..91070ab874ce 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -44,7 +44,6 @@ struct inode_security_struct { | |||
44 | u16 sclass; /* security class of this object */ | 44 | u16 sclass; /* security class of this object */ |
45 | unsigned char initialized; /* initialization flag */ | 45 | unsigned char initialized; /* initialization flag */ |
46 | struct mutex lock; | 46 | struct mutex lock; |
47 | unsigned char inherit; /* inherit SID from parent entry */ | ||
48 | }; | 47 | }; |
49 | 48 | ||
50 | struct file_security_struct { | 49 | struct file_security_struct { |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index ad30ac4273d6..44cba2e21dcf 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -93,12 +93,17 @@ int security_change_sid(u32 ssid, u32 tsid, | |||
93 | int security_sid_to_context(u32 sid, char **scontext, | 93 | int security_sid_to_context(u32 sid, char **scontext, |
94 | u32 *scontext_len); | 94 | u32 *scontext_len); |
95 | 95 | ||
96 | int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len); | ||
97 | |||
96 | int security_context_to_sid(const char *scontext, u32 scontext_len, | 98 | int security_context_to_sid(const char *scontext, u32 scontext_len, |
97 | u32 *out_sid); | 99 | u32 *out_sid); |
98 | 100 | ||
99 | int security_context_to_sid_default(const char *scontext, u32 scontext_len, | 101 | int security_context_to_sid_default(const char *scontext, u32 scontext_len, |
100 | u32 *out_sid, u32 def_sid, gfp_t gfp_flags); | 102 | u32 *out_sid, u32 def_sid, gfp_t gfp_flags); |
101 | 103 | ||
104 | int security_context_to_sid_force(const char *scontext, u32 scontext_len, | ||
105 | u32 *sid); | ||
106 | |||
102 | int security_get_user_sids(u32 callsid, char *username, | 107 | int security_get_user_sids(u32 callsid, char *username, |
103 | u32 **sids, u32 *nel); | 108 | u32 **sids, u32 *nel); |
104 | 109 | ||
@@ -131,7 +136,7 @@ int security_get_allow_unknown(void); | |||
131 | #define SECURITY_FS_USE_MNTPOINT 6 /* use mountpoint labeling */ | 136 | #define SECURITY_FS_USE_MNTPOINT 6 /* use mountpoint labeling */ |
132 | 137 | ||
133 | int security_fs_use(const char *fstype, unsigned int *behavior, | 138 | int security_fs_use(const char *fstype, unsigned int *behavior, |
134 | u32 *sid); | 139 | u32 *sid, bool can_xattr); |
135 | 140 | ||
136 | int security_genfs_sid(const char *fstype, char *name, u16 sclass, | 141 | int security_genfs_sid(const char *fstype, char *name, u16 sclass, |
137 | u32 *sid); | 142 | u32 *sid); |
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index b6ccd09379f1..7100072bb1b0 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #include <linux/ipv6.h> | 38 | #include <linux/ipv6.h> |
39 | #include <net/ip.h> | 39 | #include <net/ip.h> |
40 | #include <net/ipv6.h> | 40 | #include <net/ipv6.h> |
41 | #include <asm/bug.h> | ||
42 | 41 | ||
43 | #include "netnode.h" | 42 | #include "netnode.h" |
44 | #include "objsec.h" | 43 | #include "objsec.h" |
diff --git a/security/selinux/netport.c b/security/selinux/netport.c index 90b4cff7c350..fe7fba67f19f 100644 --- a/security/selinux/netport.c +++ b/security/selinux/netport.c | |||
@@ -37,7 +37,6 @@ | |||
37 | #include <linux/ipv6.h> | 37 | #include <linux/ipv6.h> |
38 | #include <net/ip.h> | 38 | #include <net/ip.h> |
39 | #include <net/ipv6.h> | 39 | #include <net/ipv6.h> |
40 | #include <asm/bug.h> | ||
41 | 40 | ||
42 | #include "netport.h" | 41 | #include "netport.h" |
43 | #include "objsec.h" | 42 | #include "objsec.h" |
@@ -272,7 +271,7 @@ static __init int sel_netport_init(void) | |||
272 | } | 271 | } |
273 | 272 | ||
274 | ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET, | 273 | ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET, |
275 | SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); | 274 | SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); |
276 | if (ret != 0) | 275 | if (ret != 0) |
277 | panic("avc_add_callback() failed, error %d\n", ret); | 276 | panic("avc_add_callback() failed, error %d\n", ret); |
278 | 277 | ||
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index ac1ccc13a704..69c9dccc8cf0 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include <linux/seq_file.h> | 27 | #include <linux/seq_file.h> |
28 | #include <linux/percpu.h> | 28 | #include <linux/percpu.h> |
29 | #include <linux/audit.h> | 29 | #include <linux/audit.h> |
30 | #include <asm/uaccess.h> | 30 | #include <linux/uaccess.h> |
31 | 31 | ||
32 | /* selinuxfs pseudo filesystem for exporting the security policy API. | 32 | /* selinuxfs pseudo filesystem for exporting the security policy API. |
33 | Based on the proc code and the fs/nfsd/nfsctl.c code. */ | 33 | Based on the proc code and the fs/nfsd/nfsctl.c code. */ |
@@ -57,14 +57,18 @@ int selinux_compat_net = SELINUX_COMPAT_NET_VALUE; | |||
57 | 57 | ||
58 | static int __init checkreqprot_setup(char *str) | 58 | static int __init checkreqprot_setup(char *str) |
59 | { | 59 | { |
60 | selinux_checkreqprot = simple_strtoul(str, NULL, 0) ? 1 : 0; | 60 | unsigned long checkreqprot; |
61 | if (!strict_strtoul(str, 0, &checkreqprot)) | ||
62 | selinux_checkreqprot = checkreqprot ? 1 : 0; | ||
61 | return 1; | 63 | return 1; |
62 | } | 64 | } |
63 | __setup("checkreqprot=", checkreqprot_setup); | 65 | __setup("checkreqprot=", checkreqprot_setup); |
64 | 66 | ||
65 | static int __init selinux_compat_net_setup(char *str) | 67 | static int __init selinux_compat_net_setup(char *str) |
66 | { | 68 | { |
67 | selinux_compat_net = simple_strtoul(str, NULL, 0) ? 1 : 0; | 69 | unsigned long compat_net; |
70 | if (!strict_strtoul(str, 0, &compat_net)) | ||
71 | selinux_compat_net = compat_net ? 1 : 0; | ||
68 | return 1; | 72 | return 1; |
69 | } | 73 | } |
70 | __setup("selinux_compat_net=", selinux_compat_net_setup); | 74 | __setup("selinux_compat_net=", selinux_compat_net_setup); |
@@ -352,11 +356,6 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, | |||
352 | length = count; | 356 | length = count; |
353 | 357 | ||
354 | out1: | 358 | out1: |
355 | |||
356 | printk(KERN_INFO "SELinux: policy loaded with handle_unknown=%s\n", | ||
357 | (security_get_reject_unknown() ? "reject" : | ||
358 | (security_get_allow_unknown() ? "allow" : "deny"))); | ||
359 | |||
360 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD, | 359 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD, |
361 | "policy loaded auid=%u ses=%u", | 360 | "policy loaded auid=%u ses=%u", |
362 | audit_get_loginuid(current), | 361 | audit_get_loginuid(current), |
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 9e6626362bfd..a1be97f8beea 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c | |||
@@ -311,7 +311,7 @@ void avtab_hash_eval(struct avtab *h, char *tag) | |||
311 | } | 311 | } |
312 | 312 | ||
313 | printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, " | 313 | printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, " |
314 | "longest chain length %d sum of chain length^2 %Lu\n", | 314 | "longest chain length %d sum of chain length^2 %llu\n", |
315 | tag, h->nel, slots_used, h->nslot, max_chain_len, | 315 | tag, h->nel, slots_used, h->nslot, max_chain_len, |
316 | chain2_len_sum); | 316 | chain2_len_sum); |
317 | } | 317 | } |
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index b9a6f7fc62fc..658c2bd17da8 100644 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h | |||
@@ -28,6 +28,8 @@ struct context { | |||
28 | u32 role; | 28 | u32 role; |
29 | u32 type; | 29 | u32 type; |
30 | struct mls_range range; | 30 | struct mls_range range; |
31 | char *str; /* string representation if context cannot be mapped. */ | ||
32 | u32 len; /* length of string in bytes */ | ||
31 | }; | 33 | }; |
32 | 34 | ||
33 | static inline void mls_context_init(struct context *c) | 35 | static inline void mls_context_init(struct context *c) |
@@ -106,20 +108,43 @@ static inline void context_init(struct context *c) | |||
106 | 108 | ||
107 | static inline int context_cpy(struct context *dst, struct context *src) | 109 | static inline int context_cpy(struct context *dst, struct context *src) |
108 | { | 110 | { |
111 | int rc; | ||
112 | |||
109 | dst->user = src->user; | 113 | dst->user = src->user; |
110 | dst->role = src->role; | 114 | dst->role = src->role; |
111 | dst->type = src->type; | 115 | dst->type = src->type; |
112 | return mls_context_cpy(dst, src); | 116 | if (src->str) { |
117 | dst->str = kstrdup(src->str, GFP_ATOMIC); | ||
118 | if (!dst->str) | ||
119 | return -ENOMEM; | ||
120 | dst->len = src->len; | ||
121 | } else { | ||
122 | dst->str = NULL; | ||
123 | dst->len = 0; | ||
124 | } | ||
125 | rc = mls_context_cpy(dst, src); | ||
126 | if (rc) { | ||
127 | kfree(dst->str); | ||
128 | return rc; | ||
129 | } | ||
130 | return 0; | ||
113 | } | 131 | } |
114 | 132 | ||
115 | static inline void context_destroy(struct context *c) | 133 | static inline void context_destroy(struct context *c) |
116 | { | 134 | { |
117 | c->user = c->role = c->type = 0; | 135 | c->user = c->role = c->type = 0; |
136 | kfree(c->str); | ||
137 | c->str = NULL; | ||
138 | c->len = 0; | ||
118 | mls_context_destroy(c); | 139 | mls_context_destroy(c); |
119 | } | 140 | } |
120 | 141 | ||
121 | static inline int context_cmp(struct context *c1, struct context *c2) | 142 | static inline int context_cmp(struct context *c1, struct context *c2) |
122 | { | 143 | { |
144 | if (c1->len && c2->len) | ||
145 | return (c1->len == c2->len && !strcmp(c1->str, c2->str)); | ||
146 | if (c1->len || c2->len) | ||
147 | return 0; | ||
123 | return ((c1->user == c2->user) && | 148 | return ((c1->user == c2->user) && |
124 | (c1->role == c2->role) && | 149 | (c1->role == c2->role) && |
125 | (c1->type == c2->type) && | 150 | (c1->type == c2->type) && |
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 8b1706b7b3cc..77d745da48bb 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c | |||
@@ -239,7 +239,8 @@ int mls_context_isvalid(struct policydb *p, struct context *c) | |||
239 | * Policy read-lock must be held for sidtab lookup. | 239 | * Policy read-lock must be held for sidtab lookup. |
240 | * | 240 | * |
241 | */ | 241 | */ |
242 | int mls_context_to_sid(char oldc, | 242 | int mls_context_to_sid(struct policydb *pol, |
243 | char oldc, | ||
243 | char **scontext, | 244 | char **scontext, |
244 | struct context *context, | 245 | struct context *context, |
245 | struct sidtab *s, | 246 | struct sidtab *s, |
@@ -286,7 +287,7 @@ int mls_context_to_sid(char oldc, | |||
286 | *p++ = 0; | 287 | *p++ = 0; |
287 | 288 | ||
288 | for (l = 0; l < 2; l++) { | 289 | for (l = 0; l < 2; l++) { |
289 | levdatum = hashtab_search(policydb.p_levels.table, scontextp); | 290 | levdatum = hashtab_search(pol->p_levels.table, scontextp); |
290 | if (!levdatum) { | 291 | if (!levdatum) { |
291 | rc = -EINVAL; | 292 | rc = -EINVAL; |
292 | goto out; | 293 | goto out; |
@@ -311,7 +312,7 @@ int mls_context_to_sid(char oldc, | |||
311 | *rngptr++ = 0; | 312 | *rngptr++ = 0; |
312 | } | 313 | } |
313 | 314 | ||
314 | catdatum = hashtab_search(policydb.p_cats.table, | 315 | catdatum = hashtab_search(pol->p_cats.table, |
315 | scontextp); | 316 | scontextp); |
316 | if (!catdatum) { | 317 | if (!catdatum) { |
317 | rc = -EINVAL; | 318 | rc = -EINVAL; |
@@ -327,7 +328,7 @@ int mls_context_to_sid(char oldc, | |||
327 | if (rngptr) { | 328 | if (rngptr) { |
328 | int i; | 329 | int i; |
329 | 330 | ||
330 | rngdatum = hashtab_search(policydb.p_cats.table, rngptr); | 331 | rngdatum = hashtab_search(pol->p_cats.table, rngptr); |
331 | if (!rngdatum) { | 332 | if (!rngdatum) { |
332 | rc = -EINVAL; | 333 | rc = -EINVAL; |
333 | goto out; | 334 | goto out; |
@@ -395,7 +396,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) | |||
395 | if (!tmpstr) { | 396 | if (!tmpstr) { |
396 | rc = -ENOMEM; | 397 | rc = -ENOMEM; |
397 | } else { | 398 | } else { |
398 | rc = mls_context_to_sid(':', &tmpstr, context, | 399 | rc = mls_context_to_sid(&policydb, ':', &tmpstr, context, |
399 | NULL, SECSID_NULL); | 400 | NULL, SECSID_NULL); |
400 | kfree(freestr); | 401 | kfree(freestr); |
401 | } | 402 | } |
@@ -436,13 +437,13 @@ int mls_setup_user_range(struct context *fromcon, struct user_datum *user, | |||
436 | struct mls_level *usercon_clr = &(usercon->range.level[1]); | 437 | struct mls_level *usercon_clr = &(usercon->range.level[1]); |
437 | 438 | ||
438 | /* Honor the user's default level if we can */ | 439 | /* Honor the user's default level if we can */ |
439 | if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) { | 440 | if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) |
440 | *usercon_sen = *user_def; | 441 | *usercon_sen = *user_def; |
441 | } else if (mls_level_between(fromcon_sen, user_def, user_clr)) { | 442 | else if (mls_level_between(fromcon_sen, user_def, user_clr)) |
442 | *usercon_sen = *fromcon_sen; | 443 | *usercon_sen = *fromcon_sen; |
443 | } else if (mls_level_between(fromcon_clr, user_low, user_def)) { | 444 | else if (mls_level_between(fromcon_clr, user_low, user_def)) |
444 | *usercon_sen = *user_low; | 445 | *usercon_sen = *user_low; |
445 | } else | 446 | else |
446 | return -EINVAL; | 447 | return -EINVAL; |
447 | 448 | ||
448 | /* Lower the clearance of available contexts | 449 | /* Lower the clearance of available contexts |
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index 0fdf6257ef64..1276715aaa8b 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h | |||
@@ -30,7 +30,8 @@ int mls_context_isvalid(struct policydb *p, struct context *c); | |||
30 | int mls_range_isvalid(struct policydb *p, struct mls_range *r); | 30 | int mls_range_isvalid(struct policydb *p, struct mls_range *r); |
31 | int mls_level_isvalid(struct policydb *p, struct mls_level *l); | 31 | int mls_level_isvalid(struct policydb *p, struct mls_level *l); |
32 | 32 | ||
33 | int mls_context_to_sid(char oldc, | 33 | int mls_context_to_sid(struct policydb *p, |
34 | char oldc, | ||
34 | char **scontext, | 35 | char **scontext, |
35 | struct context *context, | 36 | struct context *context, |
36 | struct sidtab *s, | 37 | struct sidtab *s, |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 84f8cc73c7db..2391761ae422 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -1478,7 +1478,8 @@ int policydb_read(struct policydb *p, void *fp) | |||
1478 | struct ocontext *l, *c, *newc; | 1478 | struct ocontext *l, *c, *newc; |
1479 | struct genfs *genfs_p, *genfs, *newgenfs; | 1479 | struct genfs *genfs_p, *genfs, *newgenfs; |
1480 | int i, j, rc; | 1480 | int i, j, rc; |
1481 | __le32 buf[8]; | 1481 | __le32 buf[4]; |
1482 | u32 nodebuf[8]; | ||
1482 | u32 len, len2, config, nprim, nel, nel2; | 1483 | u32 len, len2, config, nprim, nel, nel2; |
1483 | char *policydb_str; | 1484 | char *policydb_str; |
1484 | struct policydb_compat_info *info; | 1485 | struct policydb_compat_info *info; |
@@ -1749,11 +1750,11 @@ int policydb_read(struct policydb *p, void *fp) | |||
1749 | goto bad; | 1750 | goto bad; |
1750 | break; | 1751 | break; |
1751 | case OCON_NODE: | 1752 | case OCON_NODE: |
1752 | rc = next_entry(buf, fp, sizeof(u32) * 2); | 1753 | rc = next_entry(nodebuf, fp, sizeof(u32) * 2); |
1753 | if (rc < 0) | 1754 | if (rc < 0) |
1754 | goto bad; | 1755 | goto bad; |
1755 | c->u.node.addr = le32_to_cpu(buf[0]); | 1756 | c->u.node.addr = nodebuf[0]; /* network order */ |
1756 | c->u.node.mask = le32_to_cpu(buf[1]); | 1757 | c->u.node.mask = nodebuf[1]; /* network order */ |
1757 | rc = context_read_and_validate(&c->context[0], p, fp); | 1758 | rc = context_read_and_validate(&c->context[0], p, fp); |
1758 | if (rc) | 1759 | if (rc) |
1759 | goto bad; | 1760 | goto bad; |
@@ -1782,13 +1783,13 @@ int policydb_read(struct policydb *p, void *fp) | |||
1782 | case OCON_NODE6: { | 1783 | case OCON_NODE6: { |
1783 | int k; | 1784 | int k; |
1784 | 1785 | ||
1785 | rc = next_entry(buf, fp, sizeof(u32) * 8); | 1786 | rc = next_entry(nodebuf, fp, sizeof(u32) * 8); |
1786 | if (rc < 0) | 1787 | if (rc < 0) |
1787 | goto bad; | 1788 | goto bad; |
1788 | for (k = 0; k < 4; k++) | 1789 | for (k = 0; k < 4; k++) |
1789 | c->u.node6.addr[k] = le32_to_cpu(buf[k]); | 1790 | c->u.node6.addr[k] = nodebuf[k]; |
1790 | for (k = 0; k < 4; k++) | 1791 | for (k = 0; k < 4; k++) |
1791 | c->u.node6.mask[k] = le32_to_cpu(buf[k+4]); | 1792 | c->u.node6.mask[k] = nodebuf[k+4]; |
1792 | if (context_read_and_validate(&c->context[0], p, fp)) | 1793 | if (context_read_and_validate(&c->context[0], p, fp)) |
1793 | goto bad; | 1794 | goto bad; |
1794 | break; | 1795 | break; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index dcc2e1c4fd83..8e42da120101 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -71,14 +71,6 @@ int selinux_policycap_openperm; | |||
71 | extern const struct selinux_class_perm selinux_class_perm; | 71 | extern const struct selinux_class_perm selinux_class_perm; |
72 | 72 | ||
73 | static DEFINE_RWLOCK(policy_rwlock); | 73 | static DEFINE_RWLOCK(policy_rwlock); |
74 | #define POLICY_RDLOCK read_lock(&policy_rwlock) | ||
75 | #define POLICY_WRLOCK write_lock_irq(&policy_rwlock) | ||
76 | #define POLICY_RDUNLOCK read_unlock(&policy_rwlock) | ||
77 | #define POLICY_WRUNLOCK write_unlock_irq(&policy_rwlock) | ||
78 | |||
79 | static DEFINE_MUTEX(load_mutex); | ||
80 | #define LOAD_LOCK mutex_lock(&load_mutex) | ||
81 | #define LOAD_UNLOCK mutex_unlock(&load_mutex) | ||
82 | 74 | ||
83 | static struct sidtab sidtab; | 75 | static struct sidtab sidtab; |
84 | struct policydb policydb; | 76 | struct policydb policydb; |
@@ -332,7 +324,7 @@ static int context_struct_compute_av(struct context *scontext, | |||
332 | goto inval_class; | 324 | goto inval_class; |
333 | if (unlikely(tclass > policydb.p_classes.nprim)) | 325 | if (unlikely(tclass > policydb.p_classes.nprim)) |
334 | if (tclass > kdefs->cts_len || | 326 | if (tclass > kdefs->cts_len || |
335 | !kdefs->class_to_string[tclass - 1] || | 327 | !kdefs->class_to_string[tclass] || |
336 | !policydb.allow_unknown) | 328 | !policydb.allow_unknown) |
337 | goto inval_class; | 329 | goto inval_class; |
338 | 330 | ||
@@ -415,9 +407,19 @@ static int context_struct_compute_av(struct context *scontext, | |||
415 | return 0; | 407 | return 0; |
416 | 408 | ||
417 | inval_class: | 409 | inval_class: |
418 | printk(KERN_ERR "SELinux: %s: unrecognized class %d\n", __func__, | 410 | if (!tclass || tclass > kdefs->cts_len || |
419 | tclass); | 411 | !kdefs->class_to_string[tclass]) { |
420 | return -EINVAL; | 412 | if (printk_ratelimit()) |
413 | printk(KERN_ERR "SELinux: %s: unrecognized class %d\n", | ||
414 | __func__, tclass); | ||
415 | return -EINVAL; | ||
416 | } | ||
417 | |||
418 | /* | ||
419 | * Known to the kernel, but not to the policy. | ||
420 | * Handle as a denial (allowed is 0). | ||
421 | */ | ||
422 | return 0; | ||
421 | } | 423 | } |
422 | 424 | ||
423 | /* | 425 | /* |
@@ -429,7 +431,7 @@ int security_permissive_sid(u32 sid) | |||
429 | u32 type; | 431 | u32 type; |
430 | int rc; | 432 | int rc; |
431 | 433 | ||
432 | POLICY_RDLOCK; | 434 | read_lock(&policy_rwlock); |
433 | 435 | ||
434 | context = sidtab_search(&sidtab, sid); | 436 | context = sidtab_search(&sidtab, sid); |
435 | BUG_ON(!context); | 437 | BUG_ON(!context); |
@@ -441,7 +443,7 @@ int security_permissive_sid(u32 sid) | |||
441 | */ | 443 | */ |
442 | rc = ebitmap_get_bit(&policydb.permissive_map, type); | 444 | rc = ebitmap_get_bit(&policydb.permissive_map, type); |
443 | 445 | ||
444 | POLICY_RDUNLOCK; | 446 | read_unlock(&policy_rwlock); |
445 | return rc; | 447 | return rc; |
446 | } | 448 | } |
447 | 449 | ||
@@ -486,7 +488,7 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, | |||
486 | if (!ss_initialized) | 488 | if (!ss_initialized) |
487 | return 0; | 489 | return 0; |
488 | 490 | ||
489 | POLICY_RDLOCK; | 491 | read_lock(&policy_rwlock); |
490 | 492 | ||
491 | /* | 493 | /* |
492 | * Remap extended Netlink classes for old policy versions. | 494 | * Remap extended Netlink classes for old policy versions. |
@@ -543,7 +545,7 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, | |||
543 | } | 545 | } |
544 | 546 | ||
545 | out: | 547 | out: |
546 | POLICY_RDUNLOCK; | 548 | read_unlock(&policy_rwlock); |
547 | return rc; | 549 | return rc; |
548 | } | 550 | } |
549 | 551 | ||
@@ -578,7 +580,7 @@ int security_compute_av(u32 ssid, | |||
578 | return 0; | 580 | return 0; |
579 | } | 581 | } |
580 | 582 | ||
581 | POLICY_RDLOCK; | 583 | read_lock(&policy_rwlock); |
582 | 584 | ||
583 | scontext = sidtab_search(&sidtab, ssid); | 585 | scontext = sidtab_search(&sidtab, ssid); |
584 | if (!scontext) { | 586 | if (!scontext) { |
@@ -598,7 +600,7 @@ int security_compute_av(u32 ssid, | |||
598 | rc = context_struct_compute_av(scontext, tcontext, tclass, | 600 | rc = context_struct_compute_av(scontext, tcontext, tclass, |
599 | requested, avd); | 601 | requested, avd); |
600 | out: | 602 | out: |
601 | POLICY_RDUNLOCK; | 603 | read_unlock(&policy_rwlock); |
602 | return rc; | 604 | return rc; |
603 | } | 605 | } |
604 | 606 | ||
@@ -616,6 +618,14 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 | |||
616 | *scontext = NULL; | 618 | *scontext = NULL; |
617 | *scontext_len = 0; | 619 | *scontext_len = 0; |
618 | 620 | ||
621 | if (context->len) { | ||
622 | *scontext_len = context->len; | ||
623 | *scontext = kstrdup(context->str, GFP_ATOMIC); | ||
624 | if (!(*scontext)) | ||
625 | return -ENOMEM; | ||
626 | return 0; | ||
627 | } | ||
628 | |||
619 | /* Compute the size of the context. */ | 629 | /* Compute the size of the context. */ |
620 | *scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1; | 630 | *scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1; |
621 | *scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1; | 631 | *scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1; |
@@ -655,17 +665,8 @@ const char *security_get_initial_sid_context(u32 sid) | |||
655 | return initial_sid_to_string[sid]; | 665 | return initial_sid_to_string[sid]; |
656 | } | 666 | } |
657 | 667 | ||
658 | /** | 668 | static int security_sid_to_context_core(u32 sid, char **scontext, |
659 | * security_sid_to_context - Obtain a context for a given SID. | 669 | u32 *scontext_len, int force) |
660 | * @sid: security identifier, SID | ||
661 | * @scontext: security context | ||
662 | * @scontext_len: length in bytes | ||
663 | * | ||
664 | * Write the string representation of the context associated with @sid | ||
665 | * into a dynamically allocated string of the correct size. Set @scontext | ||
666 | * to point to this string and set @scontext_len to the length of the string. | ||
667 | */ | ||
668 | int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) | ||
669 | { | 670 | { |
670 | struct context *context; | 671 | struct context *context; |
671 | int rc = 0; | 672 | int rc = 0; |
@@ -692,8 +693,11 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) | |||
692 | rc = -EINVAL; | 693 | rc = -EINVAL; |
693 | goto out; | 694 | goto out; |
694 | } | 695 | } |
695 | POLICY_RDLOCK; | 696 | read_lock(&policy_rwlock); |
696 | context = sidtab_search(&sidtab, sid); | 697 | if (force) |
698 | context = sidtab_search_force(&sidtab, sid); | ||
699 | else | ||
700 | context = sidtab_search(&sidtab, sid); | ||
697 | if (!context) { | 701 | if (!context) { |
698 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | 702 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", |
699 | __func__, sid); | 703 | __func__, sid); |
@@ -702,59 +706,54 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) | |||
702 | } | 706 | } |
703 | rc = context_struct_to_string(context, scontext, scontext_len); | 707 | rc = context_struct_to_string(context, scontext, scontext_len); |
704 | out_unlock: | 708 | out_unlock: |
705 | POLICY_RDUNLOCK; | 709 | read_unlock(&policy_rwlock); |
706 | out: | 710 | out: |
707 | return rc; | 711 | return rc; |
708 | 712 | ||
709 | } | 713 | } |
710 | 714 | ||
711 | static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | 715 | /** |
712 | u32 *sid, u32 def_sid, gfp_t gfp_flags) | 716 | * security_sid_to_context - Obtain a context for a given SID. |
717 | * @sid: security identifier, SID | ||
718 | * @scontext: security context | ||
719 | * @scontext_len: length in bytes | ||
720 | * | ||
721 | * Write the string representation of the context associated with @sid | ||
722 | * into a dynamically allocated string of the correct size. Set @scontext | ||
723 | * to point to this string and set @scontext_len to the length of the string. | ||
724 | */ | ||
725 | int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) | ||
726 | { | ||
727 | return security_sid_to_context_core(sid, scontext, scontext_len, 0); | ||
728 | } | ||
729 | |||
730 | int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len) | ||
731 | { | ||
732 | return security_sid_to_context_core(sid, scontext, scontext_len, 1); | ||
733 | } | ||
734 | |||
735 | /* | ||
736 | * Caveat: Mutates scontext. | ||
737 | */ | ||
738 | static int string_to_context_struct(struct policydb *pol, | ||
739 | struct sidtab *sidtabp, | ||
740 | char *scontext, | ||
741 | u32 scontext_len, | ||
742 | struct context *ctx, | ||
743 | u32 def_sid) | ||
713 | { | 744 | { |
714 | char *scontext2; | ||
715 | struct context context; | ||
716 | struct role_datum *role; | 745 | struct role_datum *role; |
717 | struct type_datum *typdatum; | 746 | struct type_datum *typdatum; |
718 | struct user_datum *usrdatum; | 747 | struct user_datum *usrdatum; |
719 | char *scontextp, *p, oldc; | 748 | char *scontextp, *p, oldc; |
720 | int rc = 0; | 749 | int rc = 0; |
721 | 750 | ||
722 | if (!ss_initialized) { | 751 | context_init(ctx); |
723 | int i; | ||
724 | |||
725 | for (i = 1; i < SECINITSID_NUM; i++) { | ||
726 | if (!strcmp(initial_sid_to_string[i], scontext)) { | ||
727 | *sid = i; | ||
728 | goto out; | ||
729 | } | ||
730 | } | ||
731 | *sid = SECINITSID_KERNEL; | ||
732 | goto out; | ||
733 | } | ||
734 | *sid = SECSID_NULL; | ||
735 | |||
736 | /* Copy the string so that we can modify the copy as we parse it. | ||
737 | The string should already by null terminated, but we append a | ||
738 | null suffix to the copy to avoid problems with the existing | ||
739 | attr package, which doesn't view the null terminator as part | ||
740 | of the attribute value. */ | ||
741 | scontext2 = kmalloc(scontext_len+1, gfp_flags); | ||
742 | if (!scontext2) { | ||
743 | rc = -ENOMEM; | ||
744 | goto out; | ||
745 | } | ||
746 | memcpy(scontext2, scontext, scontext_len); | ||
747 | scontext2[scontext_len] = 0; | ||
748 | |||
749 | context_init(&context); | ||
750 | *sid = SECSID_NULL; | ||
751 | |||
752 | POLICY_RDLOCK; | ||
753 | 752 | ||
754 | /* Parse the security context. */ | 753 | /* Parse the security context. */ |
755 | 754 | ||
756 | rc = -EINVAL; | 755 | rc = -EINVAL; |
757 | scontextp = (char *) scontext2; | 756 | scontextp = (char *) scontext; |
758 | 757 | ||
759 | /* Extract the user. */ | 758 | /* Extract the user. */ |
760 | p = scontextp; | 759 | p = scontextp; |
@@ -762,15 +761,15 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | |||
762 | p++; | 761 | p++; |
763 | 762 | ||
764 | if (*p == 0) | 763 | if (*p == 0) |
765 | goto out_unlock; | 764 | goto out; |
766 | 765 | ||
767 | *p++ = 0; | 766 | *p++ = 0; |
768 | 767 | ||
769 | usrdatum = hashtab_search(policydb.p_users.table, scontextp); | 768 | usrdatum = hashtab_search(pol->p_users.table, scontextp); |
770 | if (!usrdatum) | 769 | if (!usrdatum) |
771 | goto out_unlock; | 770 | goto out; |
772 | 771 | ||
773 | context.user = usrdatum->value; | 772 | ctx->user = usrdatum->value; |
774 | 773 | ||
775 | /* Extract role. */ | 774 | /* Extract role. */ |
776 | scontextp = p; | 775 | scontextp = p; |
@@ -778,14 +777,14 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | |||
778 | p++; | 777 | p++; |
779 | 778 | ||
780 | if (*p == 0) | 779 | if (*p == 0) |
781 | goto out_unlock; | 780 | goto out; |
782 | 781 | ||
783 | *p++ = 0; | 782 | *p++ = 0; |
784 | 783 | ||
785 | role = hashtab_search(policydb.p_roles.table, scontextp); | 784 | role = hashtab_search(pol->p_roles.table, scontextp); |
786 | if (!role) | 785 | if (!role) |
787 | goto out_unlock; | 786 | goto out; |
788 | context.role = role->value; | 787 | ctx->role = role->value; |
789 | 788 | ||
790 | /* Extract type. */ | 789 | /* Extract type. */ |
791 | scontextp = p; | 790 | scontextp = p; |
@@ -794,33 +793,87 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | |||
794 | oldc = *p; | 793 | oldc = *p; |
795 | *p++ = 0; | 794 | *p++ = 0; |
796 | 795 | ||
797 | typdatum = hashtab_search(policydb.p_types.table, scontextp); | 796 | typdatum = hashtab_search(pol->p_types.table, scontextp); |
798 | if (!typdatum) | 797 | if (!typdatum) |
799 | goto out_unlock; | 798 | goto out; |
800 | 799 | ||
801 | context.type = typdatum->value; | 800 | ctx->type = typdatum->value; |
802 | 801 | ||
803 | rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid); | 802 | rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid); |
804 | if (rc) | 803 | if (rc) |
805 | goto out_unlock; | 804 | goto out; |
806 | 805 | ||
807 | if ((p - scontext2) < scontext_len) { | 806 | if ((p - scontext) < scontext_len) { |
808 | rc = -EINVAL; | 807 | rc = -EINVAL; |
809 | goto out_unlock; | 808 | goto out; |
810 | } | 809 | } |
811 | 810 | ||
812 | /* Check the validity of the new context. */ | 811 | /* Check the validity of the new context. */ |
813 | if (!policydb_context_isvalid(&policydb, &context)) { | 812 | if (!policydb_context_isvalid(pol, ctx)) { |
814 | rc = -EINVAL; | 813 | rc = -EINVAL; |
815 | goto out_unlock; | 814 | context_destroy(ctx); |
815 | goto out; | ||
816 | } | 816 | } |
817 | /* Obtain the new sid. */ | 817 | rc = 0; |
818 | out: | ||
819 | return rc; | ||
820 | } | ||
821 | |||
822 | static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | ||
823 | u32 *sid, u32 def_sid, gfp_t gfp_flags, | ||
824 | int force) | ||
825 | { | ||
826 | char *scontext2, *str = NULL; | ||
827 | struct context context; | ||
828 | int rc = 0; | ||
829 | |||
830 | if (!ss_initialized) { | ||
831 | int i; | ||
832 | |||
833 | for (i = 1; i < SECINITSID_NUM; i++) { | ||
834 | if (!strcmp(initial_sid_to_string[i], scontext)) { | ||
835 | *sid = i; | ||
836 | return 0; | ||
837 | } | ||
838 | } | ||
839 | *sid = SECINITSID_KERNEL; | ||
840 | return 0; | ||
841 | } | ||
842 | *sid = SECSID_NULL; | ||
843 | |||
844 | /* Copy the string so that we can modify the copy as we parse it. */ | ||
845 | scontext2 = kmalloc(scontext_len+1, gfp_flags); | ||
846 | if (!scontext2) | ||
847 | return -ENOMEM; | ||
848 | memcpy(scontext2, scontext, scontext_len); | ||
849 | scontext2[scontext_len] = 0; | ||
850 | |||
851 | if (force) { | ||
852 | /* Save another copy for storing in uninterpreted form */ | ||
853 | str = kstrdup(scontext2, gfp_flags); | ||
854 | if (!str) { | ||
855 | kfree(scontext2); | ||
856 | return -ENOMEM; | ||
857 | } | ||
858 | } | ||
859 | |||
860 | read_lock(&policy_rwlock); | ||
861 | rc = string_to_context_struct(&policydb, &sidtab, | ||
862 | scontext2, scontext_len, | ||
863 | &context, def_sid); | ||
864 | if (rc == -EINVAL && force) { | ||
865 | context.str = str; | ||
866 | context.len = scontext_len; | ||
867 | str = NULL; | ||
868 | } else if (rc) | ||
869 | goto out; | ||
818 | rc = sidtab_context_to_sid(&sidtab, &context, sid); | 870 | rc = sidtab_context_to_sid(&sidtab, &context, sid); |
819 | out_unlock: | 871 | if (rc) |
820 | POLICY_RDUNLOCK; | 872 | context_destroy(&context); |
821 | context_destroy(&context); | ||
822 | kfree(scontext2); | ||
823 | out: | 873 | out: |
874 | read_unlock(&policy_rwlock); | ||
875 | kfree(scontext2); | ||
876 | kfree(str); | ||
824 | return rc; | 877 | return rc; |
825 | } | 878 | } |
826 | 879 | ||
@@ -838,7 +891,7 @@ out: | |||
838 | int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) | 891 | int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) |
839 | { | 892 | { |
840 | return security_context_to_sid_core(scontext, scontext_len, | 893 | return security_context_to_sid_core(scontext, scontext_len, |
841 | sid, SECSID_NULL, GFP_KERNEL); | 894 | sid, SECSID_NULL, GFP_KERNEL, 0); |
842 | } | 895 | } |
843 | 896 | ||
844 | /** | 897 | /** |
@@ -855,6 +908,7 @@ int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) | |||
855 | * The default SID is passed to the MLS layer to be used to allow | 908 | * The default SID is passed to the MLS layer to be used to allow |
856 | * kernel labeling of the MLS field if the MLS field is not present | 909 | * kernel labeling of the MLS field if the MLS field is not present |
857 | * (for upgrading to MLS without full relabel). | 910 | * (for upgrading to MLS without full relabel). |
911 | * Implicitly forces adding of the context even if it cannot be mapped yet. | ||
858 | * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient | 912 | * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient |
859 | * memory is available, or 0 on success. | 913 | * memory is available, or 0 on success. |
860 | */ | 914 | */ |
@@ -862,7 +916,14 @@ int security_context_to_sid_default(const char *scontext, u32 scontext_len, | |||
862 | u32 *sid, u32 def_sid, gfp_t gfp_flags) | 916 | u32 *sid, u32 def_sid, gfp_t gfp_flags) |
863 | { | 917 | { |
864 | return security_context_to_sid_core(scontext, scontext_len, | 918 | return security_context_to_sid_core(scontext, scontext_len, |
865 | sid, def_sid, gfp_flags); | 919 | sid, def_sid, gfp_flags, 1); |
920 | } | ||
921 | |||
922 | int security_context_to_sid_force(const char *scontext, u32 scontext_len, | ||
923 | u32 *sid) | ||
924 | { | ||
925 | return security_context_to_sid_core(scontext, scontext_len, | ||
926 | sid, SECSID_NULL, GFP_KERNEL, 1); | ||
866 | } | 927 | } |
867 | 928 | ||
868 | static int compute_sid_handle_invalid_context( | 929 | static int compute_sid_handle_invalid_context( |
@@ -922,7 +983,7 @@ static int security_compute_sid(u32 ssid, | |||
922 | 983 | ||
923 | context_init(&newcontext); | 984 | context_init(&newcontext); |
924 | 985 | ||
925 | POLICY_RDLOCK; | 986 | read_lock(&policy_rwlock); |
926 | 987 | ||
927 | scontext = sidtab_search(&sidtab, ssid); | 988 | scontext = sidtab_search(&sidtab, ssid); |
928 | if (!scontext) { | 989 | if (!scontext) { |
@@ -1027,7 +1088,7 @@ static int security_compute_sid(u32 ssid, | |||
1027 | /* Obtain the sid for the context. */ | 1088 | /* Obtain the sid for the context. */ |
1028 | rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid); | 1089 | rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid); |
1029 | out_unlock: | 1090 | out_unlock: |
1030 | POLICY_RDUNLOCK; | 1091 | read_unlock(&policy_rwlock); |
1031 | context_destroy(&newcontext); | 1092 | context_destroy(&newcontext); |
1032 | out: | 1093 | out: |
1033 | return rc; | 1094 | return rc; |
@@ -1110,6 +1171,7 @@ static int validate_classes(struct policydb *p) | |||
1110 | const struct selinux_class_perm *kdefs = &selinux_class_perm; | 1171 | const struct selinux_class_perm *kdefs = &selinux_class_perm; |
1111 | const char *def_class, *def_perm, *pol_class; | 1172 | const char *def_class, *def_perm, *pol_class; |
1112 | struct symtab *perms; | 1173 | struct symtab *perms; |
1174 | bool print_unknown_handle = 0; | ||
1113 | 1175 | ||
1114 | if (p->allow_unknown) { | 1176 | if (p->allow_unknown) { |
1115 | u32 num_classes = kdefs->cts_len; | 1177 | u32 num_classes = kdefs->cts_len; |
@@ -1130,6 +1192,7 @@ static int validate_classes(struct policydb *p) | |||
1130 | return -EINVAL; | 1192 | return -EINVAL; |
1131 | if (p->allow_unknown) | 1193 | if (p->allow_unknown) |
1132 | p->undefined_perms[i-1] = ~0U; | 1194 | p->undefined_perms[i-1] = ~0U; |
1195 | print_unknown_handle = 1; | ||
1133 | continue; | 1196 | continue; |
1134 | } | 1197 | } |
1135 | pol_class = p->p_class_val_to_name[i-1]; | 1198 | pol_class = p->p_class_val_to_name[i-1]; |
@@ -1159,6 +1222,7 @@ static int validate_classes(struct policydb *p) | |||
1159 | return -EINVAL; | 1222 | return -EINVAL; |
1160 | if (p->allow_unknown) | 1223 | if (p->allow_unknown) |
1161 | p->undefined_perms[class_val-1] |= perm_val; | 1224 | p->undefined_perms[class_val-1] |= perm_val; |
1225 | print_unknown_handle = 1; | ||
1162 | continue; | 1226 | continue; |
1163 | } | 1227 | } |
1164 | perdatum = hashtab_search(perms->table, def_perm); | 1228 | perdatum = hashtab_search(perms->table, def_perm); |
@@ -1206,6 +1270,7 @@ static int validate_classes(struct policydb *p) | |||
1206 | return -EINVAL; | 1270 | return -EINVAL; |
1207 | if (p->allow_unknown) | 1271 | if (p->allow_unknown) |
1208 | p->undefined_perms[class_val-1] |= (1 << j); | 1272 | p->undefined_perms[class_val-1] |= (1 << j); |
1273 | print_unknown_handle = 1; | ||
1209 | continue; | 1274 | continue; |
1210 | } | 1275 | } |
1211 | perdatum = hashtab_search(perms->table, def_perm); | 1276 | perdatum = hashtab_search(perms->table, def_perm); |
@@ -1223,6 +1288,9 @@ static int validate_classes(struct policydb *p) | |||
1223 | } | 1288 | } |
1224 | } | 1289 | } |
1225 | } | 1290 | } |
1291 | if (print_unknown_handle) | ||
1292 | printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n", | ||
1293 | (security_get_allow_unknown() ? "allowed" : "denied")); | ||
1226 | return 0; | 1294 | return 0; |
1227 | } | 1295 | } |
1228 | 1296 | ||
@@ -1246,9 +1314,12 @@ static inline int convert_context_handle_invalid_context(struct context *context | |||
1246 | char *s; | 1314 | char *s; |
1247 | u32 len; | 1315 | u32 len; |
1248 | 1316 | ||
1249 | context_struct_to_string(context, &s, &len); | 1317 | if (!context_struct_to_string(context, &s, &len)) { |
1250 | printk(KERN_ERR "SELinux: context %s is invalid\n", s); | 1318 | printk(KERN_WARNING |
1251 | kfree(s); | 1319 | "SELinux: Context %s would be invalid if enforcing\n", |
1320 | s); | ||
1321 | kfree(s); | ||
1322 | } | ||
1252 | } | 1323 | } |
1253 | return rc; | 1324 | return rc; |
1254 | } | 1325 | } |
@@ -1280,6 +1351,37 @@ static int convert_context(u32 key, | |||
1280 | 1351 | ||
1281 | args = p; | 1352 | args = p; |
1282 | 1353 | ||
1354 | if (c->str) { | ||
1355 | struct context ctx; | ||
1356 | s = kstrdup(c->str, GFP_KERNEL); | ||
1357 | if (!s) { | ||
1358 | rc = -ENOMEM; | ||
1359 | goto out; | ||
1360 | } | ||
1361 | rc = string_to_context_struct(args->newp, NULL, s, | ||
1362 | c->len, &ctx, SECSID_NULL); | ||
1363 | kfree(s); | ||
1364 | if (!rc) { | ||
1365 | printk(KERN_INFO | ||
1366 | "SELinux: Context %s became valid (mapped).\n", | ||
1367 | c->str); | ||
1368 | /* Replace string with mapped representation. */ | ||
1369 | kfree(c->str); | ||
1370 | memcpy(c, &ctx, sizeof(*c)); | ||
1371 | goto out; | ||
1372 | } else if (rc == -EINVAL) { | ||
1373 | /* Retain string representation for later mapping. */ | ||
1374 | rc = 0; | ||
1375 | goto out; | ||
1376 | } else { | ||
1377 | /* Other error condition, e.g. ENOMEM. */ | ||
1378 | printk(KERN_ERR | ||
1379 | "SELinux: Unable to map context %s, rc = %d.\n", | ||
1380 | c->str, -rc); | ||
1381 | goto out; | ||
1382 | } | ||
1383 | } | ||
1384 | |||
1283 | rc = context_cpy(&oldc, c); | 1385 | rc = context_cpy(&oldc, c); |
1284 | if (rc) | 1386 | if (rc) |
1285 | goto out; | 1387 | goto out; |
@@ -1319,13 +1421,21 @@ static int convert_context(u32 key, | |||
1319 | } | 1421 | } |
1320 | 1422 | ||
1321 | context_destroy(&oldc); | 1423 | context_destroy(&oldc); |
1424 | rc = 0; | ||
1322 | out: | 1425 | out: |
1323 | return rc; | 1426 | return rc; |
1324 | bad: | 1427 | bad: |
1325 | context_struct_to_string(&oldc, &s, &len); | 1428 | /* Map old representation to string and save it. */ |
1429 | if (context_struct_to_string(&oldc, &s, &len)) | ||
1430 | return -ENOMEM; | ||
1326 | context_destroy(&oldc); | 1431 | context_destroy(&oldc); |
1327 | printk(KERN_ERR "SELinux: invalidating context %s\n", s); | 1432 | context_destroy(c); |
1328 | kfree(s); | 1433 | c->str = s; |
1434 | c->len = len; | ||
1435 | printk(KERN_INFO | ||
1436 | "SELinux: Context %s became invalid (unmapped).\n", | ||
1437 | c->str); | ||
1438 | rc = 0; | ||
1329 | goto out; | 1439 | goto out; |
1330 | } | 1440 | } |
1331 | 1441 | ||
@@ -1359,17 +1469,13 @@ int security_load_policy(void *data, size_t len) | |||
1359 | int rc = 0; | 1469 | int rc = 0; |
1360 | struct policy_file file = { data, len }, *fp = &file; | 1470 | struct policy_file file = { data, len }, *fp = &file; |
1361 | 1471 | ||
1362 | LOAD_LOCK; | ||
1363 | |||
1364 | if (!ss_initialized) { | 1472 | if (!ss_initialized) { |
1365 | avtab_cache_init(); | 1473 | avtab_cache_init(); |
1366 | if (policydb_read(&policydb, fp)) { | 1474 | if (policydb_read(&policydb, fp)) { |
1367 | LOAD_UNLOCK; | ||
1368 | avtab_cache_destroy(); | 1475 | avtab_cache_destroy(); |
1369 | return -EINVAL; | 1476 | return -EINVAL; |
1370 | } | 1477 | } |
1371 | if (policydb_load_isids(&policydb, &sidtab)) { | 1478 | if (policydb_load_isids(&policydb, &sidtab)) { |
1372 | LOAD_UNLOCK; | ||
1373 | policydb_destroy(&policydb); | 1479 | policydb_destroy(&policydb); |
1374 | avtab_cache_destroy(); | 1480 | avtab_cache_destroy(); |
1375 | return -EINVAL; | 1481 | return -EINVAL; |
@@ -1378,7 +1484,6 @@ int security_load_policy(void *data, size_t len) | |||
1378 | if (validate_classes(&policydb)) { | 1484 | if (validate_classes(&policydb)) { |
1379 | printk(KERN_ERR | 1485 | printk(KERN_ERR |
1380 | "SELinux: the definition of a class is incorrect\n"); | 1486 | "SELinux: the definition of a class is incorrect\n"); |
1381 | LOAD_UNLOCK; | ||
1382 | sidtab_destroy(&sidtab); | 1487 | sidtab_destroy(&sidtab); |
1383 | policydb_destroy(&policydb); | 1488 | policydb_destroy(&policydb); |
1384 | avtab_cache_destroy(); | 1489 | avtab_cache_destroy(); |
@@ -1388,7 +1493,6 @@ int security_load_policy(void *data, size_t len) | |||
1388 | policydb_loaded_version = policydb.policyvers; | 1493 | policydb_loaded_version = policydb.policyvers; |
1389 | ss_initialized = 1; | 1494 | ss_initialized = 1; |
1390 | seqno = ++latest_granting; | 1495 | seqno = ++latest_granting; |
1391 | LOAD_UNLOCK; | ||
1392 | selinux_complete_init(); | 1496 | selinux_complete_init(); |
1393 | avc_ss_reset(seqno); | 1497 | avc_ss_reset(seqno); |
1394 | selnl_notify_policyload(seqno); | 1498 | selnl_notify_policyload(seqno); |
@@ -1401,12 +1505,13 @@ int security_load_policy(void *data, size_t len) | |||
1401 | sidtab_hash_eval(&sidtab, "sids"); | 1505 | sidtab_hash_eval(&sidtab, "sids"); |
1402 | #endif | 1506 | #endif |
1403 | 1507 | ||
1404 | if (policydb_read(&newpolicydb, fp)) { | 1508 | if (policydb_read(&newpolicydb, fp)) |
1405 | LOAD_UNLOCK; | ||
1406 | return -EINVAL; | 1509 | return -EINVAL; |
1407 | } | ||
1408 | 1510 | ||
1409 | sidtab_init(&newsidtab); | 1511 | if (sidtab_init(&newsidtab)) { |
1512 | policydb_destroy(&newpolicydb); | ||
1513 | return -ENOMEM; | ||
1514 | } | ||
1410 | 1515 | ||
1411 | /* Verify that the kernel defined classes are correct. */ | 1516 | /* Verify that the kernel defined classes are correct. */ |
1412 | if (validate_classes(&newpolicydb)) { | 1517 | if (validate_classes(&newpolicydb)) { |
@@ -1429,25 +1534,28 @@ int security_load_policy(void *data, size_t len) | |||
1429 | goto err; | 1534 | goto err; |
1430 | } | 1535 | } |
1431 | 1536 | ||
1432 | /* Convert the internal representations of contexts | 1537 | /* |
1433 | in the new SID table and remove invalid SIDs. */ | 1538 | * Convert the internal representations of contexts |
1539 | * in the new SID table. | ||
1540 | */ | ||
1434 | args.oldp = &policydb; | 1541 | args.oldp = &policydb; |
1435 | args.newp = &newpolicydb; | 1542 | args.newp = &newpolicydb; |
1436 | sidtab_map_remove_on_error(&newsidtab, convert_context, &args); | 1543 | rc = sidtab_map(&newsidtab, convert_context, &args); |
1544 | if (rc) | ||
1545 | goto err; | ||
1437 | 1546 | ||
1438 | /* Save the old policydb and SID table to free later. */ | 1547 | /* Save the old policydb and SID table to free later. */ |
1439 | memcpy(&oldpolicydb, &policydb, sizeof policydb); | 1548 | memcpy(&oldpolicydb, &policydb, sizeof policydb); |
1440 | sidtab_set(&oldsidtab, &sidtab); | 1549 | sidtab_set(&oldsidtab, &sidtab); |
1441 | 1550 | ||
1442 | /* Install the new policydb and SID table. */ | 1551 | /* Install the new policydb and SID table. */ |
1443 | POLICY_WRLOCK; | 1552 | write_lock_irq(&policy_rwlock); |
1444 | memcpy(&policydb, &newpolicydb, sizeof policydb); | 1553 | memcpy(&policydb, &newpolicydb, sizeof policydb); |
1445 | sidtab_set(&sidtab, &newsidtab); | 1554 | sidtab_set(&sidtab, &newsidtab); |
1446 | security_load_policycaps(); | 1555 | security_load_policycaps(); |
1447 | seqno = ++latest_granting; | 1556 | seqno = ++latest_granting; |
1448 | policydb_loaded_version = policydb.policyvers; | 1557 | policydb_loaded_version = policydb.policyvers; |
1449 | POLICY_WRUNLOCK; | 1558 | write_unlock_irq(&policy_rwlock); |
1450 | LOAD_UNLOCK; | ||
1451 | 1559 | ||
1452 | /* Free the old policydb and SID table. */ | 1560 | /* Free the old policydb and SID table. */ |
1453 | policydb_destroy(&oldpolicydb); | 1561 | policydb_destroy(&oldpolicydb); |
@@ -1461,7 +1569,6 @@ int security_load_policy(void *data, size_t len) | |||
1461 | return 0; | 1569 | return 0; |
1462 | 1570 | ||
1463 | err: | 1571 | err: |
1464 | LOAD_UNLOCK; | ||
1465 | sidtab_destroy(&newsidtab); | 1572 | sidtab_destroy(&newsidtab); |
1466 | policydb_destroy(&newpolicydb); | 1573 | policydb_destroy(&newpolicydb); |
1467 | return rc; | 1574 | return rc; |
@@ -1479,7 +1586,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid) | |||
1479 | struct ocontext *c; | 1586 | struct ocontext *c; |
1480 | int rc = 0; | 1587 | int rc = 0; |
1481 | 1588 | ||
1482 | POLICY_RDLOCK; | 1589 | read_lock(&policy_rwlock); |
1483 | 1590 | ||
1484 | c = policydb.ocontexts[OCON_PORT]; | 1591 | c = policydb.ocontexts[OCON_PORT]; |
1485 | while (c) { | 1592 | while (c) { |
@@ -1504,7 +1611,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid) | |||
1504 | } | 1611 | } |
1505 | 1612 | ||
1506 | out: | 1613 | out: |
1507 | POLICY_RDUNLOCK; | 1614 | read_unlock(&policy_rwlock); |
1508 | return rc; | 1615 | return rc; |
1509 | } | 1616 | } |
1510 | 1617 | ||
@@ -1518,7 +1625,7 @@ int security_netif_sid(char *name, u32 *if_sid) | |||
1518 | int rc = 0; | 1625 | int rc = 0; |
1519 | struct ocontext *c; | 1626 | struct ocontext *c; |
1520 | 1627 | ||
1521 | POLICY_RDLOCK; | 1628 | read_lock(&policy_rwlock); |
1522 | 1629 | ||
1523 | c = policydb.ocontexts[OCON_NETIF]; | 1630 | c = policydb.ocontexts[OCON_NETIF]; |
1524 | while (c) { | 1631 | while (c) { |
@@ -1545,7 +1652,7 @@ int security_netif_sid(char *name, u32 *if_sid) | |||
1545 | *if_sid = SECINITSID_NETIF; | 1652 | *if_sid = SECINITSID_NETIF; |
1546 | 1653 | ||
1547 | out: | 1654 | out: |
1548 | POLICY_RDUNLOCK; | 1655 | read_unlock(&policy_rwlock); |
1549 | return rc; | 1656 | return rc; |
1550 | } | 1657 | } |
1551 | 1658 | ||
@@ -1577,7 +1684,7 @@ int security_node_sid(u16 domain, | |||
1577 | int rc = 0; | 1684 | int rc = 0; |
1578 | struct ocontext *c; | 1685 | struct ocontext *c; |
1579 | 1686 | ||
1580 | POLICY_RDLOCK; | 1687 | read_lock(&policy_rwlock); |
1581 | 1688 | ||
1582 | switch (domain) { | 1689 | switch (domain) { |
1583 | case AF_INET: { | 1690 | case AF_INET: { |
@@ -1632,7 +1739,7 @@ int security_node_sid(u16 domain, | |||
1632 | } | 1739 | } |
1633 | 1740 | ||
1634 | out: | 1741 | out: |
1635 | POLICY_RDUNLOCK; | 1742 | read_unlock(&policy_rwlock); |
1636 | return rc; | 1743 | return rc; |
1637 | } | 1744 | } |
1638 | 1745 | ||
@@ -1671,7 +1778,9 @@ int security_get_user_sids(u32 fromsid, | |||
1671 | if (!ss_initialized) | 1778 | if (!ss_initialized) |
1672 | goto out; | 1779 | goto out; |
1673 | 1780 | ||
1674 | POLICY_RDLOCK; | 1781 | read_lock(&policy_rwlock); |
1782 | |||
1783 | context_init(&usercon); | ||
1675 | 1784 | ||
1676 | fromcon = sidtab_search(&sidtab, fromsid); | 1785 | fromcon = sidtab_search(&sidtab, fromsid); |
1677 | if (!fromcon) { | 1786 | if (!fromcon) { |
@@ -1722,7 +1831,7 @@ int security_get_user_sids(u32 fromsid, | |||
1722 | } | 1831 | } |
1723 | 1832 | ||
1724 | out_unlock: | 1833 | out_unlock: |
1725 | POLICY_RDUNLOCK; | 1834 | read_unlock(&policy_rwlock); |
1726 | if (rc || !mynel) { | 1835 | if (rc || !mynel) { |
1727 | kfree(mysids); | 1836 | kfree(mysids); |
1728 | goto out; | 1837 | goto out; |
@@ -1775,7 +1884,7 @@ int security_genfs_sid(const char *fstype, | |||
1775 | while (path[0] == '/' && path[1] == '/') | 1884 | while (path[0] == '/' && path[1] == '/') |
1776 | path++; | 1885 | path++; |
1777 | 1886 | ||
1778 | POLICY_RDLOCK; | 1887 | read_lock(&policy_rwlock); |
1779 | 1888 | ||
1780 | for (genfs = policydb.genfs; genfs; genfs = genfs->next) { | 1889 | for (genfs = policydb.genfs; genfs; genfs = genfs->next) { |
1781 | cmp = strcmp(fstype, genfs->fstype); | 1890 | cmp = strcmp(fstype, genfs->fstype); |
@@ -1812,7 +1921,7 @@ int security_genfs_sid(const char *fstype, | |||
1812 | 1921 | ||
1813 | *sid = c->sid[0]; | 1922 | *sid = c->sid[0]; |
1814 | out: | 1923 | out: |
1815 | POLICY_RDUNLOCK; | 1924 | read_unlock(&policy_rwlock); |
1816 | return rc; | 1925 | return rc; |
1817 | } | 1926 | } |
1818 | 1927 | ||
@@ -1825,12 +1934,13 @@ out: | |||
1825 | int security_fs_use( | 1934 | int security_fs_use( |
1826 | const char *fstype, | 1935 | const char *fstype, |
1827 | unsigned int *behavior, | 1936 | unsigned int *behavior, |
1828 | u32 *sid) | 1937 | u32 *sid, |
1938 | bool can_xattr) | ||
1829 | { | 1939 | { |
1830 | int rc = 0; | 1940 | int rc = 0; |
1831 | struct ocontext *c; | 1941 | struct ocontext *c; |
1832 | 1942 | ||
1833 | POLICY_RDLOCK; | 1943 | read_lock(&policy_rwlock); |
1834 | 1944 | ||
1835 | c = policydb.ocontexts[OCON_FSUSE]; | 1945 | c = policydb.ocontexts[OCON_FSUSE]; |
1836 | while (c) { | 1946 | while (c) { |
@@ -1839,6 +1949,7 @@ int security_fs_use( | |||
1839 | c = c->next; | 1949 | c = c->next; |
1840 | } | 1950 | } |
1841 | 1951 | ||
1952 | /* look for labeling behavior defined in policy */ | ||
1842 | if (c) { | 1953 | if (c) { |
1843 | *behavior = c->v.behavior; | 1954 | *behavior = c->v.behavior; |
1844 | if (!c->sid[0]) { | 1955 | if (!c->sid[0]) { |
@@ -1849,18 +1960,27 @@ int security_fs_use( | |||
1849 | goto out; | 1960 | goto out; |
1850 | } | 1961 | } |
1851 | *sid = c->sid[0]; | 1962 | *sid = c->sid[0]; |
1963 | goto out; | ||
1964 | } | ||
1965 | |||
1966 | /* labeling behavior not in policy, use xattrs if possible */ | ||
1967 | if (can_xattr) { | ||
1968 | *behavior = SECURITY_FS_USE_XATTR; | ||
1969 | *sid = SECINITSID_FS; | ||
1970 | goto out; | ||
1971 | } | ||
1972 | |||
1973 | /* no behavior in policy and can't use xattrs, try GENFS */ | ||
1974 | rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid); | ||
1975 | if (rc) { | ||
1976 | *behavior = SECURITY_FS_USE_NONE; | ||
1977 | rc = 0; | ||
1852 | } else { | 1978 | } else { |
1853 | rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid); | 1979 | *behavior = SECURITY_FS_USE_GENFS; |
1854 | if (rc) { | ||
1855 | *behavior = SECURITY_FS_USE_NONE; | ||
1856 | rc = 0; | ||
1857 | } else { | ||
1858 | *behavior = SECURITY_FS_USE_GENFS; | ||
1859 | } | ||
1860 | } | 1980 | } |
1861 | 1981 | ||
1862 | out: | 1982 | out: |
1863 | POLICY_RDUNLOCK; | 1983 | read_unlock(&policy_rwlock); |
1864 | return rc; | 1984 | return rc; |
1865 | } | 1985 | } |
1866 | 1986 | ||
@@ -1868,7 +1988,7 @@ int security_get_bools(int *len, char ***names, int **values) | |||
1868 | { | 1988 | { |
1869 | int i, rc = -ENOMEM; | 1989 | int i, rc = -ENOMEM; |
1870 | 1990 | ||
1871 | POLICY_RDLOCK; | 1991 | read_lock(&policy_rwlock); |
1872 | *names = NULL; | 1992 | *names = NULL; |
1873 | *values = NULL; | 1993 | *values = NULL; |
1874 | 1994 | ||
@@ -1898,7 +2018,7 @@ int security_get_bools(int *len, char ***names, int **values) | |||
1898 | } | 2018 | } |
1899 | rc = 0; | 2019 | rc = 0; |
1900 | out: | 2020 | out: |
1901 | POLICY_RDUNLOCK; | 2021 | read_unlock(&policy_rwlock); |
1902 | return rc; | 2022 | return rc; |
1903 | err: | 2023 | err: |
1904 | if (*names) { | 2024 | if (*names) { |
@@ -1916,7 +2036,7 @@ int security_set_bools(int len, int *values) | |||
1916 | int lenp, seqno = 0; | 2036 | int lenp, seqno = 0; |
1917 | struct cond_node *cur; | 2037 | struct cond_node *cur; |
1918 | 2038 | ||
1919 | POLICY_WRLOCK; | 2039 | write_lock_irq(&policy_rwlock); |
1920 | 2040 | ||
1921 | lenp = policydb.p_bools.nprim; | 2041 | lenp = policydb.p_bools.nprim; |
1922 | if (len != lenp) { | 2042 | if (len != lenp) { |
@@ -1950,7 +2070,7 @@ int security_set_bools(int len, int *values) | |||
1950 | seqno = ++latest_granting; | 2070 | seqno = ++latest_granting; |
1951 | 2071 | ||
1952 | out: | 2072 | out: |
1953 | POLICY_WRUNLOCK; | 2073 | write_unlock_irq(&policy_rwlock); |
1954 | if (!rc) { | 2074 | if (!rc) { |
1955 | avc_ss_reset(seqno); | 2075 | avc_ss_reset(seqno); |
1956 | selnl_notify_policyload(seqno); | 2076 | selnl_notify_policyload(seqno); |
@@ -1964,7 +2084,7 @@ int security_get_bool_value(int bool) | |||
1964 | int rc = 0; | 2084 | int rc = 0; |
1965 | int len; | 2085 | int len; |
1966 | 2086 | ||
1967 | POLICY_RDLOCK; | 2087 | read_lock(&policy_rwlock); |
1968 | 2088 | ||
1969 | len = policydb.p_bools.nprim; | 2089 | len = policydb.p_bools.nprim; |
1970 | if (bool >= len) { | 2090 | if (bool >= len) { |
@@ -1974,7 +2094,7 @@ int security_get_bool_value(int bool) | |||
1974 | 2094 | ||
1975 | rc = policydb.bool_val_to_struct[bool]->state; | 2095 | rc = policydb.bool_val_to_struct[bool]->state; |
1976 | out: | 2096 | out: |
1977 | POLICY_RDUNLOCK; | 2097 | read_unlock(&policy_rwlock); |
1978 | return rc; | 2098 | return rc; |
1979 | } | 2099 | } |
1980 | 2100 | ||
@@ -2029,7 +2149,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) | |||
2029 | 2149 | ||
2030 | context_init(&newcon); | 2150 | context_init(&newcon); |
2031 | 2151 | ||
2032 | POLICY_RDLOCK; | 2152 | read_lock(&policy_rwlock); |
2033 | context1 = sidtab_search(&sidtab, sid); | 2153 | context1 = sidtab_search(&sidtab, sid); |
2034 | if (!context1) { | 2154 | if (!context1) { |
2035 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | 2155 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", |
@@ -2071,7 +2191,7 @@ bad: | |||
2071 | } | 2191 | } |
2072 | 2192 | ||
2073 | out_unlock: | 2193 | out_unlock: |
2074 | POLICY_RDUNLOCK; | 2194 | read_unlock(&policy_rwlock); |
2075 | context_destroy(&newcon); | 2195 | context_destroy(&newcon); |
2076 | out: | 2196 | out: |
2077 | return rc; | 2197 | return rc; |
@@ -2128,7 +2248,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, | |||
2128 | return 0; | 2248 | return 0; |
2129 | } | 2249 | } |
2130 | 2250 | ||
2131 | POLICY_RDLOCK; | 2251 | read_lock(&policy_rwlock); |
2132 | 2252 | ||
2133 | nlbl_ctx = sidtab_search(&sidtab, nlbl_sid); | 2253 | nlbl_ctx = sidtab_search(&sidtab, nlbl_sid); |
2134 | if (!nlbl_ctx) { | 2254 | if (!nlbl_ctx) { |
@@ -2147,7 +2267,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, | |||
2147 | rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES); | 2267 | rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES); |
2148 | 2268 | ||
2149 | out_slowpath: | 2269 | out_slowpath: |
2150 | POLICY_RDUNLOCK; | 2270 | read_unlock(&policy_rwlock); |
2151 | if (rc == 0) | 2271 | if (rc == 0) |
2152 | /* at present NetLabel SIDs/labels really only carry MLS | 2272 | /* at present NetLabel SIDs/labels really only carry MLS |
2153 | * information so if the MLS portion of the NetLabel SID | 2273 | * information so if the MLS portion of the NetLabel SID |
@@ -2177,7 +2297,7 @@ int security_get_classes(char ***classes, int *nclasses) | |||
2177 | { | 2297 | { |
2178 | int rc = -ENOMEM; | 2298 | int rc = -ENOMEM; |
2179 | 2299 | ||
2180 | POLICY_RDLOCK; | 2300 | read_lock(&policy_rwlock); |
2181 | 2301 | ||
2182 | *nclasses = policydb.p_classes.nprim; | 2302 | *nclasses = policydb.p_classes.nprim; |
2183 | *classes = kcalloc(*nclasses, sizeof(*classes), GFP_ATOMIC); | 2303 | *classes = kcalloc(*nclasses, sizeof(*classes), GFP_ATOMIC); |
@@ -2194,7 +2314,7 @@ int security_get_classes(char ***classes, int *nclasses) | |||
2194 | } | 2314 | } |
2195 | 2315 | ||
2196 | out: | 2316 | out: |
2197 | POLICY_RDUNLOCK; | 2317 | read_unlock(&policy_rwlock); |
2198 | return rc; | 2318 | return rc; |
2199 | } | 2319 | } |
2200 | 2320 | ||
@@ -2216,7 +2336,7 @@ int security_get_permissions(char *class, char ***perms, int *nperms) | |||
2216 | int rc = -ENOMEM, i; | 2336 | int rc = -ENOMEM, i; |
2217 | struct class_datum *match; | 2337 | struct class_datum *match; |
2218 | 2338 | ||
2219 | POLICY_RDLOCK; | 2339 | read_lock(&policy_rwlock); |
2220 | 2340 | ||
2221 | match = hashtab_search(policydb.p_classes.table, class); | 2341 | match = hashtab_search(policydb.p_classes.table, class); |
2222 | if (!match) { | 2342 | if (!match) { |
@@ -2244,11 +2364,11 @@ int security_get_permissions(char *class, char ***perms, int *nperms) | |||
2244 | goto err; | 2364 | goto err; |
2245 | 2365 | ||
2246 | out: | 2366 | out: |
2247 | POLICY_RDUNLOCK; | 2367 | read_unlock(&policy_rwlock); |
2248 | return rc; | 2368 | return rc; |
2249 | 2369 | ||
2250 | err: | 2370 | err: |
2251 | POLICY_RDUNLOCK; | 2371 | read_unlock(&policy_rwlock); |
2252 | for (i = 0; i < *nperms; i++) | 2372 | for (i = 0; i < *nperms; i++) |
2253 | kfree((*perms)[i]); | 2373 | kfree((*perms)[i]); |
2254 | kfree(*perms); | 2374 | kfree(*perms); |
@@ -2279,9 +2399,9 @@ int security_policycap_supported(unsigned int req_cap) | |||
2279 | { | 2399 | { |
2280 | int rc; | 2400 | int rc; |
2281 | 2401 | ||
2282 | POLICY_RDLOCK; | 2402 | read_lock(&policy_rwlock); |
2283 | rc = ebitmap_get_bit(&policydb.policycaps, req_cap); | 2403 | rc = ebitmap_get_bit(&policydb.policycaps, req_cap); |
2284 | POLICY_RDUNLOCK; | 2404 | read_unlock(&policy_rwlock); |
2285 | 2405 | ||
2286 | return rc; | 2406 | return rc; |
2287 | } | 2407 | } |
@@ -2345,7 +2465,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) | |||
2345 | 2465 | ||
2346 | context_init(&tmprule->au_ctxt); | 2466 | context_init(&tmprule->au_ctxt); |
2347 | 2467 | ||
2348 | POLICY_RDLOCK; | 2468 | read_lock(&policy_rwlock); |
2349 | 2469 | ||
2350 | tmprule->au_seqno = latest_granting; | 2470 | tmprule->au_seqno = latest_granting; |
2351 | 2471 | ||
@@ -2382,7 +2502,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) | |||
2382 | break; | 2502 | break; |
2383 | } | 2503 | } |
2384 | 2504 | ||
2385 | POLICY_RDUNLOCK; | 2505 | read_unlock(&policy_rwlock); |
2386 | 2506 | ||
2387 | if (rc) { | 2507 | if (rc) { |
2388 | selinux_audit_rule_free(tmprule); | 2508 | selinux_audit_rule_free(tmprule); |
@@ -2420,7 +2540,7 @@ int selinux_audit_rule_known(struct audit_krule *rule) | |||
2420 | } | 2540 | } |
2421 | 2541 | ||
2422 | int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, | 2542 | int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, |
2423 | struct audit_context *actx) | 2543 | struct audit_context *actx) |
2424 | { | 2544 | { |
2425 | struct context *ctxt; | 2545 | struct context *ctxt; |
2426 | struct mls_level *level; | 2546 | struct mls_level *level; |
@@ -2433,7 +2553,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, | |||
2433 | return -ENOENT; | 2553 | return -ENOENT; |
2434 | } | 2554 | } |
2435 | 2555 | ||
2436 | POLICY_RDLOCK; | 2556 | read_lock(&policy_rwlock); |
2437 | 2557 | ||
2438 | if (rule->au_seqno < latest_granting) { | 2558 | if (rule->au_seqno < latest_granting) { |
2439 | audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, | 2559 | audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, |
@@ -2527,14 +2647,14 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, | |||
2527 | } | 2647 | } |
2528 | 2648 | ||
2529 | out: | 2649 | out: |
2530 | POLICY_RDUNLOCK; | 2650 | read_unlock(&policy_rwlock); |
2531 | return match; | 2651 | return match; |
2532 | } | 2652 | } |
2533 | 2653 | ||
2534 | static int (*aurule_callback)(void) = audit_update_lsm_rules; | 2654 | static int (*aurule_callback)(void) = audit_update_lsm_rules; |
2535 | 2655 | ||
2536 | static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid, | 2656 | static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid, |
2537 | u16 class, u32 perms, u32 *retained) | 2657 | u16 class, u32 perms, u32 *retained) |
2538 | { | 2658 | { |
2539 | int err = 0; | 2659 | int err = 0; |
2540 | 2660 | ||
@@ -2615,7 +2735,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, | |||
2615 | return 0; | 2735 | return 0; |
2616 | } | 2736 | } |
2617 | 2737 | ||
2618 | POLICY_RDLOCK; | 2738 | read_lock(&policy_rwlock); |
2619 | 2739 | ||
2620 | if (secattr->flags & NETLBL_SECATTR_CACHE) { | 2740 | if (secattr->flags & NETLBL_SECATTR_CACHE) { |
2621 | *sid = *(u32 *)secattr->cache->data; | 2741 | *sid = *(u32 *)secattr->cache->data; |
@@ -2660,7 +2780,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, | |||
2660 | } | 2780 | } |
2661 | 2781 | ||
2662 | netlbl_secattr_to_sid_return: | 2782 | netlbl_secattr_to_sid_return: |
2663 | POLICY_RDUNLOCK; | 2783 | read_unlock(&policy_rwlock); |
2664 | return rc; | 2784 | return rc; |
2665 | netlbl_secattr_to_sid_return_cleanup: | 2785 | netlbl_secattr_to_sid_return_cleanup: |
2666 | ebitmap_destroy(&ctx_new.range.level[0].cat); | 2786 | ebitmap_destroy(&ctx_new.range.level[0].cat); |
@@ -2685,7 +2805,7 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) | |||
2685 | if (!ss_initialized) | 2805 | if (!ss_initialized) |
2686 | return 0; | 2806 | return 0; |
2687 | 2807 | ||
2688 | POLICY_RDLOCK; | 2808 | read_lock(&policy_rwlock); |
2689 | ctx = sidtab_search(&sidtab, sid); | 2809 | ctx = sidtab_search(&sidtab, sid); |
2690 | if (ctx == NULL) | 2810 | if (ctx == NULL) |
2691 | goto netlbl_sid_to_secattr_failure; | 2811 | goto netlbl_sid_to_secattr_failure; |
@@ -2696,12 +2816,12 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) | |||
2696 | rc = mls_export_netlbl_cat(ctx, secattr); | 2816 | rc = mls_export_netlbl_cat(ctx, secattr); |
2697 | if (rc != 0) | 2817 | if (rc != 0) |
2698 | goto netlbl_sid_to_secattr_failure; | 2818 | goto netlbl_sid_to_secattr_failure; |
2699 | POLICY_RDUNLOCK; | 2819 | read_unlock(&policy_rwlock); |
2700 | 2820 | ||
2701 | return 0; | 2821 | return 0; |
2702 | 2822 | ||
2703 | netlbl_sid_to_secattr_failure: | 2823 | netlbl_sid_to_secattr_failure: |
2704 | POLICY_RDUNLOCK; | 2824 | read_unlock(&policy_rwlock); |
2705 | return rc; | 2825 | return rc; |
2706 | } | 2826 | } |
2707 | #endif /* CONFIG_NETLABEL */ | 2827 | #endif /* CONFIG_NETLABEL */ |
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index 4a516ff4bcde..a81ded104129 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c | |||
@@ -14,10 +14,6 @@ | |||
14 | #define SIDTAB_HASH(sid) \ | 14 | #define SIDTAB_HASH(sid) \ |
15 | (sid & SIDTAB_HASH_MASK) | 15 | (sid & SIDTAB_HASH_MASK) |
16 | 16 | ||
17 | #define INIT_SIDTAB_LOCK(s) spin_lock_init(&s->lock) | ||
18 | #define SIDTAB_LOCK(s, x) spin_lock_irqsave(&s->lock, x) | ||
19 | #define SIDTAB_UNLOCK(s, x) spin_unlock_irqrestore(&s->lock, x) | ||
20 | |||
21 | int sidtab_init(struct sidtab *s) | 17 | int sidtab_init(struct sidtab *s) |
22 | { | 18 | { |
23 | int i; | 19 | int i; |
@@ -30,7 +26,7 @@ int sidtab_init(struct sidtab *s) | |||
30 | s->nel = 0; | 26 | s->nel = 0; |
31 | s->next_sid = 1; | 27 | s->next_sid = 1; |
32 | s->shutdown = 0; | 28 | s->shutdown = 0; |
33 | INIT_SIDTAB_LOCK(s); | 29 | spin_lock_init(&s->lock); |
34 | return 0; | 30 | return 0; |
35 | } | 31 | } |
36 | 32 | ||
@@ -86,7 +82,7 @@ out: | |||
86 | return rc; | 82 | return rc; |
87 | } | 83 | } |
88 | 84 | ||
89 | struct context *sidtab_search(struct sidtab *s, u32 sid) | 85 | static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force) |
90 | { | 86 | { |
91 | int hvalue; | 87 | int hvalue; |
92 | struct sidtab_node *cur; | 88 | struct sidtab_node *cur; |
@@ -99,7 +95,10 @@ struct context *sidtab_search(struct sidtab *s, u32 sid) | |||
99 | while (cur != NULL && sid > cur->sid) | 95 | while (cur != NULL && sid > cur->sid) |
100 | cur = cur->next; | 96 | cur = cur->next; |
101 | 97 | ||
102 | if (cur == NULL || sid != cur->sid) { | 98 | if (force && cur && sid == cur->sid && cur->context.len) |
99 | return &cur->context; | ||
100 | |||
101 | if (cur == NULL || sid != cur->sid || cur->context.len) { | ||
103 | /* Remap invalid SIDs to the unlabeled SID. */ | 102 | /* Remap invalid SIDs to the unlabeled SID. */ |
104 | sid = SECINITSID_UNLABELED; | 103 | sid = SECINITSID_UNLABELED; |
105 | hvalue = SIDTAB_HASH(sid); | 104 | hvalue = SIDTAB_HASH(sid); |
@@ -113,6 +112,16 @@ struct context *sidtab_search(struct sidtab *s, u32 sid) | |||
113 | return &cur->context; | 112 | return &cur->context; |
114 | } | 113 | } |
115 | 114 | ||
115 | struct context *sidtab_search(struct sidtab *s, u32 sid) | ||
116 | { | ||
117 | return sidtab_search_core(s, sid, 0); | ||
118 | } | ||
119 | |||
120 | struct context *sidtab_search_force(struct sidtab *s, u32 sid) | ||
121 | { | ||
122 | return sidtab_search_core(s, sid, 1); | ||
123 | } | ||
124 | |||
116 | int sidtab_map(struct sidtab *s, | 125 | int sidtab_map(struct sidtab *s, |
117 | int (*apply) (u32 sid, | 126 | int (*apply) (u32 sid, |
118 | struct context *context, | 127 | struct context *context, |
@@ -138,43 +147,6 @@ out: | |||
138 | return rc; | 147 | return rc; |
139 | } | 148 | } |
140 | 149 | ||
141 | void sidtab_map_remove_on_error(struct sidtab *s, | ||
142 | int (*apply) (u32 sid, | ||
143 | struct context *context, | ||
144 | void *args), | ||
145 | void *args) | ||
146 | { | ||
147 | int i, ret; | ||
148 | struct sidtab_node *last, *cur, *temp; | ||
149 | |||
150 | if (!s) | ||
151 | return; | ||
152 | |||
153 | for (i = 0; i < SIDTAB_SIZE; i++) { | ||
154 | last = NULL; | ||
155 | cur = s->htable[i]; | ||
156 | while (cur != NULL) { | ||
157 | ret = apply(cur->sid, &cur->context, args); | ||
158 | if (ret) { | ||
159 | if (last) | ||
160 | last->next = cur->next; | ||
161 | else | ||
162 | s->htable[i] = cur->next; | ||
163 | temp = cur; | ||
164 | cur = cur->next; | ||
165 | context_destroy(&temp->context); | ||
166 | kfree(temp); | ||
167 | s->nel--; | ||
168 | } else { | ||
169 | last = cur; | ||
170 | cur = cur->next; | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | |||
175 | return; | ||
176 | } | ||
177 | |||
178 | static inline u32 sidtab_search_context(struct sidtab *s, | 150 | static inline u32 sidtab_search_context(struct sidtab *s, |
179 | struct context *context) | 151 | struct context *context) |
180 | { | 152 | { |
@@ -204,7 +176,7 @@ int sidtab_context_to_sid(struct sidtab *s, | |||
204 | 176 | ||
205 | sid = sidtab_search_context(s, context); | 177 | sid = sidtab_search_context(s, context); |
206 | if (!sid) { | 178 | if (!sid) { |
207 | SIDTAB_LOCK(s, flags); | 179 | spin_lock_irqsave(&s->lock, flags); |
208 | /* Rescan now that we hold the lock. */ | 180 | /* Rescan now that we hold the lock. */ |
209 | sid = sidtab_search_context(s, context); | 181 | sid = sidtab_search_context(s, context); |
210 | if (sid) | 182 | if (sid) |
@@ -215,11 +187,15 @@ int sidtab_context_to_sid(struct sidtab *s, | |||
215 | goto unlock_out; | 187 | goto unlock_out; |
216 | } | 188 | } |
217 | sid = s->next_sid++; | 189 | sid = s->next_sid++; |
190 | if (context->len) | ||
191 | printk(KERN_INFO | ||
192 | "SELinux: Context %s is not valid (left unmapped).\n", | ||
193 | context->str); | ||
218 | ret = sidtab_insert(s, sid, context); | 194 | ret = sidtab_insert(s, sid, context); |
219 | if (ret) | 195 | if (ret) |
220 | s->next_sid--; | 196 | s->next_sid--; |
221 | unlock_out: | 197 | unlock_out: |
222 | SIDTAB_UNLOCK(s, flags); | 198 | spin_unlock_irqrestore(&s->lock, flags); |
223 | } | 199 | } |
224 | 200 | ||
225 | if (ret) | 201 | if (ret) |
@@ -284,19 +260,19 @@ void sidtab_set(struct sidtab *dst, struct sidtab *src) | |||
284 | { | 260 | { |
285 | unsigned long flags; | 261 | unsigned long flags; |
286 | 262 | ||
287 | SIDTAB_LOCK(src, flags); | 263 | spin_lock_irqsave(&src->lock, flags); |
288 | dst->htable = src->htable; | 264 | dst->htable = src->htable; |
289 | dst->nel = src->nel; | 265 | dst->nel = src->nel; |
290 | dst->next_sid = src->next_sid; | 266 | dst->next_sid = src->next_sid; |
291 | dst->shutdown = 0; | 267 | dst->shutdown = 0; |
292 | SIDTAB_UNLOCK(src, flags); | 268 | spin_unlock_irqrestore(&src->lock, flags); |
293 | } | 269 | } |
294 | 270 | ||
295 | void sidtab_shutdown(struct sidtab *s) | 271 | void sidtab_shutdown(struct sidtab *s) |
296 | { | 272 | { |
297 | unsigned long flags; | 273 | unsigned long flags; |
298 | 274 | ||
299 | SIDTAB_LOCK(s, flags); | 275 | spin_lock_irqsave(&s->lock, flags); |
300 | s->shutdown = 1; | 276 | s->shutdown = 1; |
301 | SIDTAB_UNLOCK(s, flags); | 277 | spin_unlock_irqrestore(&s->lock, flags); |
302 | } | 278 | } |
diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h index 2fe9dfa3eb3a..64ea5b1cdea4 100644 --- a/security/selinux/ss/sidtab.h +++ b/security/selinux/ss/sidtab.h | |||
@@ -32,6 +32,7 @@ struct sidtab { | |||
32 | int sidtab_init(struct sidtab *s); | 32 | int sidtab_init(struct sidtab *s); |
33 | int sidtab_insert(struct sidtab *s, u32 sid, struct context *context); | 33 | int sidtab_insert(struct sidtab *s, u32 sid, struct context *context); |
34 | struct context *sidtab_search(struct sidtab *s, u32 sid); | 34 | struct context *sidtab_search(struct sidtab *s, u32 sid); |
35 | struct context *sidtab_search_force(struct sidtab *s, u32 sid); | ||
35 | 36 | ||
36 | int sidtab_map(struct sidtab *s, | 37 | int sidtab_map(struct sidtab *s, |
37 | int (*apply) (u32 sid, | 38 | int (*apply) (u32 sid, |
@@ -39,12 +40,6 @@ int sidtab_map(struct sidtab *s, | |||
39 | void *args), | 40 | void *args), |
40 | void *args); | 41 | void *args); |
41 | 42 | ||
42 | void sidtab_map_remove_on_error(struct sidtab *s, | ||
43 | int (*apply) (u32 sid, | ||
44 | struct context *context, | ||
45 | void *args), | ||
46 | void *args); | ||
47 | |||
48 | int sidtab_context_to_sid(struct sidtab *s, | 43 | int sidtab_context_to_sid(struct sidtab *s, |
49 | struct context *context, | 44 | struct context *context, |
50 | u32 *sid); | 45 | u32 *sid); |