diff options
36 files changed, 995 insertions, 141 deletions
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index f5696ba9ae96..9d0058e788e5 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl | |||
@@ -283,6 +283,7 @@ X!Earch/x86/kernel/mca_32.c | |||
283 | <chapter id="security"> | 283 | <chapter id="security"> |
284 | <title>Security Framework</title> | 284 | <title>Security Framework</title> |
285 | !Isecurity/security.c | 285 | !Isecurity/security.c |
286 | !Esecurity/inode.c | ||
286 | </chapter> | 287 | </chapter> |
287 | 288 | ||
288 | <chapter id="audit"> | 289 | <chapter id="audit"> |
diff --git a/Documentation/SELinux.txt b/Documentation/SELinux.txt new file mode 100644 index 000000000000..07eae00f3314 --- /dev/null +++ b/Documentation/SELinux.txt | |||
@@ -0,0 +1,27 @@ | |||
1 | If you want to use SELinux, chances are you will want | ||
2 | to use the distro-provided policies, or install the | ||
3 | latest reference policy release from | ||
4 | http://oss.tresys.com/projects/refpolicy | ||
5 | |||
6 | However, if you want to install a dummy policy for | ||
7 | testing, you can do using 'mdp' provided under | ||
8 | scripts/selinux. Note that this requires the selinux | ||
9 | userspace to be installed - in particular you will | ||
10 | need checkpolicy to compile a kernel, and setfiles and | ||
11 | fixfiles to label the filesystem. | ||
12 | |||
13 | 1. Compile the kernel with selinux enabled. | ||
14 | 2. Type 'make' to compile mdp. | ||
15 | 3. Make sure that you are not running with | ||
16 | SELinux enabled and a real policy. If | ||
17 | you are, reboot with selinux disabled | ||
18 | before continuing. | ||
19 | 4. Run install_policy.sh: | ||
20 | cd scripts/selinux | ||
21 | sh install_policy.sh | ||
22 | |||
23 | Step 4 will create a new dummy policy valid for your | ||
24 | kernel, with a single selinux user, role, and type. | ||
25 | It will compile the policy, will set your SELINUXTYPE to | ||
26 | dummy in /etc/selinux/config, install the compiled policy | ||
27 | as 'dummy', and relabel your filesystem. | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 8dae4555f10e..7a03bd5a91a3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -3649,8 +3649,9 @@ M: jmorris@namei.org | |||
3649 | P: Eric Paris | 3649 | P: Eric Paris |
3650 | M: eparis@parisplace.org | 3650 | M: eparis@parisplace.org |
3651 | L: linux-kernel@vger.kernel.org (kernel issues) | 3651 | L: linux-kernel@vger.kernel.org (kernel issues) |
3652 | L: selinux@tycho.nsa.gov (subscribers-only, general discussion) | 3652 | L: selinux@tycho.nsa.gov (subscribers-only, general discussion) |
3653 | W: http://www.nsa.gov/selinux | 3653 | W: http://selinuxproject.org |
3654 | T: git kernel.org:pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git | ||
3654 | S: Supported | 3655 | S: Supported |
3655 | 3656 | ||
3656 | SENSABLE PHANTOM | 3657 | SENSABLE PHANTOM |
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 3738cfa209ff..f5fc64f89c5c 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig | |||
@@ -6,6 +6,7 @@ menuconfig TCG_TPM | |||
6 | tristate "TPM Hardware Support" | 6 | tristate "TPM Hardware Support" |
7 | depends on HAS_IOMEM | 7 | depends on HAS_IOMEM |
8 | depends on EXPERIMENTAL | 8 | depends on EXPERIMENTAL |
9 | select SECURITYFS | ||
9 | ---help--- | 10 | ---help--- |
10 | If you have a TPM security chip in your system, which | 11 | If you have a TPM security chip in your system, which |
11 | implements the Trusted Computing Group's specification, | 12 | implements the Trusted Computing Group's specification, |
diff --git a/include/linux/security.h b/include/linux/security.h index 80c4d002864c..f5c4a51eb42e 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -1560,11 +1560,6 @@ struct security_operations { | |||
1560 | extern int security_init(void); | 1560 | extern int security_init(void); |
1561 | extern int security_module_enable(struct security_operations *ops); | 1561 | extern int security_module_enable(struct security_operations *ops); |
1562 | extern int register_security(struct security_operations *ops); | 1562 | extern int register_security(struct security_operations *ops); |
1563 | extern struct dentry *securityfs_create_file(const char *name, mode_t mode, | ||
1564 | struct dentry *parent, void *data, | ||
1565 | const struct file_operations *fops); | ||
1566 | extern struct dentry *securityfs_create_dir(const char *name, struct dentry *parent); | ||
1567 | extern void securityfs_remove(struct dentry *dentry); | ||
1568 | 1563 | ||
1569 | /* Security operations */ | 1564 | /* Security operations */ |
1570 | int security_ptrace_may_access(struct task_struct *child, unsigned int mode); | 1565 | int security_ptrace_may_access(struct task_struct *child, unsigned int mode); |
@@ -2424,25 +2419,6 @@ static inline int security_netlink_recv(struct sk_buff *skb, int cap) | |||
2424 | return cap_netlink_recv(skb, cap); | 2419 | return cap_netlink_recv(skb, cap); |
2425 | } | 2420 | } |
2426 | 2421 | ||
2427 | static inline struct dentry *securityfs_create_dir(const char *name, | ||
2428 | struct dentry *parent) | ||
2429 | { | ||
2430 | return ERR_PTR(-ENODEV); | ||
2431 | } | ||
2432 | |||
2433 | static inline struct dentry *securityfs_create_file(const char *name, | ||
2434 | mode_t mode, | ||
2435 | struct dentry *parent, | ||
2436 | void *data, | ||
2437 | const struct file_operations *fops) | ||
2438 | { | ||
2439 | return ERR_PTR(-ENODEV); | ||
2440 | } | ||
2441 | |||
2442 | static inline void securityfs_remove(struct dentry *dentry) | ||
2443 | { | ||
2444 | } | ||
2445 | |||
2446 | static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) | 2422 | static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) |
2447 | { | 2423 | { |
2448 | return -EOPNOTSUPP; | 2424 | return -EOPNOTSUPP; |
@@ -2806,5 +2782,35 @@ static inline void security_audit_rule_free(void *lsmrule) | |||
2806 | #endif /* CONFIG_SECURITY */ | 2782 | #endif /* CONFIG_SECURITY */ |
2807 | #endif /* CONFIG_AUDIT */ | 2783 | #endif /* CONFIG_AUDIT */ |
2808 | 2784 | ||
2785 | #ifdef CONFIG_SECURITYFS | ||
2786 | |||
2787 | extern struct dentry *securityfs_create_file(const char *name, mode_t mode, | ||
2788 | struct dentry *parent, void *data, | ||
2789 | const struct file_operations *fops); | ||
2790 | extern struct dentry *securityfs_create_dir(const char *name, struct dentry *parent); | ||
2791 | extern void securityfs_remove(struct dentry *dentry); | ||
2792 | |||
2793 | #else /* CONFIG_SECURITYFS */ | ||
2794 | |||
2795 | static inline struct dentry *securityfs_create_dir(const char *name, | ||
2796 | struct dentry *parent) | ||
2797 | { | ||
2798 | return ERR_PTR(-ENODEV); | ||
2799 | } | ||
2800 | |||
2801 | static inline struct dentry *securityfs_create_file(const char *name, | ||
2802 | mode_t mode, | ||
2803 | struct dentry *parent, | ||
2804 | void *data, | ||
2805 | const struct file_operations *fops) | ||
2806 | { | ||
2807 | return ERR_PTR(-ENODEV); | ||
2808 | } | ||
2809 | |||
2810 | static inline void securityfs_remove(struct dentry *dentry) | ||
2811 | {} | ||
2812 | |||
2813 | #endif | ||
2814 | |||
2809 | #endif /* ! __LINUX_SECURITY_H */ | 2815 | #endif /* ! __LINUX_SECURITY_H */ |
2810 | 2816 | ||
diff --git a/scripts/Makefile b/scripts/Makefile index 1c73c5aea66b..aafdf064feef 100644 --- a/scripts/Makefile +++ b/scripts/Makefile | |||
@@ -20,6 +20,7 @@ hostprogs-y += unifdef | |||
20 | 20 | ||
21 | subdir-$(CONFIG_MODVERSIONS) += genksyms | 21 | subdir-$(CONFIG_MODVERSIONS) += genksyms |
22 | subdir-y += mod | 22 | subdir-y += mod |
23 | subdir-$(CONFIG_SECURITY_SELINUX) += selinux | ||
23 | 24 | ||
24 | # Let clean descend into subdirs | 25 | # Let clean descend into subdirs |
25 | subdir- += basic kconfig package | 26 | subdir- += basic kconfig package selinux |
diff --git a/scripts/selinux/Makefile b/scripts/selinux/Makefile new file mode 100644 index 000000000000..ca4b1ec01822 --- /dev/null +++ b/scripts/selinux/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | subdir-y := mdp | ||
2 | subdir- += mdp | ||
diff --git a/scripts/selinux/README b/scripts/selinux/README new file mode 100644 index 000000000000..a936315ba2c8 --- /dev/null +++ b/scripts/selinux/README | |||
@@ -0,0 +1,2 @@ | |||
1 | Please see Documentation/SELinux.txt for information on | ||
2 | installing a dummy SELinux policy. | ||
diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh new file mode 100644 index 000000000000..7b9ccf61f8f9 --- /dev/null +++ b/scripts/selinux/install_policy.sh | |||
@@ -0,0 +1,69 @@ | |||
1 | #!/bin/sh | ||
2 | if [ `id -u` -ne 0 ]; then | ||
3 | echo "$0: must be root to install the selinux policy" | ||
4 | exit 1 | ||
5 | fi | ||
6 | SF=`which setfiles` | ||
7 | if [ $? -eq 1 ]; then | ||
8 | if [ -f /sbin/setfiles ]; then | ||
9 | SF="/usr/setfiles" | ||
10 | else | ||
11 | echo "no selinux tools installed: setfiles" | ||
12 | exit 1 | ||
13 | fi | ||
14 | fi | ||
15 | |||
16 | cd mdp | ||
17 | |||
18 | CP=`which checkpolicy` | ||
19 | VERS=`$CP -V | awk '{print $1}'` | ||
20 | |||
21 | ./mdp policy.conf file_contexts | ||
22 | $CP -o policy.$VERS policy.conf | ||
23 | |||
24 | mkdir -p /etc/selinux/dummy/policy | ||
25 | mkdir -p /etc/selinux/dummy/contexts/files | ||
26 | |||
27 | cp file_contexts /etc/selinux/dummy/contexts/files | ||
28 | cp dbus_contexts /etc/selinux/dummy/contexts | ||
29 | cp policy.$VERS /etc/selinux/dummy/policy | ||
30 | FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts | ||
31 | |||
32 | if [ ! -d /etc/selinux ]; then | ||
33 | mkdir -p /etc/selinux | ||
34 | fi | ||
35 | if [ ! -f /etc/selinux/config ]; then | ||
36 | cat > /etc/selinux/config << EOF | ||
37 | SELINUX=enforcing | ||
38 | SELINUXTYPE=dummy | ||
39 | EOF | ||
40 | else | ||
41 | TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}` | ||
42 | if [ "eq$TYPE" != "eqdummy" ]; then | ||
43 | selinuxenabled | ||
44 | if [ $? -eq 0 ]; then | ||
45 | echo "SELinux already enabled with a non-dummy policy." | ||
46 | echo "Exiting. Please install policy by hand if that" | ||
47 | echo "is what you REALLY want." | ||
48 | exit 1 | ||
49 | fi | ||
50 | mv /etc/selinux/config /etc/selinux/config.mdpbak | ||
51 | grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config | ||
52 | echo "SELINUXTYPE=dummy" >> /etc/selinux/config | ||
53 | fi | ||
54 | fi | ||
55 | |||
56 | cd /etc/selinux/dummy/contexts/files | ||
57 | $SF file_contexts / | ||
58 | |||
59 | mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}` | ||
60 | $SF file_contexts $mounts | ||
61 | |||
62 | |||
63 | dodev=`cat /proc/$$/mounts | grep "/dev "` | ||
64 | if [ "eq$dodev" != "eq" ]; then | ||
65 | mount --move /dev /mnt | ||
66 | $SF file_contexts /dev | ||
67 | mount --move /mnt /dev | ||
68 | fi | ||
69 | |||
diff --git a/scripts/selinux/mdp/.gitignore b/scripts/selinux/mdp/.gitignore new file mode 100644 index 000000000000..654546d8dffd --- /dev/null +++ b/scripts/selinux/mdp/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | # Generated file | ||
2 | mdp | ||
diff --git a/scripts/selinux/mdp/Makefile b/scripts/selinux/mdp/Makefile new file mode 100644 index 000000000000..eb365b333441 --- /dev/null +++ b/scripts/selinux/mdp/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | hostprogs-y := mdp | ||
2 | HOST_EXTRACFLAGS += -Isecurity/selinux/include | ||
3 | |||
4 | always := $(hostprogs-y) | ||
5 | clean-files := $(hostprogs-y) policy.* file_contexts | ||
diff --git a/scripts/selinux/mdp/dbus_contexts b/scripts/selinux/mdp/dbus_contexts new file mode 100644 index 000000000000..116e684f9fc1 --- /dev/null +++ b/scripts/selinux/mdp/dbus_contexts | |||
@@ -0,0 +1,6 @@ | |||
1 | <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" | ||
2 | "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> | ||
3 | <busconfig> | ||
4 | <selinux> | ||
5 | </selinux> | ||
6 | </busconfig> | ||
diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c new file mode 100644 index 000000000000..ca757d486187 --- /dev/null +++ b/scripts/selinux/mdp/mdp.c | |||
@@ -0,0 +1,242 @@ | |||
1 | /* | ||
2 | * | ||
3 | * mdp - make dummy policy | ||
4 | * | ||
5 | * When pointed at a kernel tree, builds a dummy policy for that kernel | ||
6 | * with exactly one type with full rights to itself. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | * | ||
22 | * Copyright (C) IBM Corporation, 2006 | ||
23 | * | ||
24 | * Authors: Serge E. Hallyn <serue@us.ibm.com> | ||
25 | */ | ||
26 | |||
27 | #include <stdio.h> | ||
28 | #include <stdlib.h> | ||
29 | #include <unistd.h> | ||
30 | #include <string.h> | ||
31 | |||
32 | #include "flask.h" | ||
33 | |||
34 | void usage(char *name) | ||
35 | { | ||
36 | printf("usage: %s [-m] policy_file context_file\n", name); | ||
37 | exit(1); | ||
38 | } | ||
39 | |||
40 | void find_common_name(char *cname, char *dest, int len) | ||
41 | { | ||
42 | char *start, *end; | ||
43 | |||
44 | start = strchr(cname, '_')+1; | ||
45 | end = strchr(start, '_'); | ||
46 | if (!start || !end || start-cname > len || end-start > len) { | ||
47 | printf("Error with commons defines\n"); | ||
48 | exit(1); | ||
49 | } | ||
50 | strncpy(dest, start, end-start); | ||
51 | dest[end-start] = '\0'; | ||
52 | } | ||
53 | |||
54 | #define S_(x) x, | ||
55 | static char *classlist[] = { | ||
56 | #include "class_to_string.h" | ||
57 | NULL | ||
58 | }; | ||
59 | #undef S_ | ||
60 | |||
61 | #include "initial_sid_to_string.h" | ||
62 | |||
63 | #define TB_(x) char *x[] = { | ||
64 | #define TE_(x) NULL }; | ||
65 | #define S_(x) x, | ||
66 | #include "common_perm_to_string.h" | ||
67 | #undef TB_ | ||
68 | #undef TE_ | ||
69 | #undef S_ | ||
70 | |||
71 | struct common { | ||
72 | char *cname; | ||
73 | char **perms; | ||
74 | }; | ||
75 | struct common common[] = { | ||
76 | #define TB_(x) { #x, x }, | ||
77 | #define S_(x) | ||
78 | #define TE_(x) | ||
79 | #include "common_perm_to_string.h" | ||
80 | #undef TB_ | ||
81 | #undef TE_ | ||
82 | #undef S_ | ||
83 | }; | ||
84 | |||
85 | #define S_(x, y, z) {x, #y}, | ||
86 | struct av_inherit { | ||
87 | int class; | ||
88 | char *common; | ||
89 | }; | ||
90 | struct av_inherit av_inherit[] = { | ||
91 | #include "av_inherit.h" | ||
92 | }; | ||
93 | #undef S_ | ||
94 | |||
95 | #include "av_permissions.h" | ||
96 | #define S_(x, y, z) {x, y, z}, | ||
97 | struct av_perms { | ||
98 | int class; | ||
99 | int perm_i; | ||
100 | char *perm_s; | ||
101 | }; | ||
102 | struct av_perms av_perms[] = { | ||
103 | #include "av_perm_to_string.h" | ||
104 | }; | ||
105 | #undef S_ | ||
106 | |||
107 | int main(int argc, char *argv[]) | ||
108 | { | ||
109 | int i, j, mls = 0; | ||
110 | char **arg, *polout, *ctxout; | ||
111 | int classlist_len, initial_sid_to_string_len; | ||
112 | FILE *fout; | ||
113 | |||
114 | if (argc < 3) | ||
115 | usage(argv[0]); | ||
116 | arg = argv+1; | ||
117 | if (argc==4 && strcmp(argv[1], "-m") == 0) { | ||
118 | mls = 1; | ||
119 | arg++; | ||
120 | } | ||
121 | polout = *arg++; | ||
122 | ctxout = *arg; | ||
123 | |||
124 | fout = fopen(polout, "w"); | ||
125 | if (!fout) { | ||
126 | printf("Could not open %s for writing\n", polout); | ||
127 | usage(argv[0]); | ||
128 | } | ||
129 | |||
130 | classlist_len = sizeof(classlist) / sizeof(char *); | ||
131 | /* print out the classes */ | ||
132 | for (i=1; i < classlist_len; i++) { | ||
133 | if(classlist[i]) | ||
134 | fprintf(fout, "class %s\n", classlist[i]); | ||
135 | else | ||
136 | fprintf(fout, "class user%d\n", i); | ||
137 | } | ||
138 | fprintf(fout, "\n"); | ||
139 | |||
140 | initial_sid_to_string_len = sizeof(initial_sid_to_string) / sizeof (char *); | ||
141 | /* print out the sids */ | ||
142 | for (i=1; i < initial_sid_to_string_len; i++) | ||
143 | fprintf(fout, "sid %s\n", initial_sid_to_string[i]); | ||
144 | fprintf(fout, "\n"); | ||
145 | |||
146 | /* print out the commons */ | ||
147 | for (i=0; i< sizeof(common)/sizeof(struct common); i++) { | ||
148 | char cname[101]; | ||
149 | find_common_name(common[i].cname, cname, 100); | ||
150 | cname[100] = '\0'; | ||
151 | fprintf(fout, "common %s\n{\n", cname); | ||
152 | for (j=0; common[i].perms[j]; j++) | ||
153 | fprintf(fout, "\t%s\n", common[i].perms[j]); | ||
154 | fprintf(fout, "}\n\n"); | ||
155 | } | ||
156 | fprintf(fout, "\n"); | ||
157 | |||
158 | /* print out the class permissions */ | ||
159 | for (i=1; i < classlist_len; i++) { | ||
160 | if (classlist[i]) { | ||
161 | int firstperm = -1, numperms = 0; | ||
162 | |||
163 | fprintf(fout, "class %s\n", classlist[i]); | ||
164 | /* does it inherit from a common? */ | ||
165 | for (j=0; j < sizeof(av_inherit)/sizeof(struct av_inherit); j++) | ||
166 | if (av_inherit[j].class == i) | ||
167 | fprintf(fout, "inherits %s\n", av_inherit[j].common); | ||
168 | |||
169 | for (j=0; j < sizeof(av_perms)/sizeof(struct av_perms); j++) { | ||
170 | if (av_perms[j].class == i) { | ||
171 | if (firstperm == -1) | ||
172 | firstperm = j; | ||
173 | numperms++; | ||
174 | } | ||
175 | } | ||
176 | if (!numperms) { | ||
177 | fprintf(fout, "\n"); | ||
178 | continue; | ||
179 | } | ||
180 | |||
181 | fprintf(fout, "{\n"); | ||
182 | /* print out the av_perms */ | ||
183 | for (j=0; j < numperms; j++) { | ||
184 | fprintf(fout, "\t%s\n", av_perms[firstperm+j].perm_s); | ||
185 | } | ||
186 | fprintf(fout, "}\n\n"); | ||
187 | } | ||
188 | } | ||
189 | fprintf(fout, "\n"); | ||
190 | |||
191 | /* NOW PRINT OUT MLS STUFF */ | ||
192 | if (mls) { | ||
193 | printf("MLS not yet implemented\n"); | ||
194 | exit(1); | ||
195 | } | ||
196 | |||
197 | /* types, roles, and allows */ | ||
198 | fprintf(fout, "type base_t;\n"); | ||
199 | fprintf(fout, "role base_r types { base_t };\n"); | ||
200 | for (i=1; i < classlist_len; i++) { | ||
201 | if (classlist[i]) | ||
202 | fprintf(fout, "allow base_t base_t:%s *;\n", classlist[i]); | ||
203 | else | ||
204 | fprintf(fout, "allow base_t base_t:user%d *;\n", i); | ||
205 | } | ||
206 | fprintf(fout, "user user_u roles { base_r };\n"); | ||
207 | fprintf(fout, "\n"); | ||
208 | |||
209 | /* default sids */ | ||
210 | for (i=1; i < initial_sid_to_string_len; i++) | ||
211 | fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]); | ||
212 | fprintf(fout, "\n"); | ||
213 | |||
214 | |||
215 | fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n"); | ||
216 | fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n"); | ||
217 | fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n"); | ||
218 | fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n"); | ||
219 | fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n"); | ||
220 | |||
221 | fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n"); | ||
222 | fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n"); | ||
223 | |||
224 | fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n"); | ||
225 | fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n"); | ||
226 | fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n"); | ||
227 | |||
228 | fprintf(fout, "genfscon proc / user_u:base_r:base_t\n"); | ||
229 | |||
230 | fclose(fout); | ||
231 | |||
232 | fout = fopen(ctxout, "w"); | ||
233 | if (!fout) { | ||
234 | printf("Wrote policy, but cannot open %s for writing\n", ctxout); | ||
235 | usage(argv[0]); | ||
236 | } | ||
237 | fprintf(fout, "/ user_u:base_r:base_t\n"); | ||
238 | fprintf(fout, "/.* user_u:base_r:base_t\n"); | ||
239 | fclose(fout); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
diff --git a/security/Kconfig b/security/Kconfig index 559293922a47..d9f47ce7e207 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
@@ -51,6 +51,14 @@ config SECURITY | |||
51 | 51 | ||
52 | If you are unsure how to answer this question, answer N. | 52 | If you are unsure how to answer this question, answer N. |
53 | 53 | ||
54 | config SECURITYFS | ||
55 | bool "Enable the securityfs filesystem" | ||
56 | help | ||
57 | This will build the securityfs filesystem. It is currently used by | ||
58 | the TPM bios character driver. It is not used by SELinux or SMACK. | ||
59 | |||
60 | If you are unsure how to answer this question, answer N. | ||
61 | |||
54 | config SECURITY_NETWORK | 62 | config SECURITY_NETWORK |
55 | bool "Socket and Networking Security Hooks" | 63 | bool "Socket and Networking Security Hooks" |
56 | depends on SECURITY | 64 | depends on SECURITY |
diff --git a/security/Makefile b/security/Makefile index f65426099aa6..c05c127fff9a 100644 --- a/security/Makefile +++ b/security/Makefile | |||
@@ -10,7 +10,8 @@ subdir-$(CONFIG_SECURITY_SMACK) += smack | |||
10 | obj-y += commoncap.o | 10 | obj-y += commoncap.o |
11 | 11 | ||
12 | # Object file lists | 12 | # Object file lists |
13 | obj-$(CONFIG_SECURITY) += security.o capability.o inode.o | 13 | obj-$(CONFIG_SECURITY) += security.o capability.o |
14 | obj-$(CONFIG_SECURITYFS) += inode.o | ||
14 | # Must precede capability.o in order to stack properly. | 15 | # Must precede capability.o in order to stack properly. |
15 | obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o | 16 | obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o |
16 | obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o | 17 | obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o |
diff --git a/security/commoncap.c b/security/commoncap.c index e4c4b3fc0c04..399bfdb9e2da 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -541,7 +541,7 @@ int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, | |||
541 | * yet with increased caps. | 541 | * yet with increased caps. |
542 | * So we check for increased caps on the target process. | 542 | * So we check for increased caps on the target process. |
543 | */ | 543 | */ |
544 | static inline int cap_safe_nice(struct task_struct *p) | 544 | static int cap_safe_nice(struct task_struct *p) |
545 | { | 545 | { |
546 | if (!cap_issubset(p->cap_permitted, current->cap_permitted) && | 546 | if (!cap_issubset(p->cap_permitted, current->cap_permitted) && |
547 | !capable(CAP_SYS_NICE)) | 547 | !capable(CAP_SYS_NICE)) |
diff --git a/security/inode.c b/security/inode.c index acc6cf0d7900..ca4958ebad8d 100644 --- a/security/inode.c +++ b/security/inode.c | |||
@@ -190,7 +190,7 @@ static int create_by_name(const char *name, mode_t mode, | |||
190 | * @name: a pointer to a string containing the name of the file to create. | 190 | * @name: a pointer to a string containing the name of the file to create. |
191 | * @mode: the permission that the file should have | 191 | * @mode: the permission that the file should have |
192 | * @parent: a pointer to the parent dentry for this file. This should be a | 192 | * @parent: a pointer to the parent dentry for this file. This should be a |
193 | * directory dentry if set. If this paramater is NULL, then the | 193 | * directory dentry if set. If this parameter is %NULL, then the |
194 | * file will be created in the root of the securityfs filesystem. | 194 | * file will be created in the root of the securityfs filesystem. |
195 | * @data: a pointer to something that the caller will want to get to later | 195 | * @data: a pointer to something that the caller will want to get to later |
196 | * on. The inode.i_private pointer will point to this value on | 196 | * on. The inode.i_private pointer will point to this value on |
@@ -199,18 +199,18 @@ static int create_by_name(const char *name, mode_t mode, | |||
199 | * this file. | 199 | * this file. |
200 | * | 200 | * |
201 | * This is the basic "create a file" function for securityfs. It allows for a | 201 | * This is the basic "create a file" function for securityfs. It allows for a |
202 | * wide range of flexibility in createing a file, or a directory (if you | 202 | * wide range of flexibility in creating a file, or a directory (if you |
203 | * want to create a directory, the securityfs_create_dir() function is | 203 | * want to create a directory, the securityfs_create_dir() function is |
204 | * recommended to be used instead.) | 204 | * recommended to be used instead). |
205 | * | 205 | * |
206 | * This function will return a pointer to a dentry if it succeeds. This | 206 | * This function returns a pointer to a dentry if it succeeds. This |
207 | * pointer must be passed to the securityfs_remove() function when the file is | 207 | * pointer must be passed to the securityfs_remove() function when the file is |
208 | * to be removed (no automatic cleanup happens if your module is unloaded, | 208 | * to be removed (no automatic cleanup happens if your module is unloaded, |
209 | * you are responsible here.) If an error occurs, NULL will be returned. | 209 | * you are responsible here). If an error occurs, %NULL is returned. |
210 | * | 210 | * |
211 | * If securityfs is not enabled in the kernel, the value -ENODEV will be | 211 | * If securityfs is not enabled in the kernel, the value %-ENODEV is |
212 | * returned. It is not wise to check for this value, but rather, check for | 212 | * returned. It is not wise to check for this value, but rather, check for |
213 | * NULL or !NULL instead as to eliminate the need for #ifdef in the calling | 213 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
214 | * code. | 214 | * code. |
215 | */ | 215 | */ |
216 | struct dentry *securityfs_create_file(const char *name, mode_t mode, | 216 | struct dentry *securityfs_create_file(const char *name, mode_t mode, |
@@ -252,19 +252,19 @@ EXPORT_SYMBOL_GPL(securityfs_create_file); | |||
252 | * @name: a pointer to a string containing the name of the directory to | 252 | * @name: a pointer to a string containing the name of the directory to |
253 | * create. | 253 | * create. |
254 | * @parent: a pointer to the parent dentry for this file. This should be a | 254 | * @parent: a pointer to the parent dentry for this file. This should be a |
255 | * directory dentry if set. If this paramater is NULL, then the | 255 | * directory dentry if set. If this parameter is %NULL, then the |
256 | * directory will be created in the root of the securityfs filesystem. | 256 | * directory will be created in the root of the securityfs filesystem. |
257 | * | 257 | * |
258 | * This function creates a directory in securityfs with the given name. | 258 | * This function creates a directory in securityfs with the given @name. |
259 | * | 259 | * |
260 | * This function will return a pointer to a dentry if it succeeds. This | 260 | * This function returns a pointer to a dentry if it succeeds. This |
261 | * pointer must be passed to the securityfs_remove() function when the file is | 261 | * pointer must be passed to the securityfs_remove() function when the file is |
262 | * to be removed (no automatic cleanup happens if your module is unloaded, | 262 | * to be removed (no automatic cleanup happens if your module is unloaded, |
263 | * you are responsible here.) If an error occurs, NULL will be returned. | 263 | * you are responsible here). If an error occurs, %NULL will be returned. |
264 | * | 264 | * |
265 | * If securityfs is not enabled in the kernel, the value -ENODEV will be | 265 | * If securityfs is not enabled in the kernel, the value %-ENODEV is |
266 | * returned. It is not wise to check for this value, but rather, check for | 266 | * returned. It is not wise to check for this value, but rather, check for |
267 | * NULL or !NULL instead as to eliminate the need for #ifdef in the calling | 267 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
268 | * code. | 268 | * code. |
269 | */ | 269 | */ |
270 | struct dentry *securityfs_create_dir(const char *name, struct dentry *parent) | 270 | struct dentry *securityfs_create_dir(const char *name, struct dentry *parent) |
@@ -278,16 +278,15 @@ EXPORT_SYMBOL_GPL(securityfs_create_dir); | |||
278 | /** | 278 | /** |
279 | * securityfs_remove - removes a file or directory from the securityfs filesystem | 279 | * securityfs_remove - removes a file or directory from the securityfs filesystem |
280 | * | 280 | * |
281 | * @dentry: a pointer to a the dentry of the file or directory to be | 281 | * @dentry: a pointer to a the dentry of the file or directory to be removed. |
282 | * removed. | ||
283 | * | 282 | * |
284 | * This function removes a file or directory in securityfs that was previously | 283 | * This function removes a file or directory in securityfs that was previously |
285 | * created with a call to another securityfs function (like | 284 | * created with a call to another securityfs function (like |
286 | * securityfs_create_file() or variants thereof.) | 285 | * securityfs_create_file() or variants thereof.) |
287 | * | 286 | * |
288 | * This function is required to be called in order for the file to be | 287 | * This function is required to be called in order for the file to be |
289 | * removed, no automatic cleanup of files will happen when a module is | 288 | * removed. No automatic cleanup of files will happen when a module is |
290 | * removed, you are responsible here. | 289 | * removed; you are responsible here. |
291 | */ | 290 | */ |
292 | void securityfs_remove(struct dentry *dentry) | 291 | void securityfs_remove(struct dentry *dentry) |
293 | { | 292 | { |
diff --git a/security/security.c b/security/security.c index 3a4b4f55b33f..255b08559b2b 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -82,8 +82,8 @@ __setup("security=", choose_lsm); | |||
82 | * | 82 | * |
83 | * Return true if: | 83 | * Return true if: |
84 | * -The passed LSM is the one chosen by user at boot time, | 84 | * -The passed LSM is the one chosen by user at boot time, |
85 | * -or user didsn't specify a specific LSM and we're the first to ask | 85 | * -or user didn't specify a specific LSM and we're the first to ask |
86 | * for registeration permissoin, | 86 | * for registration permission, |
87 | * -or the passed LSM is currently loaded. | 87 | * -or the passed LSM is currently loaded. |
88 | * Otherwise, return false. | 88 | * Otherwise, return false. |
89 | */ | 89 | */ |
@@ -101,13 +101,13 @@ int __init security_module_enable(struct security_operations *ops) | |||
101 | * register_security - registers a security framework with the kernel | 101 | * register_security - registers a security framework with the kernel |
102 | * @ops: a pointer to the struct security_options that is to be registered | 102 | * @ops: a pointer to the struct security_options that is to be registered |
103 | * | 103 | * |
104 | * This function is to allow a security module to register itself with the | 104 | * This function allows a security module to register itself with the |
105 | * kernel security subsystem. Some rudimentary checking is done on the @ops | 105 | * kernel security subsystem. Some rudimentary checking is done on the @ops |
106 | * value passed to this function. You'll need to check first if your LSM | 106 | * value passed to this function. You'll need to check first if your LSM |
107 | * is allowed to register its @ops by calling security_module_enable(@ops). | 107 | * is allowed to register its @ops by calling security_module_enable(@ops). |
108 | * | 108 | * |
109 | * If there is already a security module registered with the kernel, | 109 | * If there is already a security module registered with the kernel, |
110 | * an error will be returned. Otherwise 0 is returned on success. | 110 | * an error will be returned. Otherwise %0 is returned on success. |
111 | */ | 111 | */ |
112 | int register_security(struct security_operations *ops) | 112 | int register_security(struct security_operations *ops) |
113 | { | 113 | { |
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index a436d1cfa88b..26301dd651d3 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig | |||
@@ -6,9 +6,6 @@ config SECURITY_SELINUX | |||
6 | help | 6 | help |
7 | This selects NSA Security-Enhanced Linux (SELinux). | 7 | This selects NSA Security-Enhanced Linux (SELinux). |
8 | You will also need a policy configuration and a labeled filesystem. | 8 | You will also need a policy configuration and a labeled filesystem. |
9 | You can obtain the policy compiler (checkpolicy), the utility for | ||
10 | labeling filesystems (setfiles), and an example policy configuration | ||
11 | from <http://www.nsa.gov/selinux/>. | ||
12 | If you are unsure how to answer this question, answer N. | 9 | If you are unsure how to answer this question, answer N. |
13 | 10 | ||
14 | config SECURITY_SELINUX_BOOTPARAM | 11 | config SECURITY_SELINUX_BOOTPARAM |
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 114b4b4c97b2..cb30c7e350b3 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -136,7 +136,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) | |||
136 | * @tclass: target security class | 136 | * @tclass: target security class |
137 | * @av: access vector | 137 | * @av: access vector |
138 | */ | 138 | */ |
139 | static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) | 139 | void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) |
140 | { | 140 | { |
141 | const char **common_pts = NULL; | 141 | const char **common_pts = NULL; |
142 | u32 common_base = 0; | 142 | u32 common_base = 0; |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 03fc6a81ae32..4a7374c12d9c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -957,7 +957,8 @@ out_err: | |||
957 | return rc; | 957 | return rc; |
958 | } | 958 | } |
959 | 959 | ||
960 | void selinux_write_opts(struct seq_file *m, struct security_mnt_opts *opts) | 960 | static void selinux_write_opts(struct seq_file *m, |
961 | struct security_mnt_opts *opts) | ||
961 | { | 962 | { |
962 | int i; | 963 | int i; |
963 | char *prefix; | 964 | char *prefix; |
@@ -1290,7 +1291,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1290 | /* Default to the fs superblock SID. */ | 1291 | /* Default to the fs superblock SID. */ |
1291 | isec->sid = sbsec->sid; | 1292 | isec->sid = sbsec->sid; |
1292 | 1293 | ||
1293 | if (sbsec->proc) { | 1294 | if (sbsec->proc && !S_ISLNK(inode->i_mode)) { |
1294 | struct proc_inode *proci = PROC_I(inode); | 1295 | struct proc_inode *proci = PROC_I(inode); |
1295 | if (proci->pde) { | 1296 | if (proci->pde) { |
1296 | isec->sclass = inode_mode_to_security_class(inode->i_mode); | 1297 | isec->sclass = inode_mode_to_security_class(inode->i_mode); |
@@ -3548,38 +3549,44 @@ out: | |||
3548 | #endif /* IPV6 */ | 3549 | #endif /* IPV6 */ |
3549 | 3550 | ||
3550 | static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, | 3551 | static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, |
3551 | char **addrp, int src, u8 *proto) | 3552 | char **_addrp, int src, u8 *proto) |
3552 | { | 3553 | { |
3553 | int ret = 0; | 3554 | char *addrp; |
3555 | int ret; | ||
3554 | 3556 | ||
3555 | switch (ad->u.net.family) { | 3557 | switch (ad->u.net.family) { |
3556 | case PF_INET: | 3558 | case PF_INET: |
3557 | ret = selinux_parse_skb_ipv4(skb, ad, proto); | 3559 | ret = selinux_parse_skb_ipv4(skb, ad, proto); |
3558 | if (ret || !addrp) | 3560 | if (ret) |
3559 | break; | 3561 | goto parse_error; |
3560 | *addrp = (char *)(src ? &ad->u.net.v4info.saddr : | 3562 | addrp = (char *)(src ? &ad->u.net.v4info.saddr : |
3561 | &ad->u.net.v4info.daddr); | 3563 | &ad->u.net.v4info.daddr); |
3562 | break; | 3564 | goto okay; |
3563 | 3565 | ||
3564 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 3566 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
3565 | case PF_INET6: | 3567 | case PF_INET6: |
3566 | ret = selinux_parse_skb_ipv6(skb, ad, proto); | 3568 | ret = selinux_parse_skb_ipv6(skb, ad, proto); |
3567 | if (ret || !addrp) | 3569 | if (ret) |
3568 | break; | 3570 | goto parse_error; |
3569 | *addrp = (char *)(src ? &ad->u.net.v6info.saddr : | 3571 | addrp = (char *)(src ? &ad->u.net.v6info.saddr : |
3570 | &ad->u.net.v6info.daddr); | 3572 | &ad->u.net.v6info.daddr); |
3571 | break; | 3573 | goto okay; |
3572 | #endif /* IPV6 */ | 3574 | #endif /* IPV6 */ |
3573 | default: | 3575 | default: |
3574 | break; | 3576 | addrp = NULL; |
3577 | goto okay; | ||
3575 | } | 3578 | } |
3576 | 3579 | ||
3577 | if (unlikely(ret)) | 3580 | parse_error: |
3578 | printk(KERN_WARNING | 3581 | printk(KERN_WARNING |
3579 | "SELinux: failure in selinux_parse_skb()," | 3582 | "SELinux: failure in selinux_parse_skb()," |
3580 | " unable to parse packet\n"); | 3583 | " unable to parse packet\n"); |
3581 | |||
3582 | return ret; | 3584 | return ret; |
3585 | |||
3586 | okay: | ||
3587 | if (_addrp) | ||
3588 | *_addrp = addrp; | ||
3589 | return 0; | ||
3583 | } | 3590 | } |
3584 | 3591 | ||
3585 | /** | 3592 | /** |
@@ -5219,8 +5226,12 @@ static int selinux_setprocattr(struct task_struct *p, | |||
5219 | 5226 | ||
5220 | if (sid == 0) | 5227 | if (sid == 0) |
5221 | return -EINVAL; | 5228 | return -EINVAL; |
5222 | 5229 | /* | |
5223 | /* Only allow single threaded processes to change context */ | 5230 | * SELinux allows to change context in the following case only. |
5231 | * - Single threaded processes. | ||
5232 | * - Multi threaded processes intend to change its context into | ||
5233 | * more restricted domain (defined by TYPEBOUNDS statement). | ||
5234 | */ | ||
5224 | if (atomic_read(&p->mm->mm_users) != 1) { | 5235 | if (atomic_read(&p->mm->mm_users) != 1) { |
5225 | struct task_struct *g, *t; | 5236 | struct task_struct *g, *t; |
5226 | struct mm_struct *mm = p->mm; | 5237 | struct mm_struct *mm = p->mm; |
@@ -5228,11 +5239,16 @@ static int selinux_setprocattr(struct task_struct *p, | |||
5228 | do_each_thread(g, t) { | 5239 | do_each_thread(g, t) { |
5229 | if (t->mm == mm && t != p) { | 5240 | if (t->mm == mm && t != p) { |
5230 | read_unlock(&tasklist_lock); | 5241 | read_unlock(&tasklist_lock); |
5231 | return -EPERM; | 5242 | error = security_bounded_transition(tsec->sid, sid); |
5243 | if (!error) | ||
5244 | goto boundary_ok; | ||
5245 | |||
5246 | return error; | ||
5232 | } | 5247 | } |
5233 | } while_each_thread(g, t); | 5248 | } while_each_thread(g, t); |
5234 | read_unlock(&tasklist_lock); | 5249 | read_unlock(&tasklist_lock); |
5235 | } | 5250 | } |
5251 | boundary_ok: | ||
5236 | 5252 | ||
5237 | /* Check permissions for the transition. */ | 5253 | /* Check permissions for the transition. */ |
5238 | error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, | 5254 | error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, |
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 7b9769f5e775..d12ff1a9c0aa 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/kdev_t.h> | 12 | #include <linux/kdev_t.h> |
13 | #include <linux/spinlock.h> | 13 | #include <linux/spinlock.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/audit.h> | ||
15 | #include <linux/in6.h> | 16 | #include <linux/in6.h> |
16 | #include <linux/path.h> | 17 | #include <linux/path.h> |
17 | #include <asm/system.h> | 18 | #include <asm/system.h> |
@@ -126,6 +127,9 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, | |||
126 | u32 events, u32 ssid, u32 tsid, | 127 | u32 events, u32 ssid, u32 tsid, |
127 | u16 tclass, u32 perms); | 128 | u16 tclass, u32 perms); |
128 | 129 | ||
130 | /* Shows permission in human readable form */ | ||
131 | void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av); | ||
132 | |||
129 | /* Exported to selinuxfs */ | 133 | /* Exported to selinuxfs */ |
130 | int avc_get_hash_stats(char *page); | 134 | int avc_get_hash_stats(char *page); |
131 | extern unsigned int avc_cache_threshold; | 135 | extern unsigned int avc_cache_threshold; |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 7c543003d653..72447370bc95 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -27,13 +27,14 @@ | |||
27 | #define POLICYDB_VERSION_RANGETRANS 21 | 27 | #define POLICYDB_VERSION_RANGETRANS 21 |
28 | #define POLICYDB_VERSION_POLCAP 22 | 28 | #define POLICYDB_VERSION_POLCAP 22 |
29 | #define POLICYDB_VERSION_PERMISSIVE 23 | 29 | #define POLICYDB_VERSION_PERMISSIVE 23 |
30 | #define POLICYDB_VERSION_BOUNDARY 24 | ||
30 | 31 | ||
31 | /* Range of policy versions we understand*/ | 32 | /* Range of policy versions we understand*/ |
32 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE | 33 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE |
33 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX | 34 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX |
34 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE | 35 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE |
35 | #else | 36 | #else |
36 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_PERMISSIVE | 37 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_BOUNDARY |
37 | #endif | 38 | #endif |
38 | 39 | ||
39 | #define CONTEXT_MNT 0x01 | 40 | #define CONTEXT_MNT 0x01 |
@@ -62,6 +63,16 @@ enum { | |||
62 | extern int selinux_policycap_netpeer; | 63 | extern int selinux_policycap_netpeer; |
63 | extern int selinux_policycap_openperm; | 64 | extern int selinux_policycap_openperm; |
64 | 65 | ||
66 | /* | ||
67 | * type_datum properties | ||
68 | * available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY | ||
69 | */ | ||
70 | #define TYPEDATUM_PROPERTY_PRIMARY 0x0001 | ||
71 | #define TYPEDATUM_PROPERTY_ATTRIBUTE 0x0002 | ||
72 | |||
73 | /* limitation of boundary depth */ | ||
74 | #define POLICYDB_BOUNDS_MAXDEPTH 4 | ||
75 | |||
65 | int security_load_policy(void *data, size_t len); | 76 | int security_load_policy(void *data, size_t len); |
66 | 77 | ||
67 | int security_policycap_supported(unsigned int req_cap); | 78 | int security_policycap_supported(unsigned int req_cap); |
@@ -117,6 +128,8 @@ int security_node_sid(u16 domain, void *addr, u32 addrlen, | |||
117 | int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, | 128 | int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, |
118 | u16 tclass); | 129 | u16 tclass); |
119 | 130 | ||
131 | int security_bounded_transition(u32 oldsid, u32 newsid); | ||
132 | |||
120 | int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); | 133 | int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); |
121 | 134 | ||
122 | int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, | 135 | int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, |
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index a1be97f8beea..1215b8e47dba 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c | |||
@@ -98,7 +98,7 @@ struct avtab_node * | |||
98 | avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum) | 98 | avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum) |
99 | { | 99 | { |
100 | int hvalue; | 100 | int hvalue; |
101 | struct avtab_node *prev, *cur, *newnode; | 101 | struct avtab_node *prev, *cur; |
102 | u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); | 102 | u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); |
103 | 103 | ||
104 | if (!h || !h->htable) | 104 | if (!h || !h->htable) |
@@ -122,9 +122,7 @@ avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datu | |||
122 | key->target_class < cur->key.target_class) | 122 | key->target_class < cur->key.target_class) |
123 | break; | 123 | break; |
124 | } | 124 | } |
125 | newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum); | 125 | return avtab_insert_node(h, hvalue, prev, cur, key, datum); |
126 | |||
127 | return newnode; | ||
128 | } | 126 | } |
129 | 127 | ||
130 | struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key) | 128 | struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key) |
@@ -231,7 +229,7 @@ void avtab_destroy(struct avtab *h) | |||
231 | 229 | ||
232 | for (i = 0; i < h->nslot; i++) { | 230 | for (i = 0; i < h->nslot; i++) { |
233 | cur = h->htable[i]; | 231 | cur = h->htable[i]; |
234 | while (cur != NULL) { | 232 | while (cur) { |
235 | temp = cur; | 233 | temp = cur; |
236 | cur = cur->next; | 234 | cur = cur->next; |
237 | kmem_cache_free(avtab_node_cachep, temp); | 235 | kmem_cache_free(avtab_node_cachep, temp); |
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index fb4efe4f4bc8..4a4e35cac22b 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c | |||
@@ -29,7 +29,7 @@ static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr) | |||
29 | int s[COND_EXPR_MAXDEPTH]; | 29 | int s[COND_EXPR_MAXDEPTH]; |
30 | int sp = -1; | 30 | int sp = -1; |
31 | 31 | ||
32 | for (cur = expr; cur != NULL; cur = cur->next) { | 32 | for (cur = expr; cur; cur = cur->next) { |
33 | switch (cur->expr_type) { | 33 | switch (cur->expr_type) { |
34 | case COND_BOOL: | 34 | case COND_BOOL: |
35 | if (sp == (COND_EXPR_MAXDEPTH - 1)) | 35 | if (sp == (COND_EXPR_MAXDEPTH - 1)) |
@@ -97,14 +97,14 @@ int evaluate_cond_node(struct policydb *p, struct cond_node *node) | |||
97 | if (new_state == -1) | 97 | if (new_state == -1) |
98 | printk(KERN_ERR "SELinux: expression result was undefined - disabling all rules.\n"); | 98 | printk(KERN_ERR "SELinux: expression result was undefined - disabling all rules.\n"); |
99 | /* turn the rules on or off */ | 99 | /* turn the rules on or off */ |
100 | for (cur = node->true_list; cur != NULL; cur = cur->next) { | 100 | for (cur = node->true_list; cur; cur = cur->next) { |
101 | if (new_state <= 0) | 101 | if (new_state <= 0) |
102 | cur->node->key.specified &= ~AVTAB_ENABLED; | 102 | cur->node->key.specified &= ~AVTAB_ENABLED; |
103 | else | 103 | else |
104 | cur->node->key.specified |= AVTAB_ENABLED; | 104 | cur->node->key.specified |= AVTAB_ENABLED; |
105 | } | 105 | } |
106 | 106 | ||
107 | for (cur = node->false_list; cur != NULL; cur = cur->next) { | 107 | for (cur = node->false_list; cur; cur = cur->next) { |
108 | /* -1 or 1 */ | 108 | /* -1 or 1 */ |
109 | if (new_state) | 109 | if (new_state) |
110 | cur->node->key.specified &= ~AVTAB_ENABLED; | 110 | cur->node->key.specified &= ~AVTAB_ENABLED; |
@@ -128,7 +128,7 @@ int cond_policydb_init(struct policydb *p) | |||
128 | static void cond_av_list_destroy(struct cond_av_list *list) | 128 | static void cond_av_list_destroy(struct cond_av_list *list) |
129 | { | 129 | { |
130 | struct cond_av_list *cur, *next; | 130 | struct cond_av_list *cur, *next; |
131 | for (cur = list; cur != NULL; cur = next) { | 131 | for (cur = list; cur; cur = next) { |
132 | next = cur->next; | 132 | next = cur->next; |
133 | /* the avtab_ptr_t node is destroy by the avtab */ | 133 | /* the avtab_ptr_t node is destroy by the avtab */ |
134 | kfree(cur); | 134 | kfree(cur); |
@@ -139,7 +139,7 @@ static void cond_node_destroy(struct cond_node *node) | |||
139 | { | 139 | { |
140 | struct cond_expr *cur_expr, *next_expr; | 140 | struct cond_expr *cur_expr, *next_expr; |
141 | 141 | ||
142 | for (cur_expr = node->expr; cur_expr != NULL; cur_expr = next_expr) { | 142 | for (cur_expr = node->expr; cur_expr; cur_expr = next_expr) { |
143 | next_expr = cur_expr->next; | 143 | next_expr = cur_expr->next; |
144 | kfree(cur_expr); | 144 | kfree(cur_expr); |
145 | } | 145 | } |
@@ -155,7 +155,7 @@ static void cond_list_destroy(struct cond_node *list) | |||
155 | if (list == NULL) | 155 | if (list == NULL) |
156 | return; | 156 | return; |
157 | 157 | ||
158 | for (cur = list; cur != NULL; cur = next) { | 158 | for (cur = list; cur; cur = next) { |
159 | next = cur->next; | 159 | next = cur->next; |
160 | cond_node_destroy(cur); | 160 | cond_node_destroy(cur); |
161 | } | 161 | } |
@@ -239,7 +239,7 @@ int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp) | |||
239 | rc = next_entry(key, fp, len); | 239 | rc = next_entry(key, fp, len); |
240 | if (rc < 0) | 240 | if (rc < 0) |
241 | goto err; | 241 | goto err; |
242 | key[len] = 0; | 242 | key[len] = '\0'; |
243 | if (hashtab_insert(h, key, booldatum)) | 243 | if (hashtab_insert(h, key, booldatum)) |
244 | goto err; | 244 | goto err; |
245 | 245 | ||
@@ -291,7 +291,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum | |||
291 | goto err; | 291 | goto err; |
292 | } | 292 | } |
293 | found = 0; | 293 | found = 0; |
294 | for (cur = other; cur != NULL; cur = cur->next) { | 294 | for (cur = other; cur; cur = cur->next) { |
295 | if (cur->node == node_ptr) { | 295 | if (cur->node == node_ptr) { |
296 | found = 1; | 296 | found = 1; |
297 | break; | 297 | break; |
@@ -485,7 +485,7 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decisi | |||
485 | if (!ctab || !key || !avd) | 485 | if (!ctab || !key || !avd) |
486 | return; | 486 | return; |
487 | 487 | ||
488 | for (node = avtab_search_node(ctab, key); node != NULL; | 488 | for (node = avtab_search_node(ctab, key); node; |
489 | node = avtab_search_node_next(node, key->specified)) { | 489 | node = avtab_search_node_next(node, key->specified)) { |
490 | if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == | 490 | if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == |
491 | (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) | 491 | (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) |
diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h index 65b9f8366e9c..53ddb013ae57 100644 --- a/security/selinux/ss/conditional.h +++ b/security/selinux/ss/conditional.h | |||
@@ -28,7 +28,7 @@ struct cond_expr { | |||
28 | #define COND_XOR 5 /* bool ^ bool */ | 28 | #define COND_XOR 5 /* bool ^ bool */ |
29 | #define COND_EQ 6 /* bool == bool */ | 29 | #define COND_EQ 6 /* bool == bool */ |
30 | #define COND_NEQ 7 /* bool != bool */ | 30 | #define COND_NEQ 7 /* bool != bool */ |
31 | #define COND_LAST 8 | 31 | #define COND_LAST COND_NEQ |
32 | __u32 expr_type; | 32 | __u32 expr_type; |
33 | __u32 bool; | 33 | __u32 bool; |
34 | struct cond_expr *next; | 34 | struct cond_expr *next; |
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index ddc275490af8..68c7348d1acc 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c | |||
@@ -109,7 +109,7 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, | |||
109 | *catmap = c_iter; | 109 | *catmap = c_iter; |
110 | c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1); | 110 | c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1); |
111 | 111 | ||
112 | while (e_iter != NULL) { | 112 | while (e_iter) { |
113 | for (i = 0; i < EBITMAP_UNIT_NUMS; i++) { | 113 | for (i = 0; i < EBITMAP_UNIT_NUMS; i++) { |
114 | unsigned int delta, e_startbit, c_endbit; | 114 | unsigned int delta, e_startbit, c_endbit; |
115 | 115 | ||
@@ -197,7 +197,7 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap, | |||
197 | } | 197 | } |
198 | } | 198 | } |
199 | c_iter = c_iter->next; | 199 | c_iter = c_iter->next; |
200 | } while (c_iter != NULL); | 200 | } while (c_iter); |
201 | if (e_iter != NULL) | 201 | if (e_iter != NULL) |
202 | ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; | 202 | ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; |
203 | else | 203 | else |
diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index 2e7788e13213..933e735bb185 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c | |||
@@ -81,7 +81,7 @@ void *hashtab_search(struct hashtab *h, const void *key) | |||
81 | 81 | ||
82 | hvalue = h->hash_value(h, key); | 82 | hvalue = h->hash_value(h, key); |
83 | cur = h->htable[hvalue]; | 83 | cur = h->htable[hvalue]; |
84 | while (cur != NULL && h->keycmp(h, key, cur->key) > 0) | 84 | while (cur && h->keycmp(h, key, cur->key) > 0) |
85 | cur = cur->next; | 85 | cur = cur->next; |
86 | 86 | ||
87 | if (cur == NULL || (h->keycmp(h, key, cur->key) != 0)) | 87 | if (cur == NULL || (h->keycmp(h, key, cur->key) != 0)) |
@@ -100,7 +100,7 @@ void hashtab_destroy(struct hashtab *h) | |||
100 | 100 | ||
101 | for (i = 0; i < h->size; i++) { | 101 | for (i = 0; i < h->size; i++) { |
102 | cur = h->htable[i]; | 102 | cur = h->htable[i]; |
103 | while (cur != NULL) { | 103 | while (cur) { |
104 | temp = cur; | 104 | temp = cur; |
105 | cur = cur->next; | 105 | cur = cur->next; |
106 | kfree(temp); | 106 | kfree(temp); |
@@ -127,7 +127,7 @@ int hashtab_map(struct hashtab *h, | |||
127 | 127 | ||
128 | for (i = 0; i < h->size; i++) { | 128 | for (i = 0; i < h->size; i++) { |
129 | cur = h->htable[i]; | 129 | cur = h->htable[i]; |
130 | while (cur != NULL) { | 130 | while (cur) { |
131 | ret = apply(cur->key, cur->datum, args); | 131 | ret = apply(cur->key, cur->datum, args); |
132 | if (ret) | 132 | if (ret) |
133 | return ret; | 133 | return ret; |
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 77d745da48bb..b5407f16c2a4 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c | |||
@@ -283,8 +283,8 @@ int mls_context_to_sid(struct policydb *pol, | |||
283 | p++; | 283 | p++; |
284 | 284 | ||
285 | delim = *p; | 285 | delim = *p; |
286 | if (delim != 0) | 286 | if (delim != '\0') |
287 | *p++ = 0; | 287 | *p++ = '\0'; |
288 | 288 | ||
289 | for (l = 0; l < 2; l++) { | 289 | for (l = 0; l < 2; l++) { |
290 | levdatum = hashtab_search(pol->p_levels.table, scontextp); | 290 | levdatum = hashtab_search(pol->p_levels.table, scontextp); |
@@ -302,14 +302,14 @@ int mls_context_to_sid(struct policydb *pol, | |||
302 | while (*p && *p != ',' && *p != '-') | 302 | while (*p && *p != ',' && *p != '-') |
303 | p++; | 303 | p++; |
304 | delim = *p; | 304 | delim = *p; |
305 | if (delim != 0) | 305 | if (delim != '\0') |
306 | *p++ = 0; | 306 | *p++ = '\0'; |
307 | 307 | ||
308 | /* Separate into range if exists */ | 308 | /* Separate into range if exists */ |
309 | rngptr = strchr(scontextp, '.'); | 309 | rngptr = strchr(scontextp, '.'); |
310 | if (rngptr != NULL) { | 310 | if (rngptr != NULL) { |
311 | /* Remove '.' */ | 311 | /* Remove '.' */ |
312 | *rngptr++ = 0; | 312 | *rngptr++ = '\0'; |
313 | } | 313 | } |
314 | 314 | ||
315 | catdatum = hashtab_search(pol->p_cats.table, | 315 | catdatum = hashtab_search(pol->p_cats.table, |
@@ -357,8 +357,8 @@ int mls_context_to_sid(struct policydb *pol, | |||
357 | p++; | 357 | p++; |
358 | 358 | ||
359 | delim = *p; | 359 | delim = *p; |
360 | if (delim != 0) | 360 | if (delim != '\0') |
361 | *p++ = 0; | 361 | *p++ = '\0'; |
362 | } else | 362 | } else |
363 | break; | 363 | break; |
364 | } | 364 | } |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 2391761ae422..72e4a54973aa 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/string.h> | 31 | #include <linux/string.h> |
32 | #include <linux/errno.h> | 32 | #include <linux/errno.h> |
33 | #include <linux/audit.h> | ||
33 | #include "security.h" | 34 | #include "security.h" |
34 | 35 | ||
35 | #include "policydb.h" | 36 | #include "policydb.h" |
@@ -116,7 +117,12 @@ static struct policydb_compat_info policydb_compat[] = { | |||
116 | .version = POLICYDB_VERSION_PERMISSIVE, | 117 | .version = POLICYDB_VERSION_PERMISSIVE, |
117 | .sym_num = SYM_NUM, | 118 | .sym_num = SYM_NUM, |
118 | .ocon_num = OCON_NUM, | 119 | .ocon_num = OCON_NUM, |
119 | } | 120 | }, |
121 | { | ||
122 | .version = POLICYDB_VERSION_BOUNDARY, | ||
123 | .sym_num = SYM_NUM, | ||
124 | .ocon_num = OCON_NUM, | ||
125 | }, | ||
120 | }; | 126 | }; |
121 | 127 | ||
122 | static struct policydb_compat_info *policydb_lookup_compat(int version) | 128 | static struct policydb_compat_info *policydb_lookup_compat(int version) |
@@ -254,7 +260,9 @@ static int role_index(void *key, void *datum, void *datap) | |||
254 | 260 | ||
255 | role = datum; | 261 | role = datum; |
256 | p = datap; | 262 | p = datap; |
257 | if (!role->value || role->value > p->p_roles.nprim) | 263 | if (!role->value |
264 | || role->value > p->p_roles.nprim | ||
265 | || role->bounds > p->p_roles.nprim) | ||
258 | return -EINVAL; | 266 | return -EINVAL; |
259 | p->p_role_val_to_name[role->value - 1] = key; | 267 | p->p_role_val_to_name[role->value - 1] = key; |
260 | p->role_val_to_struct[role->value - 1] = role; | 268 | p->role_val_to_struct[role->value - 1] = role; |
@@ -270,9 +278,12 @@ static int type_index(void *key, void *datum, void *datap) | |||
270 | p = datap; | 278 | p = datap; |
271 | 279 | ||
272 | if (typdatum->primary) { | 280 | if (typdatum->primary) { |
273 | if (!typdatum->value || typdatum->value > p->p_types.nprim) | 281 | if (!typdatum->value |
282 | || typdatum->value > p->p_types.nprim | ||
283 | || typdatum->bounds > p->p_types.nprim) | ||
274 | return -EINVAL; | 284 | return -EINVAL; |
275 | p->p_type_val_to_name[typdatum->value - 1] = key; | 285 | p->p_type_val_to_name[typdatum->value - 1] = key; |
286 | p->type_val_to_struct[typdatum->value - 1] = typdatum; | ||
276 | } | 287 | } |
277 | 288 | ||
278 | return 0; | 289 | return 0; |
@@ -285,7 +296,9 @@ static int user_index(void *key, void *datum, void *datap) | |||
285 | 296 | ||
286 | usrdatum = datum; | 297 | usrdatum = datum; |
287 | p = datap; | 298 | p = datap; |
288 | if (!usrdatum->value || usrdatum->value > p->p_users.nprim) | 299 | if (!usrdatum->value |
300 | || usrdatum->value > p->p_users.nprim | ||
301 | || usrdatum->bounds > p->p_users.nprim) | ||
289 | return -EINVAL; | 302 | return -EINVAL; |
290 | p->p_user_val_to_name[usrdatum->value - 1] = key; | 303 | p->p_user_val_to_name[usrdatum->value - 1] = key; |
291 | p->user_val_to_struct[usrdatum->value - 1] = usrdatum; | 304 | p->user_val_to_struct[usrdatum->value - 1] = usrdatum; |
@@ -438,6 +451,14 @@ static int policydb_index_others(struct policydb *p) | |||
438 | goto out; | 451 | goto out; |
439 | } | 452 | } |
440 | 453 | ||
454 | p->type_val_to_struct = | ||
455 | kmalloc(p->p_types.nprim * sizeof(*(p->type_val_to_struct)), | ||
456 | GFP_KERNEL); | ||
457 | if (!p->type_val_to_struct) { | ||
458 | rc = -ENOMEM; | ||
459 | goto out; | ||
460 | } | ||
461 | |||
441 | if (cond_init_bool_indexes(p)) { | 462 | if (cond_init_bool_indexes(p)) { |
442 | rc = -ENOMEM; | 463 | rc = -ENOMEM; |
443 | goto out; | 464 | goto out; |
@@ -625,6 +646,7 @@ void policydb_destroy(struct policydb *p) | |||
625 | kfree(p->class_val_to_struct); | 646 | kfree(p->class_val_to_struct); |
626 | kfree(p->role_val_to_struct); | 647 | kfree(p->role_val_to_struct); |
627 | kfree(p->user_val_to_struct); | 648 | kfree(p->user_val_to_struct); |
649 | kfree(p->type_val_to_struct); | ||
628 | 650 | ||
629 | avtab_destroy(&p->te_avtab); | 651 | avtab_destroy(&p->te_avtab); |
630 | 652 | ||
@@ -932,7 +954,7 @@ static int perm_read(struct policydb *p, struct hashtab *h, void *fp) | |||
932 | rc = next_entry(key, fp, len); | 954 | rc = next_entry(key, fp, len); |
933 | if (rc < 0) | 955 | if (rc < 0) |
934 | goto bad; | 956 | goto bad; |
935 | key[len] = 0; | 957 | key[len] = '\0'; |
936 | 958 | ||
937 | rc = hashtab_insert(h, key, perdatum); | 959 | rc = hashtab_insert(h, key, perdatum); |
938 | if (rc) | 960 | if (rc) |
@@ -979,7 +1001,7 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp) | |||
979 | rc = next_entry(key, fp, len); | 1001 | rc = next_entry(key, fp, len); |
980 | if (rc < 0) | 1002 | if (rc < 0) |
981 | goto bad; | 1003 | goto bad; |
982 | key[len] = 0; | 1004 | key[len] = '\0'; |
983 | 1005 | ||
984 | for (i = 0; i < nel; i++) { | 1006 | for (i = 0; i < nel; i++) { |
985 | rc = perm_read(p, comdatum->permissions.table, fp); | 1007 | rc = perm_read(p, comdatum->permissions.table, fp); |
@@ -1117,7 +1139,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1117 | rc = next_entry(key, fp, len); | 1139 | rc = next_entry(key, fp, len); |
1118 | if (rc < 0) | 1140 | if (rc < 0) |
1119 | goto bad; | 1141 | goto bad; |
1120 | key[len] = 0; | 1142 | key[len] = '\0'; |
1121 | 1143 | ||
1122 | if (len2) { | 1144 | if (len2) { |
1123 | cladatum->comkey = kmalloc(len2 + 1, GFP_KERNEL); | 1145 | cladatum->comkey = kmalloc(len2 + 1, GFP_KERNEL); |
@@ -1128,7 +1150,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1128 | rc = next_entry(cladatum->comkey, fp, len2); | 1150 | rc = next_entry(cladatum->comkey, fp, len2); |
1129 | if (rc < 0) | 1151 | if (rc < 0) |
1130 | goto bad; | 1152 | goto bad; |
1131 | cladatum->comkey[len2] = 0; | 1153 | cladatum->comkey[len2] = '\0'; |
1132 | 1154 | ||
1133 | cladatum->comdatum = hashtab_search(p->p_commons.table, | 1155 | cladatum->comdatum = hashtab_search(p->p_commons.table, |
1134 | cladatum->comkey); | 1156 | cladatum->comkey); |
@@ -1176,8 +1198,8 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1176 | { | 1198 | { |
1177 | char *key = NULL; | 1199 | char *key = NULL; |
1178 | struct role_datum *role; | 1200 | struct role_datum *role; |
1179 | int rc; | 1201 | int rc, to_read = 2; |
1180 | __le32 buf[2]; | 1202 | __le32 buf[3]; |
1181 | u32 len; | 1203 | u32 len; |
1182 | 1204 | ||
1183 | role = kzalloc(sizeof(*role), GFP_KERNEL); | 1205 | role = kzalloc(sizeof(*role), GFP_KERNEL); |
@@ -1186,12 +1208,17 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1186 | goto out; | 1208 | goto out; |
1187 | } | 1209 | } |
1188 | 1210 | ||
1189 | rc = next_entry(buf, fp, sizeof buf); | 1211 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) |
1212 | to_read = 3; | ||
1213 | |||
1214 | rc = next_entry(buf, fp, sizeof(buf[0]) * to_read); | ||
1190 | if (rc < 0) | 1215 | if (rc < 0) |
1191 | goto bad; | 1216 | goto bad; |
1192 | 1217 | ||
1193 | len = le32_to_cpu(buf[0]); | 1218 | len = le32_to_cpu(buf[0]); |
1194 | role->value = le32_to_cpu(buf[1]); | 1219 | role->value = le32_to_cpu(buf[1]); |
1220 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) | ||
1221 | role->bounds = le32_to_cpu(buf[2]); | ||
1195 | 1222 | ||
1196 | key = kmalloc(len + 1, GFP_KERNEL); | 1223 | key = kmalloc(len + 1, GFP_KERNEL); |
1197 | if (!key) { | 1224 | if (!key) { |
@@ -1201,7 +1228,7 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1201 | rc = next_entry(key, fp, len); | 1228 | rc = next_entry(key, fp, len); |
1202 | if (rc < 0) | 1229 | if (rc < 0) |
1203 | goto bad; | 1230 | goto bad; |
1204 | key[len] = 0; | 1231 | key[len] = '\0'; |
1205 | 1232 | ||
1206 | rc = ebitmap_read(&role->dominates, fp); | 1233 | rc = ebitmap_read(&role->dominates, fp); |
1207 | if (rc) | 1234 | if (rc) |
@@ -1236,8 +1263,8 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1236 | { | 1263 | { |
1237 | char *key = NULL; | 1264 | char *key = NULL; |
1238 | struct type_datum *typdatum; | 1265 | struct type_datum *typdatum; |
1239 | int rc; | 1266 | int rc, to_read = 3; |
1240 | __le32 buf[3]; | 1267 | __le32 buf[4]; |
1241 | u32 len; | 1268 | u32 len; |
1242 | 1269 | ||
1243 | typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL); | 1270 | typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL); |
@@ -1246,13 +1273,27 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1246 | return rc; | 1273 | return rc; |
1247 | } | 1274 | } |
1248 | 1275 | ||
1249 | rc = next_entry(buf, fp, sizeof buf); | 1276 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) |
1277 | to_read = 4; | ||
1278 | |||
1279 | rc = next_entry(buf, fp, sizeof(buf[0]) * to_read); | ||
1250 | if (rc < 0) | 1280 | if (rc < 0) |
1251 | goto bad; | 1281 | goto bad; |
1252 | 1282 | ||
1253 | len = le32_to_cpu(buf[0]); | 1283 | len = le32_to_cpu(buf[0]); |
1254 | typdatum->value = le32_to_cpu(buf[1]); | 1284 | typdatum->value = le32_to_cpu(buf[1]); |
1255 | typdatum->primary = le32_to_cpu(buf[2]); | 1285 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) { |
1286 | u32 prop = le32_to_cpu(buf[2]); | ||
1287 | |||
1288 | if (prop & TYPEDATUM_PROPERTY_PRIMARY) | ||
1289 | typdatum->primary = 1; | ||
1290 | if (prop & TYPEDATUM_PROPERTY_ATTRIBUTE) | ||
1291 | typdatum->attribute = 1; | ||
1292 | |||
1293 | typdatum->bounds = le32_to_cpu(buf[3]); | ||
1294 | } else { | ||
1295 | typdatum->primary = le32_to_cpu(buf[2]); | ||
1296 | } | ||
1256 | 1297 | ||
1257 | key = kmalloc(len + 1, GFP_KERNEL); | 1298 | key = kmalloc(len + 1, GFP_KERNEL); |
1258 | if (!key) { | 1299 | if (!key) { |
@@ -1262,7 +1303,7 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1262 | rc = next_entry(key, fp, len); | 1303 | rc = next_entry(key, fp, len); |
1263 | if (rc < 0) | 1304 | if (rc < 0) |
1264 | goto bad; | 1305 | goto bad; |
1265 | key[len] = 0; | 1306 | key[len] = '\0'; |
1266 | 1307 | ||
1267 | rc = hashtab_insert(h, key, typdatum); | 1308 | rc = hashtab_insert(h, key, typdatum); |
1268 | if (rc) | 1309 | if (rc) |
@@ -1309,8 +1350,8 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1309 | { | 1350 | { |
1310 | char *key = NULL; | 1351 | char *key = NULL; |
1311 | struct user_datum *usrdatum; | 1352 | struct user_datum *usrdatum; |
1312 | int rc; | 1353 | int rc, to_read = 2; |
1313 | __le32 buf[2]; | 1354 | __le32 buf[3]; |
1314 | u32 len; | 1355 | u32 len; |
1315 | 1356 | ||
1316 | usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL); | 1357 | usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL); |
@@ -1319,12 +1360,17 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1319 | goto out; | 1360 | goto out; |
1320 | } | 1361 | } |
1321 | 1362 | ||
1322 | rc = next_entry(buf, fp, sizeof buf); | 1363 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) |
1364 | to_read = 3; | ||
1365 | |||
1366 | rc = next_entry(buf, fp, sizeof(buf[0]) * to_read); | ||
1323 | if (rc < 0) | 1367 | if (rc < 0) |
1324 | goto bad; | 1368 | goto bad; |
1325 | 1369 | ||
1326 | len = le32_to_cpu(buf[0]); | 1370 | len = le32_to_cpu(buf[0]); |
1327 | usrdatum->value = le32_to_cpu(buf[1]); | 1371 | usrdatum->value = le32_to_cpu(buf[1]); |
1372 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) | ||
1373 | usrdatum->bounds = le32_to_cpu(buf[2]); | ||
1328 | 1374 | ||
1329 | key = kmalloc(len + 1, GFP_KERNEL); | 1375 | key = kmalloc(len + 1, GFP_KERNEL); |
1330 | if (!key) { | 1376 | if (!key) { |
@@ -1334,7 +1380,7 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1334 | rc = next_entry(key, fp, len); | 1380 | rc = next_entry(key, fp, len); |
1335 | if (rc < 0) | 1381 | if (rc < 0) |
1336 | goto bad; | 1382 | goto bad; |
1337 | key[len] = 0; | 1383 | key[len] = '\0'; |
1338 | 1384 | ||
1339 | rc = ebitmap_read(&usrdatum->roles, fp); | 1385 | rc = ebitmap_read(&usrdatum->roles, fp); |
1340 | if (rc) | 1386 | if (rc) |
@@ -1388,7 +1434,7 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1388 | rc = next_entry(key, fp, len); | 1434 | rc = next_entry(key, fp, len); |
1389 | if (rc < 0) | 1435 | if (rc < 0) |
1390 | goto bad; | 1436 | goto bad; |
1391 | key[len] = 0; | 1437 | key[len] = '\0'; |
1392 | 1438 | ||
1393 | levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC); | 1439 | levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC); |
1394 | if (!levdatum->level) { | 1440 | if (!levdatum->level) { |
@@ -1440,7 +1486,7 @@ static int cat_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1440 | rc = next_entry(key, fp, len); | 1486 | rc = next_entry(key, fp, len); |
1441 | if (rc < 0) | 1487 | if (rc < 0) |
1442 | goto bad; | 1488 | goto bad; |
1443 | key[len] = 0; | 1489 | key[len] = '\0'; |
1444 | 1490 | ||
1445 | rc = hashtab_insert(h, key, catdatum); | 1491 | rc = hashtab_insert(h, key, catdatum); |
1446 | if (rc) | 1492 | if (rc) |
@@ -1465,6 +1511,133 @@ static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) | |||
1465 | cat_read, | 1511 | cat_read, |
1466 | }; | 1512 | }; |
1467 | 1513 | ||
1514 | static int user_bounds_sanity_check(void *key, void *datum, void *datap) | ||
1515 | { | ||
1516 | struct user_datum *upper, *user; | ||
1517 | struct policydb *p = datap; | ||
1518 | int depth = 0; | ||
1519 | |||
1520 | upper = user = datum; | ||
1521 | while (upper->bounds) { | ||
1522 | struct ebitmap_node *node; | ||
1523 | unsigned long bit; | ||
1524 | |||
1525 | if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { | ||
1526 | printk(KERN_ERR "SELinux: user %s: " | ||
1527 | "too deep or looped boundary", | ||
1528 | (char *) key); | ||
1529 | return -EINVAL; | ||
1530 | } | ||
1531 | |||
1532 | upper = p->user_val_to_struct[upper->bounds - 1]; | ||
1533 | ebitmap_for_each_positive_bit(&user->roles, node, bit) { | ||
1534 | if (ebitmap_get_bit(&upper->roles, bit)) | ||
1535 | continue; | ||
1536 | |||
1537 | printk(KERN_ERR | ||
1538 | "SELinux: boundary violated policy: " | ||
1539 | "user=%s role=%s bounds=%s\n", | ||
1540 | p->p_user_val_to_name[user->value - 1], | ||
1541 | p->p_role_val_to_name[bit], | ||
1542 | p->p_user_val_to_name[upper->value - 1]); | ||
1543 | |||
1544 | return -EINVAL; | ||
1545 | } | ||
1546 | } | ||
1547 | |||
1548 | return 0; | ||
1549 | } | ||
1550 | |||
1551 | static int role_bounds_sanity_check(void *key, void *datum, void *datap) | ||
1552 | { | ||
1553 | struct role_datum *upper, *role; | ||
1554 | struct policydb *p = datap; | ||
1555 | int depth = 0; | ||
1556 | |||
1557 | upper = role = datum; | ||
1558 | while (upper->bounds) { | ||
1559 | struct ebitmap_node *node; | ||
1560 | unsigned long bit; | ||
1561 | |||
1562 | if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { | ||
1563 | printk(KERN_ERR "SELinux: role %s: " | ||
1564 | "too deep or looped bounds\n", | ||
1565 | (char *) key); | ||
1566 | return -EINVAL; | ||
1567 | } | ||
1568 | |||
1569 | upper = p->role_val_to_struct[upper->bounds - 1]; | ||
1570 | ebitmap_for_each_positive_bit(&role->types, node, bit) { | ||
1571 | if (ebitmap_get_bit(&upper->types, bit)) | ||
1572 | continue; | ||
1573 | |||
1574 | printk(KERN_ERR | ||
1575 | "SELinux: boundary violated policy: " | ||
1576 | "role=%s type=%s bounds=%s\n", | ||
1577 | p->p_role_val_to_name[role->value - 1], | ||
1578 | p->p_type_val_to_name[bit], | ||
1579 | p->p_role_val_to_name[upper->value - 1]); | ||
1580 | |||
1581 | return -EINVAL; | ||
1582 | } | ||
1583 | } | ||
1584 | |||
1585 | return 0; | ||
1586 | } | ||
1587 | |||
1588 | static int type_bounds_sanity_check(void *key, void *datum, void *datap) | ||
1589 | { | ||
1590 | struct type_datum *upper, *type; | ||
1591 | struct policydb *p = datap; | ||
1592 | int depth = 0; | ||
1593 | |||
1594 | upper = type = datum; | ||
1595 | while (upper->bounds) { | ||
1596 | if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { | ||
1597 | printk(KERN_ERR "SELinux: type %s: " | ||
1598 | "too deep or looped boundary\n", | ||
1599 | (char *) key); | ||
1600 | return -EINVAL; | ||
1601 | } | ||
1602 | |||
1603 | upper = p->type_val_to_struct[upper->bounds - 1]; | ||
1604 | if (upper->attribute) { | ||
1605 | printk(KERN_ERR "SELinux: type %s: " | ||
1606 | "bounded by attribute %s", | ||
1607 | (char *) key, | ||
1608 | p->p_type_val_to_name[upper->value - 1]); | ||
1609 | return -EINVAL; | ||
1610 | } | ||
1611 | } | ||
1612 | |||
1613 | return 0; | ||
1614 | } | ||
1615 | |||
1616 | static int policydb_bounds_sanity_check(struct policydb *p) | ||
1617 | { | ||
1618 | int rc; | ||
1619 | |||
1620 | if (p->policyvers < POLICYDB_VERSION_BOUNDARY) | ||
1621 | return 0; | ||
1622 | |||
1623 | rc = hashtab_map(p->p_users.table, | ||
1624 | user_bounds_sanity_check, p); | ||
1625 | if (rc) | ||
1626 | return rc; | ||
1627 | |||
1628 | rc = hashtab_map(p->p_roles.table, | ||
1629 | role_bounds_sanity_check, p); | ||
1630 | if (rc) | ||
1631 | return rc; | ||
1632 | |||
1633 | rc = hashtab_map(p->p_types.table, | ||
1634 | type_bounds_sanity_check, p); | ||
1635 | if (rc) | ||
1636 | return rc; | ||
1637 | |||
1638 | return 0; | ||
1639 | } | ||
1640 | |||
1468 | extern int ss_initialized; | 1641 | extern int ss_initialized; |
1469 | 1642 | ||
1470 | /* | 1643 | /* |
@@ -1523,7 +1696,7 @@ int policydb_read(struct policydb *p, void *fp) | |||
1523 | kfree(policydb_str); | 1696 | kfree(policydb_str); |
1524 | goto bad; | 1697 | goto bad; |
1525 | } | 1698 | } |
1526 | policydb_str[len] = 0; | 1699 | policydb_str[len] = '\0'; |
1527 | if (strcmp(policydb_str, POLICYDB_STRING)) { | 1700 | if (strcmp(policydb_str, POLICYDB_STRING)) { |
1528 | printk(KERN_ERR "SELinux: policydb string %s does not match " | 1701 | printk(KERN_ERR "SELinux: policydb string %s does not match " |
1529 | "my string %s\n", policydb_str, POLICYDB_STRING); | 1702 | "my string %s\n", policydb_str, POLICYDB_STRING); |
@@ -1961,6 +2134,10 @@ int policydb_read(struct policydb *p, void *fp) | |||
1961 | goto bad; | 2134 | goto bad; |
1962 | } | 2135 | } |
1963 | 2136 | ||
2137 | rc = policydb_bounds_sanity_check(p); | ||
2138 | if (rc) | ||
2139 | goto bad; | ||
2140 | |||
1964 | rc = 0; | 2141 | rc = 0; |
1965 | out: | 2142 | out: |
1966 | return rc; | 2143 | return rc; |
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 4253370fda6a..55152d498b53 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
@@ -61,6 +61,7 @@ struct class_datum { | |||
61 | /* Role attributes */ | 61 | /* Role attributes */ |
62 | struct role_datum { | 62 | struct role_datum { |
63 | u32 value; /* internal role value */ | 63 | u32 value; /* internal role value */ |
64 | u32 bounds; /* boundary of role */ | ||
64 | struct ebitmap dominates; /* set of roles dominated by this role */ | 65 | struct ebitmap dominates; /* set of roles dominated by this role */ |
65 | struct ebitmap types; /* set of authorized types for role */ | 66 | struct ebitmap types; /* set of authorized types for role */ |
66 | }; | 67 | }; |
@@ -81,12 +82,15 @@ struct role_allow { | |||
81 | /* Type attributes */ | 82 | /* Type attributes */ |
82 | struct type_datum { | 83 | struct type_datum { |
83 | u32 value; /* internal type value */ | 84 | u32 value; /* internal type value */ |
85 | u32 bounds; /* boundary of type */ | ||
84 | unsigned char primary; /* primary name? */ | 86 | unsigned char primary; /* primary name? */ |
87 | unsigned char attribute;/* attribute ?*/ | ||
85 | }; | 88 | }; |
86 | 89 | ||
87 | /* User attributes */ | 90 | /* User attributes */ |
88 | struct user_datum { | 91 | struct user_datum { |
89 | u32 value; /* internal user value */ | 92 | u32 value; /* internal user value */ |
93 | u32 bounds; /* bounds of user */ | ||
90 | struct ebitmap roles; /* set of authorized roles for user */ | 94 | struct ebitmap roles; /* set of authorized roles for user */ |
91 | struct mls_range range; /* MLS range (min - max) for user */ | 95 | struct mls_range range; /* MLS range (min - max) for user */ |
92 | struct mls_level dfltlevel; /* default login MLS level for user */ | 96 | struct mls_level dfltlevel; /* default login MLS level for user */ |
@@ -209,6 +213,7 @@ struct policydb { | |||
209 | struct class_datum **class_val_to_struct; | 213 | struct class_datum **class_val_to_struct; |
210 | struct role_datum **role_val_to_struct; | 214 | struct role_datum **role_val_to_struct; |
211 | struct user_datum **user_val_to_struct; | 215 | struct user_datum **user_val_to_struct; |
216 | struct type_datum **type_val_to_struct; | ||
212 | 217 | ||
213 | /* type enforcement access vectors and transitions */ | 218 | /* type enforcement access vectors and transitions */ |
214 | struct avtab te_avtab; | 219 | struct avtab te_avtab; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 8551952ef329..ab0cc0c7b944 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -88,6 +88,11 @@ static u32 latest_granting; | |||
88 | static int context_struct_to_string(struct context *context, char **scontext, | 88 | static int context_struct_to_string(struct context *context, char **scontext, |
89 | u32 *scontext_len); | 89 | u32 *scontext_len); |
90 | 90 | ||
91 | static int context_struct_compute_av(struct context *scontext, | ||
92 | struct context *tcontext, | ||
93 | u16 tclass, | ||
94 | u32 requested, | ||
95 | struct av_decision *avd); | ||
91 | /* | 96 | /* |
92 | * Return the boolean value of a constraint expression | 97 | * Return the boolean value of a constraint expression |
93 | * when it is applied to the specified source and target | 98 | * when it is applied to the specified source and target |
@@ -274,6 +279,100 @@ mls_ops: | |||
274 | } | 279 | } |
275 | 280 | ||
276 | /* | 281 | /* |
282 | * security_boundary_permission - drops violated permissions | ||
283 | * on boundary constraint. | ||
284 | */ | ||
285 | static void type_attribute_bounds_av(struct context *scontext, | ||
286 | struct context *tcontext, | ||
287 | u16 tclass, | ||
288 | u32 requested, | ||
289 | struct av_decision *avd) | ||
290 | { | ||
291 | struct context lo_scontext; | ||
292 | struct context lo_tcontext; | ||
293 | struct av_decision lo_avd; | ||
294 | struct type_datum *source | ||
295 | = policydb.type_val_to_struct[scontext->type - 1]; | ||
296 | struct type_datum *target | ||
297 | = policydb.type_val_to_struct[tcontext->type - 1]; | ||
298 | u32 masked = 0; | ||
299 | |||
300 | if (source->bounds) { | ||
301 | memset(&lo_avd, 0, sizeof(lo_avd)); | ||
302 | |||
303 | memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); | ||
304 | lo_scontext.type = source->bounds; | ||
305 | |||
306 | context_struct_compute_av(&lo_scontext, | ||
307 | tcontext, | ||
308 | tclass, | ||
309 | requested, | ||
310 | &lo_avd); | ||
311 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | ||
312 | return; /* no masked permission */ | ||
313 | masked = ~lo_avd.allowed & avd->allowed; | ||
314 | } | ||
315 | |||
316 | if (target->bounds) { | ||
317 | memset(&lo_avd, 0, sizeof(lo_avd)); | ||
318 | |||
319 | memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); | ||
320 | lo_tcontext.type = target->bounds; | ||
321 | |||
322 | context_struct_compute_av(scontext, | ||
323 | &lo_tcontext, | ||
324 | tclass, | ||
325 | requested, | ||
326 | &lo_avd); | ||
327 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | ||
328 | return; /* no masked permission */ | ||
329 | masked = ~lo_avd.allowed & avd->allowed; | ||
330 | } | ||
331 | |||
332 | if (source->bounds && target->bounds) { | ||
333 | memset(&lo_avd, 0, sizeof(lo_avd)); | ||
334 | /* | ||
335 | * lo_scontext and lo_tcontext are already | ||
336 | * set up. | ||
337 | */ | ||
338 | |||
339 | context_struct_compute_av(&lo_scontext, | ||
340 | &lo_tcontext, | ||
341 | tclass, | ||
342 | requested, | ||
343 | &lo_avd); | ||
344 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | ||
345 | return; /* no masked permission */ | ||
346 | masked = ~lo_avd.allowed & avd->allowed; | ||
347 | } | ||
348 | |||
349 | if (masked) { | ||
350 | struct audit_buffer *ab; | ||
351 | char *stype_name | ||
352 | = policydb.p_type_val_to_name[source->value - 1]; | ||
353 | char *ttype_name | ||
354 | = policydb.p_type_val_to_name[target->value - 1]; | ||
355 | char *tclass_name | ||
356 | = policydb.p_class_val_to_name[tclass - 1]; | ||
357 | |||
358 | /* mask violated permissions */ | ||
359 | avd->allowed &= ~masked; | ||
360 | |||
361 | /* notice to userspace via audit message */ | ||
362 | ab = audit_log_start(current->audit_context, | ||
363 | GFP_ATOMIC, AUDIT_SELINUX_ERR); | ||
364 | if (!ab) | ||
365 | return; | ||
366 | |||
367 | audit_log_format(ab, "av boundary violation: " | ||
368 | "source=%s target=%s tclass=%s", | ||
369 | stype_name, ttype_name, tclass_name); | ||
370 | avc_dump_av(ab, tclass, masked); | ||
371 | audit_log_end(ab); | ||
372 | } | ||
373 | } | ||
374 | |||
375 | /* | ||
277 | * Compute access vectors based on a context structure pair for | 376 | * Compute access vectors based on a context structure pair for |
278 | * the permissions in a particular class. | 377 | * the permissions in a particular class. |
279 | */ | 378 | */ |
@@ -356,7 +455,7 @@ static int context_struct_compute_av(struct context *scontext, | |||
356 | avkey.source_type = i + 1; | 455 | avkey.source_type = i + 1; |
357 | avkey.target_type = j + 1; | 456 | avkey.target_type = j + 1; |
358 | for (node = avtab_search_node(&policydb.te_avtab, &avkey); | 457 | for (node = avtab_search_node(&policydb.te_avtab, &avkey); |
359 | node != NULL; | 458 | node; |
360 | node = avtab_search_node_next(node, avkey.specified)) { | 459 | node = avtab_search_node_next(node, avkey.specified)) { |
361 | if (node->key.specified == AVTAB_ALLOWED) | 460 | if (node->key.specified == AVTAB_ALLOWED) |
362 | avd->allowed |= node->datum.data; | 461 | avd->allowed |= node->datum.data; |
@@ -404,6 +503,14 @@ static int context_struct_compute_av(struct context *scontext, | |||
404 | PROCESS__DYNTRANSITION); | 503 | PROCESS__DYNTRANSITION); |
405 | } | 504 | } |
406 | 505 | ||
506 | /* | ||
507 | * If the given source and target types have boundary | ||
508 | * constraint, lazy checks have to mask any violated | ||
509 | * permission and notice it to userspace via audit. | ||
510 | */ | ||
511 | type_attribute_bounds_av(scontext, tcontext, | ||
512 | tclass, requested, avd); | ||
513 | |||
407 | return 0; | 514 | return 0; |
408 | 515 | ||
409 | inval_class: | 516 | inval_class: |
@@ -549,6 +656,69 @@ out: | |||
549 | return rc; | 656 | return rc; |
550 | } | 657 | } |
551 | 658 | ||
659 | /* | ||
660 | * security_bounded_transition - check whether the given | ||
661 | * transition is directed to bounded, or not. | ||
662 | * It returns 0, if @newsid is bounded by @oldsid. | ||
663 | * Otherwise, it returns error code. | ||
664 | * | ||
665 | * @oldsid : current security identifier | ||
666 | * @newsid : destinated security identifier | ||
667 | */ | ||
668 | int security_bounded_transition(u32 old_sid, u32 new_sid) | ||
669 | { | ||
670 | struct context *old_context, *new_context; | ||
671 | struct type_datum *type; | ||
672 | int index; | ||
673 | int rc = -EINVAL; | ||
674 | |||
675 | read_lock(&policy_rwlock); | ||
676 | |||
677 | old_context = sidtab_search(&sidtab, old_sid); | ||
678 | if (!old_context) { | ||
679 | printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", | ||
680 | __func__, old_sid); | ||
681 | goto out; | ||
682 | } | ||
683 | |||
684 | new_context = sidtab_search(&sidtab, new_sid); | ||
685 | if (!new_context) { | ||
686 | printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", | ||
687 | __func__, new_sid); | ||
688 | goto out; | ||
689 | } | ||
690 | |||
691 | /* type/domain unchaned */ | ||
692 | if (old_context->type == new_context->type) { | ||
693 | rc = 0; | ||
694 | goto out; | ||
695 | } | ||
696 | |||
697 | index = new_context->type; | ||
698 | while (true) { | ||
699 | type = policydb.type_val_to_struct[index - 1]; | ||
700 | BUG_ON(!type); | ||
701 | |||
702 | /* not bounded anymore */ | ||
703 | if (!type->bounds) { | ||
704 | rc = -EPERM; | ||
705 | break; | ||
706 | } | ||
707 | |||
708 | /* @newsid is bounded by @oldsid */ | ||
709 | if (type->bounds == old_context->type) { | ||
710 | rc = 0; | ||
711 | break; | ||
712 | } | ||
713 | index = type->bounds; | ||
714 | } | ||
715 | out: | ||
716 | read_unlock(&policy_rwlock); | ||
717 | |||
718 | return rc; | ||
719 | } | ||
720 | |||
721 | |||
552 | /** | 722 | /** |
553 | * security_compute_av - Compute access vector decisions. | 723 | * security_compute_av - Compute access vector decisions. |
554 | * @ssid: source security identifier | 724 | * @ssid: source security identifier |
@@ -794,7 +964,7 @@ static int string_to_context_struct(struct policydb *pol, | |||
794 | *p++ = 0; | 964 | *p++ = 0; |
795 | 965 | ||
796 | typdatum = hashtab_search(pol->p_types.table, scontextp); | 966 | typdatum = hashtab_search(pol->p_types.table, scontextp); |
797 | if (!typdatum) | 967 | if (!typdatum || typdatum->attribute) |
798 | goto out; | 968 | goto out; |
799 | 969 | ||
800 | ctx->type = typdatum->value; | 970 | ctx->type = typdatum->value; |
@@ -1037,7 +1207,7 @@ static int security_compute_sid(u32 ssid, | |||
1037 | /* If no permanent rule, also check for enabled conditional rules */ | 1207 | /* If no permanent rule, also check for enabled conditional rules */ |
1038 | if (!avdatum) { | 1208 | if (!avdatum) { |
1039 | node = avtab_search_node(&policydb.te_cond_avtab, &avkey); | 1209 | node = avtab_search_node(&policydb.te_cond_avtab, &avkey); |
1040 | for (; node != NULL; node = avtab_search_node_next(node, specified)) { | 1210 | for (; node; node = avtab_search_node_next(node, specified)) { |
1041 | if (node->key.specified & AVTAB_ENABLED) { | 1211 | if (node->key.specified & AVTAB_ENABLED) { |
1042 | avdatum = &node->datum; | 1212 | avdatum = &node->datum; |
1043 | break; | 1213 | break; |
@@ -2050,7 +2220,7 @@ int security_set_bools(int len, int *values) | |||
2050 | policydb.bool_val_to_struct[i]->state = 0; | 2220 | policydb.bool_val_to_struct[i]->state = 0; |
2051 | } | 2221 | } |
2052 | 2222 | ||
2053 | for (cur = policydb.cond_list; cur != NULL; cur = cur->next) { | 2223 | for (cur = policydb.cond_list; cur; cur = cur->next) { |
2054 | rc = evaluate_cond_node(&policydb, cur); | 2224 | rc = evaluate_cond_node(&policydb, cur); |
2055 | if (rc) | 2225 | if (rc) |
2056 | goto out; | 2226 | goto out; |
@@ -2102,7 +2272,7 @@ static int security_preserve_bools(struct policydb *p) | |||
2102 | if (booldatum) | 2272 | if (booldatum) |
2103 | booldatum->state = bvalues[i]; | 2273 | booldatum->state = bvalues[i]; |
2104 | } | 2274 | } |
2105 | for (cur = p->cond_list; cur != NULL; cur = cur->next) { | 2275 | for (cur = p->cond_list; cur; cur = cur->next) { |
2106 | rc = evaluate_cond_node(p, cur); | 2276 | rc = evaluate_cond_node(p, cur); |
2107 | if (rc) | 2277 | if (rc) |
2108 | goto out; | 2278 | goto out; |
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index a81ded104129..e817989764cd 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c | |||
@@ -43,7 +43,7 @@ int sidtab_insert(struct sidtab *s, u32 sid, struct context *context) | |||
43 | hvalue = SIDTAB_HASH(sid); | 43 | hvalue = SIDTAB_HASH(sid); |
44 | prev = NULL; | 44 | prev = NULL; |
45 | cur = s->htable[hvalue]; | 45 | cur = s->htable[hvalue]; |
46 | while (cur != NULL && sid > cur->sid) { | 46 | while (cur && sid > cur->sid) { |
47 | prev = cur; | 47 | prev = cur; |
48 | cur = cur->next; | 48 | cur = cur->next; |
49 | } | 49 | } |
@@ -92,7 +92,7 @@ static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force) | |||
92 | 92 | ||
93 | hvalue = SIDTAB_HASH(sid); | 93 | hvalue = SIDTAB_HASH(sid); |
94 | cur = s->htable[hvalue]; | 94 | cur = s->htable[hvalue]; |
95 | while (cur != NULL && sid > cur->sid) | 95 | while (cur && sid > cur->sid) |
96 | cur = cur->next; | 96 | cur = cur->next; |
97 | 97 | ||
98 | if (force && cur && sid == cur->sid && cur->context.len) | 98 | if (force && cur && sid == cur->sid && cur->context.len) |
@@ -103,7 +103,7 @@ static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force) | |||
103 | sid = SECINITSID_UNLABELED; | 103 | sid = SECINITSID_UNLABELED; |
104 | hvalue = SIDTAB_HASH(sid); | 104 | hvalue = SIDTAB_HASH(sid); |
105 | cur = s->htable[hvalue]; | 105 | cur = s->htable[hvalue]; |
106 | while (cur != NULL && sid > cur->sid) | 106 | while (cur && sid > cur->sid) |
107 | cur = cur->next; | 107 | cur = cur->next; |
108 | if (!cur || sid != cur->sid) | 108 | if (!cur || sid != cur->sid) |
109 | return NULL; | 109 | return NULL; |
@@ -136,7 +136,7 @@ int sidtab_map(struct sidtab *s, | |||
136 | 136 | ||
137 | for (i = 0; i < SIDTAB_SIZE; i++) { | 137 | for (i = 0; i < SIDTAB_SIZE; i++) { |
138 | cur = s->htable[i]; | 138 | cur = s->htable[i]; |
139 | while (cur != NULL) { | 139 | while (cur) { |
140 | rc = apply(cur->sid, &cur->context, args); | 140 | rc = apply(cur->sid, &cur->context, args); |
141 | if (rc) | 141 | if (rc) |
142 | goto out; | 142 | goto out; |
@@ -155,7 +155,7 @@ static inline u32 sidtab_search_context(struct sidtab *s, | |||
155 | 155 | ||
156 | for (i = 0; i < SIDTAB_SIZE; i++) { | 156 | for (i = 0; i < SIDTAB_SIZE; i++) { |
157 | cur = s->htable[i]; | 157 | cur = s->htable[i]; |
158 | while (cur != NULL) { | 158 | while (cur) { |
159 | if (context_cmp(&cur->context, context)) | 159 | if (context_cmp(&cur->context, context)) |
160 | return cur->sid; | 160 | return cur->sid; |
161 | cur = cur->next; | 161 | cur = cur->next; |
@@ -242,7 +242,7 @@ void sidtab_destroy(struct sidtab *s) | |||
242 | 242 | ||
243 | for (i = 0; i < SIDTAB_SIZE; i++) { | 243 | for (i = 0; i < SIDTAB_SIZE; i++) { |
244 | cur = s->htable[i]; | 244 | cur = s->htable[i]; |
245 | while (cur != NULL) { | 245 | while (cur) { |
246 | temp = cur; | 246 | temp = cur; |
247 | cur = cur->next; | 247 | cur = cur->next; |
248 | context_destroy(&temp->context); | 248 | context_destroy(&temp->context); |
diff --git a/security/smack/smack.h b/security/smack/smack.h index 4a4477f5afdc..31dce559595a 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -178,6 +178,7 @@ u32 smack_to_secid(const char *); | |||
178 | extern int smack_cipso_direct; | 178 | extern int smack_cipso_direct; |
179 | extern int smack_net_nltype; | 179 | extern int smack_net_nltype; |
180 | extern char *smack_net_ambient; | 180 | extern char *smack_net_ambient; |
181 | extern char *smack_onlycap; | ||
181 | 182 | ||
182 | extern struct smack_known *smack_known; | 183 | extern struct smack_known *smack_known; |
183 | extern struct smack_known smack_known_floor; | 184 | extern struct smack_known smack_known_floor; |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index f6b5f6eed6dd..79ff21ed4c3b 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -157,7 +157,7 @@ int smk_access(char *subject_label, char *object_label, int request) | |||
157 | * | 157 | * |
158 | * This function checks the current subject label/object label pair | 158 | * This function checks the current subject label/object label pair |
159 | * in the access rule list and returns 0 if the access is permitted, | 159 | * in the access rule list and returns 0 if the access is permitted, |
160 | * non zero otherwise. It allows that current my have the capability | 160 | * non zero otherwise. It allows that current may have the capability |
161 | * to override the rules. | 161 | * to override the rules. |
162 | */ | 162 | */ |
163 | int smk_curacc(char *obj_label, u32 mode) | 163 | int smk_curacc(char *obj_label, u32 mode) |
@@ -168,6 +168,14 @@ int smk_curacc(char *obj_label, u32 mode) | |||
168 | if (rc == 0) | 168 | if (rc == 0) |
169 | return 0; | 169 | return 0; |
170 | 170 | ||
171 | /* | ||
172 | * Return if a specific label has been designated as the | ||
173 | * only one that gets privilege and current does not | ||
174 | * have that label. | ||
175 | */ | ||
176 | if (smack_onlycap != NULL && smack_onlycap != current->security) | ||
177 | return rc; | ||
178 | |||
171 | if (capable(CAP_MAC_OVERRIDE)) | 179 | if (capable(CAP_MAC_OVERRIDE)) |
172 | return 0; | 180 | return 0; |
173 | 181 | ||
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 271a835fbbe3..e7c642458ec9 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -39,6 +39,7 @@ enum smk_inos { | |||
39 | SMK_DIRECT = 6, /* CIPSO level indicating direct label */ | 39 | SMK_DIRECT = 6, /* CIPSO level indicating direct label */ |
40 | SMK_AMBIENT = 7, /* internet ambient label */ | 40 | SMK_AMBIENT = 7, /* internet ambient label */ |
41 | SMK_NLTYPE = 8, /* label scheme to use by default */ | 41 | SMK_NLTYPE = 8, /* label scheme to use by default */ |
42 | SMK_ONLYCAP = 9, /* the only "capable" label */ | ||
42 | }; | 43 | }; |
43 | 44 | ||
44 | /* | 45 | /* |
@@ -68,6 +69,16 @@ int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4; | |||
68 | */ | 69 | */ |
69 | int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT; | 70 | int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT; |
70 | 71 | ||
72 | /* | ||
73 | * Unless a process is running with this label even | ||
74 | * having CAP_MAC_OVERRIDE isn't enough to grant | ||
75 | * privilege to violate MAC policy. If no label is | ||
76 | * designated (the NULL case) capabilities apply to | ||
77 | * everyone. It is expected that the hat (^) label | ||
78 | * will be used if any label is used. | ||
79 | */ | ||
80 | char *smack_onlycap; | ||
81 | |||
71 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; | 82 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; |
72 | struct smk_list_entry *smack_list; | 83 | struct smk_list_entry *smack_list; |
73 | 84 | ||
@@ -787,6 +798,85 @@ static const struct file_operations smk_ambient_ops = { | |||
787 | .write = smk_write_ambient, | 798 | .write = smk_write_ambient, |
788 | }; | 799 | }; |
789 | 800 | ||
801 | /** | ||
802 | * smk_read_onlycap - read() for /smack/onlycap | ||
803 | * @filp: file pointer, not actually used | ||
804 | * @buf: where to put the result | ||
805 | * @cn: maximum to send along | ||
806 | * @ppos: where to start | ||
807 | * | ||
808 | * Returns number of bytes read or error code, as appropriate | ||
809 | */ | ||
810 | static ssize_t smk_read_onlycap(struct file *filp, char __user *buf, | ||
811 | size_t cn, loff_t *ppos) | ||
812 | { | ||
813 | char *smack = ""; | ||
814 | ssize_t rc = -EINVAL; | ||
815 | int asize; | ||
816 | |||
817 | if (*ppos != 0) | ||
818 | return 0; | ||
819 | |||
820 | if (smack_onlycap != NULL) | ||
821 | smack = smack_onlycap; | ||
822 | |||
823 | asize = strlen(smack) + 1; | ||
824 | |||
825 | if (cn >= asize) | ||
826 | rc = simple_read_from_buffer(buf, cn, ppos, smack, asize); | ||
827 | |||
828 | return rc; | ||
829 | } | ||
830 | |||
831 | /** | ||
832 | * smk_write_onlycap - write() for /smack/onlycap | ||
833 | * @filp: file pointer, not actually used | ||
834 | * @buf: where to get the data from | ||
835 | * @count: bytes sent | ||
836 | * @ppos: where to start | ||
837 | * | ||
838 | * Returns number of bytes written or error code, as appropriate | ||
839 | */ | ||
840 | static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | ||
841 | size_t count, loff_t *ppos) | ||
842 | { | ||
843 | char in[SMK_LABELLEN]; | ||
844 | char *sp = current->security; | ||
845 | |||
846 | if (!capable(CAP_MAC_ADMIN)) | ||
847 | return -EPERM; | ||
848 | |||
849 | /* | ||
850 | * This can be done using smk_access() but is done | ||
851 | * explicitly for clarity. The smk_access() implementation | ||
852 | * would use smk_access(smack_onlycap, MAY_WRITE) | ||
853 | */ | ||
854 | if (smack_onlycap != NULL && smack_onlycap != sp) | ||
855 | return -EPERM; | ||
856 | |||
857 | if (count >= SMK_LABELLEN) | ||
858 | return -EINVAL; | ||
859 | |||
860 | if (copy_from_user(in, buf, count) != 0) | ||
861 | return -EFAULT; | ||
862 | |||
863 | /* | ||
864 | * Should the null string be passed in unset the onlycap value. | ||
865 | * This seems like something to be careful with as usually | ||
866 | * smk_import only expects to return NULL for errors. It | ||
867 | * is usually the case that a nullstring or "\n" would be | ||
868 | * bad to pass to smk_import but in fact this is useful here. | ||
869 | */ | ||
870 | smack_onlycap = smk_import(in, count); | ||
871 | |||
872 | return count; | ||
873 | } | ||
874 | |||
875 | static const struct file_operations smk_onlycap_ops = { | ||
876 | .read = smk_read_onlycap, | ||
877 | .write = smk_write_onlycap, | ||
878 | }; | ||
879 | |||
790 | struct option_names { | 880 | struct option_names { |
791 | int o_number; | 881 | int o_number; |
792 | char *o_name; | 882 | char *o_name; |
@@ -919,6 +1009,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
919 | {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, | 1009 | {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, |
920 | [SMK_NLTYPE] = | 1010 | [SMK_NLTYPE] = |
921 | {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR}, | 1011 | {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR}, |
1012 | [SMK_ONLYCAP] = | ||
1013 | {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, | ||
922 | /* last one */ {""} | 1014 | /* last one */ {""} |
923 | }; | 1015 | }; |
924 | 1016 | ||