diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-10-28 11:26:12 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-28 11:26:12 -0400 |
commit | 7a9787e1eba95a166265e6a260cf30af04ef0a99 (patch) | |
tree | e730a4565e0318140d2fbd2f0415d18a339d7336 /security | |
parent | 41b9eb264c8407655db57b60b4457fe1b2ec9977 (diff) | |
parent | 0173a3265b228da319ceb9c1ec6a5682fd1b2d92 (diff) |
Merge commit 'v2.6.28-rc2' into x86/pci-ioapic-boot-irq-quirks
Diffstat (limited to 'security')
30 files changed, 1332 insertions, 515 deletions
diff --git a/security/Kconfig b/security/Kconfig index 62ed4717d334..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 |
@@ -74,8 +82,7 @@ config SECURITY_NETWORK_XFRM | |||
74 | If you are unsure how to answer this question, answer N. | 82 | If you are unsure how to answer this question, answer N. |
75 | 83 | ||
76 | config SECURITY_FILE_CAPABILITIES | 84 | config SECURITY_FILE_CAPABILITIES |
77 | bool "File POSIX Capabilities (EXPERIMENTAL)" | 85 | bool "File POSIX Capabilities" |
78 | depends on EXPERIMENTAL | ||
79 | default n | 86 | default n |
80 | help | 87 | help |
81 | This enables filesystem capabilities, allowing you to give | 88 | This enables filesystem capabilities, allowing you to give |
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/capability.c b/security/capability.c index 5b01c0b02422..245874819036 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -211,8 +211,7 @@ static int cap_inode_follow_link(struct dentry *dentry, | |||
211 | return 0; | 211 | return 0; |
212 | } | 212 | } |
213 | 213 | ||
214 | static int cap_inode_permission(struct inode *inode, int mask, | 214 | static int cap_inode_permission(struct inode *inode, int mask) |
215 | struct nameidata *nd) | ||
216 | { | 215 | { |
217 | return 0; | 216 | return 0; |
218 | } | 217 | } |
@@ -812,7 +811,8 @@ struct security_operations default_security_ops = { | |||
812 | 811 | ||
813 | void security_fixup_ops(struct security_operations *ops) | 812 | void security_fixup_ops(struct security_operations *ops) |
814 | { | 813 | { |
815 | set_to_cap_if_null(ops, ptrace); | 814 | set_to_cap_if_null(ops, ptrace_may_access); |
815 | set_to_cap_if_null(ops, ptrace_traceme); | ||
816 | set_to_cap_if_null(ops, capget); | 816 | set_to_cap_if_null(ops, capget); |
817 | set_to_cap_if_null(ops, capset_check); | 817 | set_to_cap_if_null(ops, capset_check); |
818 | set_to_cap_if_null(ops, capset_set); | 818 | set_to_cap_if_null(ops, capset_set); |
diff --git a/security/commoncap.c b/security/commoncap.c index 0b6537a3672d..399bfdb9e2da 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -63,14 +63,24 @@ int cap_settime(struct timespec *ts, struct timezone *tz) | |||
63 | return 0; | 63 | return 0; |
64 | } | 64 | } |
65 | 65 | ||
66 | int cap_ptrace (struct task_struct *parent, struct task_struct *child, | 66 | int cap_ptrace_may_access(struct task_struct *child, unsigned int mode) |
67 | unsigned int mode) | ||
68 | { | 67 | { |
69 | /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */ | 68 | /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */ |
70 | if (!cap_issubset(child->cap_permitted, parent->cap_permitted) && | 69 | if (cap_issubset(child->cap_permitted, current->cap_permitted)) |
71 | !__capable(parent, CAP_SYS_PTRACE)) | 70 | return 0; |
72 | return -EPERM; | 71 | if (capable(CAP_SYS_PTRACE)) |
73 | return 0; | 72 | return 0; |
73 | return -EPERM; | ||
74 | } | ||
75 | |||
76 | int cap_ptrace_traceme(struct task_struct *parent) | ||
77 | { | ||
78 | /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */ | ||
79 | if (cap_issubset(current->cap_permitted, parent->cap_permitted)) | ||
80 | return 0; | ||
81 | if (has_capability(parent, CAP_SYS_PTRACE)) | ||
82 | return 0; | ||
83 | return -EPERM; | ||
74 | } | 84 | } |
75 | 85 | ||
76 | int cap_capget (struct task_struct *target, kernel_cap_t *effective, | 86 | int cap_capget (struct task_struct *target, kernel_cap_t *effective, |
@@ -162,8 +172,7 @@ void cap_capset_set (struct task_struct *target, kernel_cap_t *effective, | |||
162 | 172 | ||
163 | static inline void bprm_clear_caps(struct linux_binprm *bprm) | 173 | static inline void bprm_clear_caps(struct linux_binprm *bprm) |
164 | { | 174 | { |
165 | cap_clear(bprm->cap_inheritable); | 175 | cap_clear(bprm->cap_post_exec_permitted); |
166 | cap_clear(bprm->cap_permitted); | ||
167 | bprm->cap_effective = false; | 176 | bprm->cap_effective = false; |
168 | } | 177 | } |
169 | 178 | ||
@@ -198,6 +207,7 @@ static inline int cap_from_disk(struct vfs_cap_data *caps, | |||
198 | { | 207 | { |
199 | __u32 magic_etc; | 208 | __u32 magic_etc; |
200 | unsigned tocopy, i; | 209 | unsigned tocopy, i; |
210 | int ret; | ||
201 | 211 | ||
202 | if (size < sizeof(magic_etc)) | 212 | if (size < sizeof(magic_etc)) |
203 | return -EINVAL; | 213 | return -EINVAL; |
@@ -225,19 +235,40 @@ static inline int cap_from_disk(struct vfs_cap_data *caps, | |||
225 | bprm->cap_effective = false; | 235 | bprm->cap_effective = false; |
226 | } | 236 | } |
227 | 237 | ||
228 | for (i = 0; i < tocopy; ++i) { | 238 | ret = 0; |
229 | bprm->cap_permitted.cap[i] = | 239 | |
230 | le32_to_cpu(caps->data[i].permitted); | 240 | CAP_FOR_EACH_U32(i) { |
231 | bprm->cap_inheritable.cap[i] = | 241 | __u32 value_cpu; |
232 | le32_to_cpu(caps->data[i].inheritable); | 242 | |
233 | } | 243 | if (i >= tocopy) { |
234 | while (i < VFS_CAP_U32) { | 244 | /* |
235 | bprm->cap_permitted.cap[i] = 0; | 245 | * Legacy capability sets have no upper bits |
236 | bprm->cap_inheritable.cap[i] = 0; | 246 | */ |
237 | i++; | 247 | bprm->cap_post_exec_permitted.cap[i] = 0; |
248 | continue; | ||
249 | } | ||
250 | /* | ||
251 | * pP' = (X & fP) | (pI & fI) | ||
252 | */ | ||
253 | value_cpu = le32_to_cpu(caps->data[i].permitted); | ||
254 | bprm->cap_post_exec_permitted.cap[i] = | ||
255 | (current->cap_bset.cap[i] & value_cpu) | | ||
256 | (current->cap_inheritable.cap[i] & | ||
257 | le32_to_cpu(caps->data[i].inheritable)); | ||
258 | if (value_cpu & ~bprm->cap_post_exec_permitted.cap[i]) { | ||
259 | /* | ||
260 | * insufficient to execute correctly | ||
261 | */ | ||
262 | ret = -EPERM; | ||
263 | } | ||
238 | } | 264 | } |
239 | 265 | ||
240 | return 0; | 266 | /* |
267 | * For legacy apps, with no internal support for recognizing they | ||
268 | * do not have enough capabilities, we return an error if they are | ||
269 | * missing some "forced" (aka file-permitted) capabilities. | ||
270 | */ | ||
271 | return bprm->cap_effective ? ret : 0; | ||
241 | } | 272 | } |
242 | 273 | ||
243 | /* Locate any VFS capabilities: */ | 274 | /* Locate any VFS capabilities: */ |
@@ -269,9 +300,9 @@ static int get_file_caps(struct linux_binprm *bprm) | |||
269 | goto out; | 300 | goto out; |
270 | 301 | ||
271 | rc = cap_from_disk(&vcaps, bprm, rc); | 302 | rc = cap_from_disk(&vcaps, bprm, rc); |
272 | if (rc) | 303 | if (rc == -EINVAL) |
273 | printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", | 304 | printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", |
274 | __func__, rc, bprm->filename); | 305 | __func__, rc, bprm->filename); |
275 | 306 | ||
276 | out: | 307 | out: |
277 | dput(dentry); | 308 | dput(dentry); |
@@ -304,25 +335,24 @@ int cap_bprm_set_security (struct linux_binprm *bprm) | |||
304 | int ret; | 335 | int ret; |
305 | 336 | ||
306 | ret = get_file_caps(bprm); | 337 | ret = get_file_caps(bprm); |
307 | if (ret) | ||
308 | printk(KERN_NOTICE "%s: get_file_caps returned %d for %s\n", | ||
309 | __func__, ret, bprm->filename); | ||
310 | |||
311 | /* To support inheritance of root-permissions and suid-root | ||
312 | * executables under compatibility mode, we raise all three | ||
313 | * capability sets for the file. | ||
314 | * | ||
315 | * If only the real uid is 0, we only raise the inheritable | ||
316 | * and permitted sets of the executable file. | ||
317 | */ | ||
318 | 338 | ||
319 | if (!issecure (SECURE_NOROOT)) { | 339 | if (!issecure(SECURE_NOROOT)) { |
340 | /* | ||
341 | * To support inheritance of root-permissions and suid-root | ||
342 | * executables under compatibility mode, we override the | ||
343 | * capability sets for the file. | ||
344 | * | ||
345 | * If only the real uid is 0, we do not set the effective | ||
346 | * bit. | ||
347 | */ | ||
320 | if (bprm->e_uid == 0 || current->uid == 0) { | 348 | if (bprm->e_uid == 0 || current->uid == 0) { |
321 | cap_set_full (bprm->cap_inheritable); | 349 | /* pP' = (cap_bset & ~0) | (pI & ~0) */ |
322 | cap_set_full (bprm->cap_permitted); | 350 | bprm->cap_post_exec_permitted = cap_combine( |
351 | current->cap_bset, current->cap_inheritable | ||
352 | ); | ||
353 | bprm->cap_effective = (bprm->e_uid == 0); | ||
354 | ret = 0; | ||
323 | } | 355 | } |
324 | if (bprm->e_uid == 0) | ||
325 | bprm->cap_effective = true; | ||
326 | } | 356 | } |
327 | 357 | ||
328 | return ret; | 358 | return ret; |
@@ -330,17 +360,9 @@ int cap_bprm_set_security (struct linux_binprm *bprm) | |||
330 | 360 | ||
331 | void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | 361 | void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) |
332 | { | 362 | { |
333 | /* Derived from fs/exec.c:compute_creds. */ | ||
334 | kernel_cap_t new_permitted, working; | ||
335 | |||
336 | new_permitted = cap_intersect(bprm->cap_permitted, | ||
337 | current->cap_bset); | ||
338 | working = cap_intersect(bprm->cap_inheritable, | ||
339 | current->cap_inheritable); | ||
340 | new_permitted = cap_combine(new_permitted, working); | ||
341 | |||
342 | if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || | 363 | if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || |
343 | !cap_issubset (new_permitted, current->cap_permitted)) { | 364 | !cap_issubset(bprm->cap_post_exec_permitted, |
365 | current->cap_permitted)) { | ||
344 | set_dumpable(current->mm, suid_dumpable); | 366 | set_dumpable(current->mm, suid_dumpable); |
345 | current->pdeath_signal = 0; | 367 | current->pdeath_signal = 0; |
346 | 368 | ||
@@ -350,9 +372,9 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | |||
350 | bprm->e_gid = current->gid; | 372 | bprm->e_gid = current->gid; |
351 | } | 373 | } |
352 | if (cap_limit_ptraced_target()) { | 374 | if (cap_limit_ptraced_target()) { |
353 | new_permitted = | 375 | bprm->cap_post_exec_permitted = cap_intersect( |
354 | cap_intersect(new_permitted, | 376 | bprm->cap_post_exec_permitted, |
355 | current->cap_permitted); | 377 | current->cap_permitted); |
356 | } | 378 | } |
357 | } | 379 | } |
358 | } | 380 | } |
@@ -364,9 +386,9 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | |||
364 | * in the init_task struct. Thus we skip the usual | 386 | * in the init_task struct. Thus we skip the usual |
365 | * capability rules */ | 387 | * capability rules */ |
366 | if (!is_global_init(current)) { | 388 | if (!is_global_init(current)) { |
367 | current->cap_permitted = new_permitted; | 389 | current->cap_permitted = bprm->cap_post_exec_permitted; |
368 | if (bprm->cap_effective) | 390 | if (bprm->cap_effective) |
369 | current->cap_effective = new_permitted; | 391 | current->cap_effective = bprm->cap_post_exec_permitted; |
370 | else | 392 | else |
371 | cap_clear(current->cap_effective); | 393 | cap_clear(current->cap_effective); |
372 | } | 394 | } |
@@ -381,9 +403,7 @@ int cap_bprm_secureexec (struct linux_binprm *bprm) | |||
381 | if (current->uid != 0) { | 403 | if (current->uid != 0) { |
382 | if (bprm->cap_effective) | 404 | if (bprm->cap_effective) |
383 | return 1; | 405 | return 1; |
384 | if (!cap_isclear(bprm->cap_permitted)) | 406 | if (!cap_isclear(bprm->cap_post_exec_permitted)) |
385 | return 1; | ||
386 | if (!cap_isclear(bprm->cap_inheritable)) | ||
387 | return 1; | 407 | return 1; |
388 | } | 408 | } |
389 | 409 | ||
@@ -521,10 +541,10 @@ int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, | |||
521 | * yet with increased caps. | 541 | * yet with increased caps. |
522 | * So we check for increased caps on the target process. | 542 | * So we check for increased caps on the target process. |
523 | */ | 543 | */ |
524 | static inline int cap_safe_nice(struct task_struct *p) | 544 | static int cap_safe_nice(struct task_struct *p) |
525 | { | 545 | { |
526 | if (!cap_issubset(p->cap_permitted, current->cap_permitted) && | 546 | if (!cap_issubset(p->cap_permitted, current->cap_permitted) && |
527 | !__capable(current, CAP_SYS_NICE)) | 547 | !capable(CAP_SYS_NICE)) |
528 | return -EPERM; | 548 | return -EPERM; |
529 | return 0; | 549 | return 0; |
530 | } | 550 | } |
diff --git a/security/device_cgroup.c b/security/device_cgroup.c index ddd92cec78ed..5ba78701adc3 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * dev_cgroup.c - device cgroup subsystem | 2 | * device_cgroup.c - device cgroup subsystem |
3 | * | 3 | * |
4 | * Copyright 2007 IBM Corp | 4 | * Copyright 2007 IBM Corp |
5 | */ | 5 | */ |
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/list.h> | 10 | #include <linux/list.h> |
11 | #include <linux/uaccess.h> | 11 | #include <linux/uaccess.h> |
12 | #include <linux/seq_file.h> | 12 | #include <linux/seq_file.h> |
13 | #include <linux/rcupdate.h> | ||
13 | 14 | ||
14 | #define ACC_MKNOD 1 | 15 | #define ACC_MKNOD 1 |
15 | #define ACC_READ 2 | 16 | #define ACC_READ 2 |
@@ -22,18 +23,8 @@ | |||
22 | 23 | ||
23 | /* | 24 | /* |
24 | * whitelist locking rules: | 25 | * whitelist locking rules: |
25 | * cgroup_lock() cannot be taken under dev_cgroup->lock. | 26 | * hold cgroup_lock() for update/read. |
26 | * dev_cgroup->lock can be taken with or without cgroup_lock(). | 27 | * hold rcu_read_lock() for read. |
27 | * | ||
28 | * modifications always require cgroup_lock | ||
29 | * modifications to a list which is visible require the | ||
30 | * dev_cgroup->lock *and* cgroup_lock() | ||
31 | * walking the list requires dev_cgroup->lock or cgroup_lock(). | ||
32 | * | ||
33 | * reasoning: dev_whitelist_copy() needs to kmalloc, so needs | ||
34 | * a mutex, which the cgroup_lock() is. Since modifying | ||
35 | * a visible list requires both locks, either lock can be | ||
36 | * taken for walking the list. | ||
37 | */ | 28 | */ |
38 | 29 | ||
39 | struct dev_whitelist_item { | 30 | struct dev_whitelist_item { |
@@ -41,12 +32,12 @@ struct dev_whitelist_item { | |||
41 | short type; | 32 | short type; |
42 | short access; | 33 | short access; |
43 | struct list_head list; | 34 | struct list_head list; |
35 | struct rcu_head rcu; | ||
44 | }; | 36 | }; |
45 | 37 | ||
46 | struct dev_cgroup { | 38 | struct dev_cgroup { |
47 | struct cgroup_subsys_state css; | 39 | struct cgroup_subsys_state css; |
48 | struct list_head whitelist; | 40 | struct list_head whitelist; |
49 | spinlock_t lock; | ||
50 | }; | 41 | }; |
51 | 42 | ||
52 | static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s) | 43 | static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s) |
@@ -59,6 +50,11 @@ static inline struct dev_cgroup *cgroup_to_devcgroup(struct cgroup *cgroup) | |||
59 | return css_to_devcgroup(cgroup_subsys_state(cgroup, devices_subsys_id)); | 50 | return css_to_devcgroup(cgroup_subsys_state(cgroup, devices_subsys_id)); |
60 | } | 51 | } |
61 | 52 | ||
53 | static inline struct dev_cgroup *task_devcgroup(struct task_struct *task) | ||
54 | { | ||
55 | return css_to_devcgroup(task_subsys_state(task, devices_subsys_id)); | ||
56 | } | ||
57 | |||
62 | struct cgroup_subsys devices_subsys; | 58 | struct cgroup_subsys devices_subsys; |
63 | 59 | ||
64 | static int devcgroup_can_attach(struct cgroup_subsys *ss, | 60 | static int devcgroup_can_attach(struct cgroup_subsys *ss, |
@@ -78,13 +74,9 @@ static int dev_whitelist_copy(struct list_head *dest, struct list_head *orig) | |||
78 | struct dev_whitelist_item *wh, *tmp, *new; | 74 | struct dev_whitelist_item *wh, *tmp, *new; |
79 | 75 | ||
80 | list_for_each_entry(wh, orig, list) { | 76 | list_for_each_entry(wh, orig, list) { |
81 | new = kmalloc(sizeof(*wh), GFP_KERNEL); | 77 | new = kmemdup(wh, sizeof(*wh), GFP_KERNEL); |
82 | if (!new) | 78 | if (!new) |
83 | goto free_and_exit; | 79 | goto free_and_exit; |
84 | new->major = wh->major; | ||
85 | new->minor = wh->minor; | ||
86 | new->type = wh->type; | ||
87 | new->access = wh->access; | ||
88 | list_add_tail(&new->list, dest); | 80 | list_add_tail(&new->list, dest); |
89 | } | 81 | } |
90 | 82 | ||
@@ -101,19 +93,16 @@ free_and_exit: | |||
101 | /* Stupid prototype - don't bother combining existing entries */ | 93 | /* Stupid prototype - don't bother combining existing entries */ |
102 | /* | 94 | /* |
103 | * called under cgroup_lock() | 95 | * called under cgroup_lock() |
104 | * since the list is visible to other tasks, we need the spinlock also | ||
105 | */ | 96 | */ |
106 | static int dev_whitelist_add(struct dev_cgroup *dev_cgroup, | 97 | static int dev_whitelist_add(struct dev_cgroup *dev_cgroup, |
107 | struct dev_whitelist_item *wh) | 98 | struct dev_whitelist_item *wh) |
108 | { | 99 | { |
109 | struct dev_whitelist_item *whcopy, *walk; | 100 | struct dev_whitelist_item *whcopy, *walk; |
110 | 101 | ||
111 | whcopy = kmalloc(sizeof(*whcopy), GFP_KERNEL); | 102 | whcopy = kmemdup(wh, sizeof(*wh), GFP_KERNEL); |
112 | if (!whcopy) | 103 | if (!whcopy) |
113 | return -ENOMEM; | 104 | return -ENOMEM; |
114 | 105 | ||
115 | memcpy(whcopy, wh, sizeof(*whcopy)); | ||
116 | spin_lock(&dev_cgroup->lock); | ||
117 | list_for_each_entry(walk, &dev_cgroup->whitelist, list) { | 106 | list_for_each_entry(walk, &dev_cgroup->whitelist, list) { |
118 | if (walk->type != wh->type) | 107 | if (walk->type != wh->type) |
119 | continue; | 108 | continue; |
@@ -128,21 +117,26 @@ static int dev_whitelist_add(struct dev_cgroup *dev_cgroup, | |||
128 | } | 117 | } |
129 | 118 | ||
130 | if (whcopy != NULL) | 119 | if (whcopy != NULL) |
131 | list_add_tail(&whcopy->list, &dev_cgroup->whitelist); | 120 | list_add_tail_rcu(&whcopy->list, &dev_cgroup->whitelist); |
132 | spin_unlock(&dev_cgroup->lock); | ||
133 | return 0; | 121 | return 0; |
134 | } | 122 | } |
135 | 123 | ||
124 | static void whitelist_item_free(struct rcu_head *rcu) | ||
125 | { | ||
126 | struct dev_whitelist_item *item; | ||
127 | |||
128 | item = container_of(rcu, struct dev_whitelist_item, rcu); | ||
129 | kfree(item); | ||
130 | } | ||
131 | |||
136 | /* | 132 | /* |
137 | * called under cgroup_lock() | 133 | * called under cgroup_lock() |
138 | * since the list is visible to other tasks, we need the spinlock also | ||
139 | */ | 134 | */ |
140 | static void dev_whitelist_rm(struct dev_cgroup *dev_cgroup, | 135 | static void dev_whitelist_rm(struct dev_cgroup *dev_cgroup, |
141 | struct dev_whitelist_item *wh) | 136 | struct dev_whitelist_item *wh) |
142 | { | 137 | { |
143 | struct dev_whitelist_item *walk, *tmp; | 138 | struct dev_whitelist_item *walk, *tmp; |
144 | 139 | ||
145 | spin_lock(&dev_cgroup->lock); | ||
146 | list_for_each_entry_safe(walk, tmp, &dev_cgroup->whitelist, list) { | 140 | list_for_each_entry_safe(walk, tmp, &dev_cgroup->whitelist, list) { |
147 | if (walk->type == DEV_ALL) | 141 | if (walk->type == DEV_ALL) |
148 | goto remove; | 142 | goto remove; |
@@ -156,11 +150,10 @@ static void dev_whitelist_rm(struct dev_cgroup *dev_cgroup, | |||
156 | remove: | 150 | remove: |
157 | walk->access &= ~wh->access; | 151 | walk->access &= ~wh->access; |
158 | if (!walk->access) { | 152 | if (!walk->access) { |
159 | list_del(&walk->list); | 153 | list_del_rcu(&walk->list); |
160 | kfree(walk); | 154 | call_rcu(&walk->rcu, whitelist_item_free); |
161 | } | 155 | } |
162 | } | 156 | } |
163 | spin_unlock(&dev_cgroup->lock); | ||
164 | } | 157 | } |
165 | 158 | ||
166 | /* | 159 | /* |
@@ -188,7 +181,7 @@ static struct cgroup_subsys_state *devcgroup_create(struct cgroup_subsys *ss, | |||
188 | } | 181 | } |
189 | wh->minor = wh->major = ~0; | 182 | wh->minor = wh->major = ~0; |
190 | wh->type = DEV_ALL; | 183 | wh->type = DEV_ALL; |
191 | wh->access = ACC_MKNOD | ACC_READ | ACC_WRITE; | 184 | wh->access = ACC_MASK; |
192 | list_add(&wh->list, &dev_cgroup->whitelist); | 185 | list_add(&wh->list, &dev_cgroup->whitelist); |
193 | } else { | 186 | } else { |
194 | parent_dev_cgroup = cgroup_to_devcgroup(parent_cgroup); | 187 | parent_dev_cgroup = cgroup_to_devcgroup(parent_cgroup); |
@@ -200,7 +193,6 @@ static struct cgroup_subsys_state *devcgroup_create(struct cgroup_subsys *ss, | |||
200 | } | 193 | } |
201 | } | 194 | } |
202 | 195 | ||
203 | spin_lock_init(&dev_cgroup->lock); | ||
204 | return &dev_cgroup->css; | 196 | return &dev_cgroup->css; |
205 | } | 197 | } |
206 | 198 | ||
@@ -250,11 +242,10 @@ static char type_to_char(short type) | |||
250 | 242 | ||
251 | static void set_majmin(char *str, unsigned m) | 243 | static void set_majmin(char *str, unsigned m) |
252 | { | 244 | { |
253 | memset(str, 0, MAJMINLEN); | ||
254 | if (m == ~0) | 245 | if (m == ~0) |
255 | sprintf(str, "*"); | 246 | strcpy(str, "*"); |
256 | else | 247 | else |
257 | snprintf(str, MAJMINLEN, "%u", m); | 248 | sprintf(str, "%u", m); |
258 | } | 249 | } |
259 | 250 | ||
260 | static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft, | 251 | static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft, |
@@ -264,15 +255,15 @@ static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft, | |||
264 | struct dev_whitelist_item *wh; | 255 | struct dev_whitelist_item *wh; |
265 | char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN]; | 256 | char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN]; |
266 | 257 | ||
267 | spin_lock(&devcgroup->lock); | 258 | rcu_read_lock(); |
268 | list_for_each_entry(wh, &devcgroup->whitelist, list) { | 259 | list_for_each_entry_rcu(wh, &devcgroup->whitelist, list) { |
269 | set_access(acc, wh->access); | 260 | set_access(acc, wh->access); |
270 | set_majmin(maj, wh->major); | 261 | set_majmin(maj, wh->major); |
271 | set_majmin(min, wh->minor); | 262 | set_majmin(min, wh->minor); |
272 | seq_printf(m, "%c %s:%s %s\n", type_to_char(wh->type), | 263 | seq_printf(m, "%c %s:%s %s\n", type_to_char(wh->type), |
273 | maj, min, acc); | 264 | maj, min, acc); |
274 | } | 265 | } |
275 | spin_unlock(&devcgroup->lock); | 266 | rcu_read_unlock(); |
276 | 267 | ||
277 | return 0; | 268 | return 0; |
278 | } | 269 | } |
@@ -312,20 +303,16 @@ static int may_access_whitelist(struct dev_cgroup *c, | |||
312 | * when adding a new allow rule to a device whitelist, the rule | 303 | * when adding a new allow rule to a device whitelist, the rule |
313 | * must be allowed in the parent device | 304 | * must be allowed in the parent device |
314 | */ | 305 | */ |
315 | static int parent_has_perm(struct cgroup *childcg, | 306 | static int parent_has_perm(struct dev_cgroup *childcg, |
316 | struct dev_whitelist_item *wh) | 307 | struct dev_whitelist_item *wh) |
317 | { | 308 | { |
318 | struct cgroup *pcg = childcg->parent; | 309 | struct cgroup *pcg = childcg->css.cgroup->parent; |
319 | struct dev_cgroup *parent; | 310 | struct dev_cgroup *parent; |
320 | int ret; | ||
321 | 311 | ||
322 | if (!pcg) | 312 | if (!pcg) |
323 | return 1; | 313 | return 1; |
324 | parent = cgroup_to_devcgroup(pcg); | 314 | parent = cgroup_to_devcgroup(pcg); |
325 | spin_lock(&parent->lock); | 315 | return may_access_whitelist(parent, wh); |
326 | ret = may_access_whitelist(parent, wh); | ||
327 | spin_unlock(&parent->lock); | ||
328 | return ret; | ||
329 | } | 316 | } |
330 | 317 | ||
331 | /* | 318 | /* |
@@ -341,40 +328,17 @@ static int parent_has_perm(struct cgroup *childcg, | |||
341 | * new access is only allowed if you're in the top-level cgroup, or your | 328 | * new access is only allowed if you're in the top-level cgroup, or your |
342 | * parent cgroup has the access you're asking for. | 329 | * parent cgroup has the access you're asking for. |
343 | */ | 330 | */ |
344 | static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft, | 331 | static int devcgroup_update_access(struct dev_cgroup *devcgroup, |
345 | struct file *file, const char __user *userbuf, | 332 | int filetype, const char *buffer) |
346 | size_t nbytes, loff_t *ppos) | ||
347 | { | 333 | { |
348 | struct cgroup *cur_cgroup; | 334 | const char *b; |
349 | struct dev_cgroup *devcgroup, *cur_devcgroup; | 335 | char *endp; |
350 | int filetype = cft->private; | 336 | int count; |
351 | char *buffer, *b; | ||
352 | int retval = 0, count; | ||
353 | struct dev_whitelist_item wh; | 337 | struct dev_whitelist_item wh; |
354 | 338 | ||
355 | if (!capable(CAP_SYS_ADMIN)) | 339 | if (!capable(CAP_SYS_ADMIN)) |
356 | return -EPERM; | 340 | return -EPERM; |
357 | 341 | ||
358 | devcgroup = cgroup_to_devcgroup(cgroup); | ||
359 | cur_cgroup = task_cgroup(current, devices_subsys.subsys_id); | ||
360 | cur_devcgroup = cgroup_to_devcgroup(cur_cgroup); | ||
361 | |||
362 | buffer = kmalloc(nbytes+1, GFP_KERNEL); | ||
363 | if (!buffer) | ||
364 | return -ENOMEM; | ||
365 | |||
366 | if (copy_from_user(buffer, userbuf, nbytes)) { | ||
367 | retval = -EFAULT; | ||
368 | goto out1; | ||
369 | } | ||
370 | buffer[nbytes] = 0; /* nul-terminate */ | ||
371 | |||
372 | cgroup_lock(); | ||
373 | if (cgroup_is_removed(cgroup)) { | ||
374 | retval = -ENODEV; | ||
375 | goto out2; | ||
376 | } | ||
377 | |||
378 | memset(&wh, 0, sizeof(wh)); | 342 | memset(&wh, 0, sizeof(wh)); |
379 | b = buffer; | 343 | b = buffer; |
380 | 344 | ||
@@ -392,32 +356,23 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft, | |||
392 | wh.type = DEV_CHAR; | 356 | wh.type = DEV_CHAR; |
393 | break; | 357 | break; |
394 | default: | 358 | default: |
395 | retval = -EINVAL; | 359 | return -EINVAL; |
396 | goto out2; | ||
397 | } | 360 | } |
398 | b++; | 361 | b++; |
399 | if (!isspace(*b)) { | 362 | if (!isspace(*b)) |
400 | retval = -EINVAL; | 363 | return -EINVAL; |
401 | goto out2; | ||
402 | } | ||
403 | b++; | 364 | b++; |
404 | if (*b == '*') { | 365 | if (*b == '*') { |
405 | wh.major = ~0; | 366 | wh.major = ~0; |
406 | b++; | 367 | b++; |
407 | } else if (isdigit(*b)) { | 368 | } else if (isdigit(*b)) { |
408 | wh.major = 0; | 369 | wh.major = simple_strtoul(b, &endp, 10); |
409 | while (isdigit(*b)) { | 370 | b = endp; |
410 | wh.major = wh.major*10+(*b-'0'); | ||
411 | b++; | ||
412 | } | ||
413 | } else { | 371 | } else { |
414 | retval = -EINVAL; | 372 | return -EINVAL; |
415 | goto out2; | ||
416 | } | ||
417 | if (*b != ':') { | ||
418 | retval = -EINVAL; | ||
419 | goto out2; | ||
420 | } | 373 | } |
374 | if (*b != ':') | ||
375 | return -EINVAL; | ||
421 | b++; | 376 | b++; |
422 | 377 | ||
423 | /* read minor */ | 378 | /* read minor */ |
@@ -425,19 +380,13 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft, | |||
425 | wh.minor = ~0; | 380 | wh.minor = ~0; |
426 | b++; | 381 | b++; |
427 | } else if (isdigit(*b)) { | 382 | } else if (isdigit(*b)) { |
428 | wh.minor = 0; | 383 | wh.minor = simple_strtoul(b, &endp, 10); |
429 | while (isdigit(*b)) { | 384 | b = endp; |
430 | wh.minor = wh.minor*10+(*b-'0'); | ||
431 | b++; | ||
432 | } | ||
433 | } else { | 385 | } else { |
434 | retval = -EINVAL; | 386 | return -EINVAL; |
435 | goto out2; | ||
436 | } | ||
437 | if (!isspace(*b)) { | ||
438 | retval = -EINVAL; | ||
439 | goto out2; | ||
440 | } | 387 | } |
388 | if (!isspace(*b)) | ||
389 | return -EINVAL; | ||
441 | for (b++, count = 0; count < 3; count++, b++) { | 390 | for (b++, count = 0; count < 3; count++, b++) { |
442 | switch (*b) { | 391 | switch (*b) { |
443 | case 'r': | 392 | case 'r': |
@@ -454,47 +403,46 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft, | |||
454 | count = 3; | 403 | count = 3; |
455 | break; | 404 | break; |
456 | default: | 405 | default: |
457 | retval = -EINVAL; | 406 | return -EINVAL; |
458 | goto out2; | ||
459 | } | 407 | } |
460 | } | 408 | } |
461 | 409 | ||
462 | handle: | 410 | handle: |
463 | retval = 0; | ||
464 | switch (filetype) { | 411 | switch (filetype) { |
465 | case DEVCG_ALLOW: | 412 | case DEVCG_ALLOW: |
466 | if (!parent_has_perm(cgroup, &wh)) | 413 | if (!parent_has_perm(devcgroup, &wh)) |
467 | retval = -EPERM; | 414 | return -EPERM; |
468 | else | 415 | return dev_whitelist_add(devcgroup, &wh); |
469 | retval = dev_whitelist_add(devcgroup, &wh); | ||
470 | break; | ||
471 | case DEVCG_DENY: | 416 | case DEVCG_DENY: |
472 | dev_whitelist_rm(devcgroup, &wh); | 417 | dev_whitelist_rm(devcgroup, &wh); |
473 | break; | 418 | break; |
474 | default: | 419 | default: |
475 | retval = -EINVAL; | 420 | return -EINVAL; |
476 | goto out2; | ||
477 | } | 421 | } |
422 | return 0; | ||
423 | } | ||
478 | 424 | ||
479 | if (retval == 0) | 425 | static int devcgroup_access_write(struct cgroup *cgrp, struct cftype *cft, |
480 | retval = nbytes; | 426 | const char *buffer) |
481 | 427 | { | |
482 | out2: | 428 | int retval; |
429 | if (!cgroup_lock_live_group(cgrp)) | ||
430 | return -ENODEV; | ||
431 | retval = devcgroup_update_access(cgroup_to_devcgroup(cgrp), | ||
432 | cft->private, buffer); | ||
483 | cgroup_unlock(); | 433 | cgroup_unlock(); |
484 | out1: | ||
485 | kfree(buffer); | ||
486 | return retval; | 434 | return retval; |
487 | } | 435 | } |
488 | 436 | ||
489 | static struct cftype dev_cgroup_files[] = { | 437 | static struct cftype dev_cgroup_files[] = { |
490 | { | 438 | { |
491 | .name = "allow", | 439 | .name = "allow", |
492 | .write = devcgroup_access_write, | 440 | .write_string = devcgroup_access_write, |
493 | .private = DEVCG_ALLOW, | 441 | .private = DEVCG_ALLOW, |
494 | }, | 442 | }, |
495 | { | 443 | { |
496 | .name = "deny", | 444 | .name = "deny", |
497 | .write = devcgroup_access_write, | 445 | .write_string = devcgroup_access_write, |
498 | .private = DEVCG_DENY, | 446 | .private = DEVCG_DENY, |
499 | }, | 447 | }, |
500 | { | 448 | { |
@@ -530,13 +478,12 @@ int devcgroup_inode_permission(struct inode *inode, int mask) | |||
530 | return 0; | 478 | return 0; |
531 | if (!S_ISBLK(inode->i_mode) && !S_ISCHR(inode->i_mode)) | 479 | if (!S_ISBLK(inode->i_mode) && !S_ISCHR(inode->i_mode)) |
532 | return 0; | 480 | return 0; |
533 | dev_cgroup = css_to_devcgroup(task_subsys_state(current, | ||
534 | devices_subsys_id)); | ||
535 | if (!dev_cgroup) | ||
536 | return 0; | ||
537 | 481 | ||
538 | spin_lock(&dev_cgroup->lock); | 482 | rcu_read_lock(); |
539 | list_for_each_entry(wh, &dev_cgroup->whitelist, list) { | 483 | |
484 | dev_cgroup = task_devcgroup(current); | ||
485 | |||
486 | list_for_each_entry_rcu(wh, &dev_cgroup->whitelist, list) { | ||
540 | if (wh->type & DEV_ALL) | 487 | if (wh->type & DEV_ALL) |
541 | goto acc_check; | 488 | goto acc_check; |
542 | if ((wh->type & DEV_BLOCK) && !S_ISBLK(inode->i_mode)) | 489 | if ((wh->type & DEV_BLOCK) && !S_ISBLK(inode->i_mode)) |
@@ -552,10 +499,11 @@ acc_check: | |||
552 | continue; | 499 | continue; |
553 | if ((mask & MAY_READ) && !(wh->access & ACC_READ)) | 500 | if ((mask & MAY_READ) && !(wh->access & ACC_READ)) |
554 | continue; | 501 | continue; |
555 | spin_unlock(&dev_cgroup->lock); | 502 | rcu_read_unlock(); |
556 | return 0; | 503 | return 0; |
557 | } | 504 | } |
558 | spin_unlock(&dev_cgroup->lock); | 505 | |
506 | rcu_read_unlock(); | ||
559 | 507 | ||
560 | return -EPERM; | 508 | return -EPERM; |
561 | } | 509 | } |
@@ -565,12 +513,10 @@ int devcgroup_inode_mknod(int mode, dev_t dev) | |||
565 | struct dev_cgroup *dev_cgroup; | 513 | struct dev_cgroup *dev_cgroup; |
566 | struct dev_whitelist_item *wh; | 514 | struct dev_whitelist_item *wh; |
567 | 515 | ||
568 | dev_cgroup = css_to_devcgroup(task_subsys_state(current, | 516 | rcu_read_lock(); |
569 | devices_subsys_id)); | 517 | |
570 | if (!dev_cgroup) | 518 | dev_cgroup = task_devcgroup(current); |
571 | return 0; | ||
572 | 519 | ||
573 | spin_lock(&dev_cgroup->lock); | ||
574 | list_for_each_entry(wh, &dev_cgroup->whitelist, list) { | 520 | list_for_each_entry(wh, &dev_cgroup->whitelist, list) { |
575 | if (wh->type & DEV_ALL) | 521 | if (wh->type & DEV_ALL) |
576 | goto acc_check; | 522 | goto acc_check; |
@@ -585,9 +531,11 @@ int devcgroup_inode_mknod(int mode, dev_t dev) | |||
585 | acc_check: | 531 | acc_check: |
586 | if (!(wh->access & ACC_MKNOD)) | 532 | if (!(wh->access & ACC_MKNOD)) |
587 | continue; | 533 | continue; |
588 | spin_unlock(&dev_cgroup->lock); | 534 | rcu_read_unlock(); |
589 | return 0; | 535 | return 0; |
590 | } | 536 | } |
591 | spin_unlock(&dev_cgroup->lock); | 537 | |
538 | rcu_read_unlock(); | ||
539 | |||
592 | return -EPERM; | 540 | return -EPERM; |
593 | } | 541 | } |
diff --git a/security/inode.c b/security/inode.c index acc6cf0d7900..efea5a605466 100644 --- a/security/inode.c +++ b/security/inode.c | |||
@@ -20,8 +20,7 @@ | |||
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/namei.h> | 21 | #include <linux/namei.h> |
22 | #include <linux/security.h> | 22 | #include <linux/security.h> |
23 | 23 | #include <linux/magic.h> | |
24 | #define SECURITYFS_MAGIC 0x73636673 | ||
25 | 24 | ||
26 | static struct vfsmount *mount; | 25 | static struct vfsmount *mount; |
27 | static int mount_count; | 26 | static int mount_count; |
@@ -190,7 +189,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. | 189 | * @name: a pointer to a string containing the name of the file to create. |
191 | * @mode: the permission that the file should have | 190 | * @mode: the permission that the file should have |
192 | * @parent: a pointer to the parent dentry for this file. This should be a | 191 | * @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 | 192 | * directory dentry if set. If this parameter is %NULL, then the |
194 | * file will be created in the root of the securityfs filesystem. | 193 | * 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 | 194 | * @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 | 195 | * on. The inode.i_private pointer will point to this value on |
@@ -199,18 +198,18 @@ static int create_by_name(const char *name, mode_t mode, | |||
199 | * this file. | 198 | * this file. |
200 | * | 199 | * |
201 | * This is the basic "create a file" function for securityfs. It allows for a | 200 | * 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 | 201 | * 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 | 202 | * want to create a directory, the securityfs_create_dir() function is |
204 | * recommended to be used instead.) | 203 | * recommended to be used instead). |
205 | * | 204 | * |
206 | * This function will return a pointer to a dentry if it succeeds. This | 205 | * 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 | 206 | * 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, | 207 | * 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. | 208 | * you are responsible here). If an error occurs, %NULL is returned. |
210 | * | 209 | * |
211 | * If securityfs is not enabled in the kernel, the value -ENODEV will be | 210 | * 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 | 211 | * 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 | 212 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
214 | * code. | 213 | * code. |
215 | */ | 214 | */ |
216 | struct dentry *securityfs_create_file(const char *name, mode_t mode, | 215 | struct dentry *securityfs_create_file(const char *name, mode_t mode, |
@@ -252,19 +251,19 @@ EXPORT_SYMBOL_GPL(securityfs_create_file); | |||
252 | * @name: a pointer to a string containing the name of the directory to | 251 | * @name: a pointer to a string containing the name of the directory to |
253 | * create. | 252 | * create. |
254 | * @parent: a pointer to the parent dentry for this file. This should be a | 253 | * @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 | 254 | * directory dentry if set. If this parameter is %NULL, then the |
256 | * directory will be created in the root of the securityfs filesystem. | 255 | * directory will be created in the root of the securityfs filesystem. |
257 | * | 256 | * |
258 | * This function creates a directory in securityfs with the given name. | 257 | * This function creates a directory in securityfs with the given @name. |
259 | * | 258 | * |
260 | * This function will return a pointer to a dentry if it succeeds. This | 259 | * 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 | 260 | * 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, | 261 | * 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. | 262 | * you are responsible here). If an error occurs, %NULL will be returned. |
264 | * | 263 | * |
265 | * If securityfs is not enabled in the kernel, the value -ENODEV will be | 264 | * 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 | 265 | * 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 | 266 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling |
268 | * code. | 267 | * code. |
269 | */ | 268 | */ |
270 | struct dentry *securityfs_create_dir(const char *name, struct dentry *parent) | 269 | struct dentry *securityfs_create_dir(const char *name, struct dentry *parent) |
@@ -278,16 +277,15 @@ EXPORT_SYMBOL_GPL(securityfs_create_dir); | |||
278 | /** | 277 | /** |
279 | * securityfs_remove - removes a file or directory from the securityfs filesystem | 278 | * securityfs_remove - removes a file or directory from the securityfs filesystem |
280 | * | 279 | * |
281 | * @dentry: a pointer to a the dentry of the file or directory to be | 280 | * @dentry: a pointer to a the dentry of the file or directory to be removed. |
282 | * removed. | ||
283 | * | 281 | * |
284 | * This function removes a file or directory in securityfs that was previously | 282 | * This function removes a file or directory in securityfs that was previously |
285 | * created with a call to another securityfs function (like | 283 | * created with a call to another securityfs function (like |
286 | * securityfs_create_file() or variants thereof.) | 284 | * securityfs_create_file() or variants thereof.) |
287 | * | 285 | * |
288 | * This function is required to be called in order for the file to be | 286 | * 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 | 287 | * removed. No automatic cleanup of files will happen when a module is |
290 | * removed, you are responsible here. | 288 | * removed; you are responsible here. |
291 | */ | 289 | */ |
292 | void securityfs_remove(struct dentry *dentry) | 290 | void securityfs_remove(struct dentry *dentry) |
293 | { | 291 | { |
diff --git a/security/root_plug.c b/security/root_plug.c index be0ebec2580b..c3f68b5b372d 100644 --- a/security/root_plug.c +++ b/security/root_plug.c | |||
@@ -72,7 +72,8 @@ static int rootplug_bprm_check_security (struct linux_binprm *bprm) | |||
72 | 72 | ||
73 | static struct security_operations rootplug_security_ops = { | 73 | static struct security_operations rootplug_security_ops = { |
74 | /* Use the capability functions for some of the hooks */ | 74 | /* Use the capability functions for some of the hooks */ |
75 | .ptrace = cap_ptrace, | 75 | .ptrace_may_access = cap_ptrace_may_access, |
76 | .ptrace_traceme = cap_ptrace_traceme, | ||
76 | .capget = cap_capget, | 77 | .capget = cap_capget, |
77 | .capset_check = cap_capset_check, | 78 | .capset_check = cap_capset_check, |
78 | .capset_set = cap_capset_set, | 79 | .capset_set = cap_capset_set, |
diff --git a/security/security.c b/security/security.c index 59f23b5918b3..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 | { |
@@ -127,10 +127,14 @@ int register_security(struct security_operations *ops) | |||
127 | 127 | ||
128 | /* Security operations */ | 128 | /* Security operations */ |
129 | 129 | ||
130 | int security_ptrace(struct task_struct *parent, struct task_struct *child, | 130 | int security_ptrace_may_access(struct task_struct *child, unsigned int mode) |
131 | unsigned int mode) | ||
132 | { | 131 | { |
133 | return security_ops->ptrace(parent, child, mode); | 132 | return security_ops->ptrace_may_access(child, mode); |
133 | } | ||
134 | |||
135 | int security_ptrace_traceme(struct task_struct *parent) | ||
136 | { | ||
137 | return security_ops->ptrace_traceme(parent); | ||
134 | } | 138 | } |
135 | 139 | ||
136 | int security_capget(struct task_struct *target, | 140 | int security_capget(struct task_struct *target, |
@@ -429,11 +433,11 @@ int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
429 | return security_ops->inode_follow_link(dentry, nd); | 433 | return security_ops->inode_follow_link(dentry, nd); |
430 | } | 434 | } |
431 | 435 | ||
432 | int security_inode_permission(struct inode *inode, int mask, struct nameidata *nd) | 436 | int security_inode_permission(struct inode *inode, int mask) |
433 | { | 437 | { |
434 | if (unlikely(IS_PRIVATE(inode))) | 438 | if (unlikely(IS_PRIVATE(inode))) |
435 | return 0; | 439 | return 0; |
436 | return security_ops->inode_permission(inode, mask, nd); | 440 | return security_ops->inode_permission(inode, mask); |
437 | } | 441 | } |
438 | 442 | ||
439 | int security_inode_setattr(struct dentry *dentry, struct iattr *attr) | 443 | int security_inode_setattr(struct dentry *dentry, struct iattr *attr) |
@@ -442,6 +446,7 @@ int security_inode_setattr(struct dentry *dentry, struct iattr *attr) | |||
442 | return 0; | 446 | return 0; |
443 | return security_ops->inode_setattr(dentry, attr); | 447 | return security_ops->inode_setattr(dentry, attr); |
444 | } | 448 | } |
449 | EXPORT_SYMBOL_GPL(security_inode_setattr); | ||
445 | 450 | ||
446 | int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | 451 | int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) |
447 | { | 452 | { |
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 63f131fc42e4..3e3fde7c1d2b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
28 | #include <linux/ptrace.h> | 28 | #include <linux/tracehook.h> |
29 | #include <linux/errno.h> | 29 | #include <linux/errno.h> |
30 | #include <linux/sched.h> | 30 | #include <linux/sched.h> |
31 | #include <linux/security.h> | 31 | #include <linux/security.h> |
@@ -75,6 +75,7 @@ | |||
75 | #include <linux/string.h> | 75 | #include <linux/string.h> |
76 | #include <linux/selinux.h> | 76 | #include <linux/selinux.h> |
77 | #include <linux/mutex.h> | 77 | #include <linux/mutex.h> |
78 | #include <linux/posix-timers.h> | ||
78 | 79 | ||
79 | #include "avc.h" | 80 | #include "avc.h" |
80 | #include "objsec.h" | 81 | #include "objsec.h" |
@@ -291,6 +292,7 @@ static void sk_free_security(struct sock *sk) | |||
291 | struct sk_security_struct *ssec = sk->sk_security; | 292 | struct sk_security_struct *ssec = sk->sk_security; |
292 | 293 | ||
293 | sk->sk_security = NULL; | 294 | sk->sk_security = NULL; |
295 | selinux_netlbl_sk_security_free(ssec); | ||
294 | kfree(ssec); | 296 | kfree(ssec); |
295 | } | 297 | } |
296 | 298 | ||
@@ -324,7 +326,7 @@ enum { | |||
324 | Opt_rootcontext = 4, | 326 | Opt_rootcontext = 4, |
325 | }; | 327 | }; |
326 | 328 | ||
327 | static match_table_t tokens = { | 329 | static const match_table_t tokens = { |
328 | {Opt_context, CONTEXT_STR "%s"}, | 330 | {Opt_context, CONTEXT_STR "%s"}, |
329 | {Opt_fscontext, FSCONTEXT_STR "%s"}, | 331 | {Opt_fscontext, FSCONTEXT_STR "%s"}, |
330 | {Opt_defcontext, DEFCONTEXT_STR "%s"}, | 332 | {Opt_defcontext, DEFCONTEXT_STR "%s"}, |
@@ -957,7 +959,8 @@ out_err: | |||
957 | return rc; | 959 | return rc; |
958 | } | 960 | } |
959 | 961 | ||
960 | void selinux_write_opts(struct seq_file *m, struct security_mnt_opts *opts) | 962 | static void selinux_write_opts(struct seq_file *m, |
963 | struct security_mnt_opts *opts) | ||
961 | { | 964 | { |
962 | int i; | 965 | int i; |
963 | char *prefix; | 966 | char *prefix; |
@@ -998,8 +1001,12 @@ static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb) | |||
998 | int rc; | 1001 | int rc; |
999 | 1002 | ||
1000 | rc = selinux_get_mnt_opts(sb, &opts); | 1003 | rc = selinux_get_mnt_opts(sb, &opts); |
1001 | if (rc) | 1004 | if (rc) { |
1005 | /* before policy load we may get EINVAL, don't show anything */ | ||
1006 | if (rc == -EINVAL) | ||
1007 | rc = 0; | ||
1002 | return rc; | 1008 | return rc; |
1009 | } | ||
1003 | 1010 | ||
1004 | selinux_write_opts(m, &opts); | 1011 | selinux_write_opts(m, &opts); |
1005 | 1012 | ||
@@ -1286,7 +1293,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1286 | /* Default to the fs superblock SID. */ | 1293 | /* Default to the fs superblock SID. */ |
1287 | isec->sid = sbsec->sid; | 1294 | isec->sid = sbsec->sid; |
1288 | 1295 | ||
1289 | if (sbsec->proc) { | 1296 | if (sbsec->proc && !S_ISLNK(inode->i_mode)) { |
1290 | struct proc_inode *proci = PROC_I(inode); | 1297 | struct proc_inode *proci = PROC_I(inode); |
1291 | if (proci->pde) { | 1298 | if (proci->pde) { |
1292 | isec->sclass = inode_mode_to_security_class(inode->i_mode); | 1299 | isec->sclass = inode_mode_to_security_class(inode->i_mode); |
@@ -1734,24 +1741,34 @@ static inline u32 file_to_av(struct file *file) | |||
1734 | 1741 | ||
1735 | /* Hook functions begin here. */ | 1742 | /* Hook functions begin here. */ |
1736 | 1743 | ||
1737 | static int selinux_ptrace(struct task_struct *parent, | 1744 | static int selinux_ptrace_may_access(struct task_struct *child, |
1738 | struct task_struct *child, | 1745 | unsigned int mode) |
1739 | unsigned int mode) | ||
1740 | { | 1746 | { |
1741 | int rc; | 1747 | int rc; |
1742 | 1748 | ||
1743 | rc = secondary_ops->ptrace(parent, child, mode); | 1749 | rc = secondary_ops->ptrace_may_access(child, mode); |
1744 | if (rc) | 1750 | if (rc) |
1745 | return rc; | 1751 | return rc; |
1746 | 1752 | ||
1747 | if (mode == PTRACE_MODE_READ) { | 1753 | if (mode == PTRACE_MODE_READ) { |
1748 | struct task_security_struct *tsec = parent->security; | 1754 | struct task_security_struct *tsec = current->security; |
1749 | struct task_security_struct *csec = child->security; | 1755 | struct task_security_struct *csec = child->security; |
1750 | return avc_has_perm(tsec->sid, csec->sid, | 1756 | return avc_has_perm(tsec->sid, csec->sid, |
1751 | SECCLASS_FILE, FILE__READ, NULL); | 1757 | SECCLASS_FILE, FILE__READ, NULL); |
1752 | } | 1758 | } |
1753 | 1759 | ||
1754 | return task_has_perm(parent, child, PROCESS__PTRACE); | 1760 | return task_has_perm(current, child, PROCESS__PTRACE); |
1761 | } | ||
1762 | |||
1763 | static int selinux_ptrace_traceme(struct task_struct *parent) | ||
1764 | { | ||
1765 | int rc; | ||
1766 | |||
1767 | rc = secondary_ops->ptrace_traceme(parent); | ||
1768 | if (rc) | ||
1769 | return rc; | ||
1770 | |||
1771 | return task_has_perm(parent, current, PROCESS__PTRACE); | ||
1755 | } | 1772 | } |
1756 | 1773 | ||
1757 | static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, | 1774 | static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, |
@@ -1971,22 +1988,6 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) | |||
1971 | return __vm_enough_memory(mm, pages, cap_sys_admin); | 1988 | return __vm_enough_memory(mm, pages, cap_sys_admin); |
1972 | } | 1989 | } |
1973 | 1990 | ||
1974 | /** | ||
1975 | * task_tracer_task - return the task that is tracing the given task | ||
1976 | * @task: task to consider | ||
1977 | * | ||
1978 | * Returns NULL if noone is tracing @task, or the &struct task_struct | ||
1979 | * pointer to its tracer. | ||
1980 | * | ||
1981 | * Must be called under rcu_read_lock(). | ||
1982 | */ | ||
1983 | static struct task_struct *task_tracer_task(struct task_struct *task) | ||
1984 | { | ||
1985 | if (task->ptrace & PT_PTRACED) | ||
1986 | return rcu_dereference(task->parent); | ||
1987 | return NULL; | ||
1988 | } | ||
1989 | |||
1990 | /* binprm security operations */ | 1991 | /* binprm security operations */ |
1991 | 1992 | ||
1992 | static int selinux_bprm_alloc_security(struct linux_binprm *bprm) | 1993 | static int selinux_bprm_alloc_security(struct linux_binprm *bprm) |
@@ -2122,7 +2123,6 @@ static inline void flush_unauthorized_files(struct files_struct *files) | |||
2122 | long j = -1; | 2123 | long j = -1; |
2123 | int drop_tty = 0; | 2124 | int drop_tty = 0; |
2124 | 2125 | ||
2125 | mutex_lock(&tty_mutex); | ||
2126 | tty = get_current_tty(); | 2126 | tty = get_current_tty(); |
2127 | if (tty) { | 2127 | if (tty) { |
2128 | file_list_lock(); | 2128 | file_list_lock(); |
@@ -2140,8 +2140,8 @@ static inline void flush_unauthorized_files(struct files_struct *files) | |||
2140 | } | 2140 | } |
2141 | } | 2141 | } |
2142 | file_list_unlock(); | 2142 | file_list_unlock(); |
2143 | tty_kref_put(tty); | ||
2143 | } | 2144 | } |
2144 | mutex_unlock(&tty_mutex); | ||
2145 | /* Reset controlling tty. */ | 2145 | /* Reset controlling tty. */ |
2146 | if (drop_tty) | 2146 | if (drop_tty) |
2147 | no_tty(); | 2147 | no_tty(); |
@@ -2238,7 +2238,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) | |||
2238 | u32 ptsid = 0; | 2238 | u32 ptsid = 0; |
2239 | 2239 | ||
2240 | rcu_read_lock(); | 2240 | rcu_read_lock(); |
2241 | tracer = task_tracer_task(current); | 2241 | tracer = tracehook_tracer_task(current); |
2242 | if (likely(tracer != NULL)) { | 2242 | if (likely(tracer != NULL)) { |
2243 | sec = tracer->security; | 2243 | sec = tracer->security; |
2244 | ptsid = sec->sid; | 2244 | ptsid = sec->sid; |
@@ -2323,13 +2323,7 @@ static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm) | |||
2323 | initrlim = init_task.signal->rlim+i; | 2323 | initrlim = init_task.signal->rlim+i; |
2324 | rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur); | 2324 | rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur); |
2325 | } | 2325 | } |
2326 | if (current->signal->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) { | 2326 | update_rlimit_cpu(rlim->rlim_cur); |
2327 | /* | ||
2328 | * This will cause RLIMIT_CPU calculations | ||
2329 | * to be refigured. | ||
2330 | */ | ||
2331 | current->it_prof_expires = jiffies_to_cputime(1); | ||
2332 | } | ||
2333 | } | 2327 | } |
2334 | 2328 | ||
2335 | /* Wake up the parent if it is waiting so that it can | 2329 | /* Wake up the parent if it is waiting so that it can |
@@ -2640,12 +2634,11 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na | |||
2640 | return dentry_has_perm(current, NULL, dentry, FILE__READ); | 2634 | return dentry_has_perm(current, NULL, dentry, FILE__READ); |
2641 | } | 2635 | } |
2642 | 2636 | ||
2643 | static int selinux_inode_permission(struct inode *inode, int mask, | 2637 | static int selinux_inode_permission(struct inode *inode, int mask) |
2644 | struct nameidata *nd) | ||
2645 | { | 2638 | { |
2646 | int rc; | 2639 | int rc; |
2647 | 2640 | ||
2648 | rc = secondary_ops->inode_permission(inode, mask, nd); | 2641 | rc = secondary_ops->inode_permission(inode, mask); |
2649 | if (rc) | 2642 | if (rc) |
2650 | return rc; | 2643 | return rc; |
2651 | 2644 | ||
@@ -3551,38 +3544,44 @@ out: | |||
3551 | #endif /* IPV6 */ | 3544 | #endif /* IPV6 */ |
3552 | 3545 | ||
3553 | static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, | 3546 | static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, |
3554 | char **addrp, int src, u8 *proto) | 3547 | char **_addrp, int src, u8 *proto) |
3555 | { | 3548 | { |
3556 | int ret = 0; | 3549 | char *addrp; |
3550 | int ret; | ||
3557 | 3551 | ||
3558 | switch (ad->u.net.family) { | 3552 | switch (ad->u.net.family) { |
3559 | case PF_INET: | 3553 | case PF_INET: |
3560 | ret = selinux_parse_skb_ipv4(skb, ad, proto); | 3554 | ret = selinux_parse_skb_ipv4(skb, ad, proto); |
3561 | if (ret || !addrp) | 3555 | if (ret) |
3562 | break; | 3556 | goto parse_error; |
3563 | *addrp = (char *)(src ? &ad->u.net.v4info.saddr : | 3557 | addrp = (char *)(src ? &ad->u.net.v4info.saddr : |
3564 | &ad->u.net.v4info.daddr); | 3558 | &ad->u.net.v4info.daddr); |
3565 | break; | 3559 | goto okay; |
3566 | 3560 | ||
3567 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 3561 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
3568 | case PF_INET6: | 3562 | case PF_INET6: |
3569 | ret = selinux_parse_skb_ipv6(skb, ad, proto); | 3563 | ret = selinux_parse_skb_ipv6(skb, ad, proto); |
3570 | if (ret || !addrp) | 3564 | if (ret) |
3571 | break; | 3565 | goto parse_error; |
3572 | *addrp = (char *)(src ? &ad->u.net.v6info.saddr : | 3566 | addrp = (char *)(src ? &ad->u.net.v6info.saddr : |
3573 | &ad->u.net.v6info.daddr); | 3567 | &ad->u.net.v6info.daddr); |
3574 | break; | 3568 | goto okay; |
3575 | #endif /* IPV6 */ | 3569 | #endif /* IPV6 */ |
3576 | default: | 3570 | default: |
3577 | break; | 3571 | addrp = NULL; |
3572 | goto okay; | ||
3578 | } | 3573 | } |
3579 | 3574 | ||
3580 | if (unlikely(ret)) | 3575 | parse_error: |
3581 | printk(KERN_WARNING | 3576 | printk(KERN_WARNING |
3582 | "SELinux: failure in selinux_parse_skb()," | 3577 | "SELinux: failure in selinux_parse_skb()," |
3583 | " unable to parse packet\n"); | 3578 | " unable to parse packet\n"); |
3584 | |||
3585 | return ret; | 3579 | return ret; |
3580 | |||
3581 | okay: | ||
3582 | if (_addrp) | ||
3583 | *_addrp = addrp; | ||
3584 | return 0; | ||
3586 | } | 3585 | } |
3587 | 3586 | ||
3588 | /** | 3587 | /** |
@@ -3797,6 +3796,7 @@ out: | |||
3797 | 3796 | ||
3798 | static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) | 3797 | static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) |
3799 | { | 3798 | { |
3799 | struct sock *sk = sock->sk; | ||
3800 | struct inode_security_struct *isec; | 3800 | struct inode_security_struct *isec; |
3801 | int err; | 3801 | int err; |
3802 | 3802 | ||
@@ -3810,7 +3810,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
3810 | isec = SOCK_INODE(sock)->i_security; | 3810 | isec = SOCK_INODE(sock)->i_security; |
3811 | if (isec->sclass == SECCLASS_TCP_SOCKET || | 3811 | if (isec->sclass == SECCLASS_TCP_SOCKET || |
3812 | isec->sclass == SECCLASS_DCCP_SOCKET) { | 3812 | isec->sclass == SECCLASS_DCCP_SOCKET) { |
3813 | struct sock *sk = sock->sk; | ||
3814 | struct avc_audit_data ad; | 3813 | struct avc_audit_data ad; |
3815 | struct sockaddr_in *addr4 = NULL; | 3814 | struct sockaddr_in *addr4 = NULL; |
3816 | struct sockaddr_in6 *addr6 = NULL; | 3815 | struct sockaddr_in6 *addr6 = NULL; |
@@ -3844,6 +3843,8 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
3844 | goto out; | 3843 | goto out; |
3845 | } | 3844 | } |
3846 | 3845 | ||
3846 | err = selinux_netlbl_socket_connect(sk, address); | ||
3847 | |||
3847 | out: | 3848 | out: |
3848 | return err; | 3849 | return err; |
3849 | } | 3850 | } |
@@ -4073,20 +4074,28 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, | |||
4073 | } | 4074 | } |
4074 | 4075 | ||
4075 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | 4076 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
4076 | struct avc_audit_data *ad, | 4077 | u16 family) |
4077 | u16 family, char *addrp) | ||
4078 | { | 4078 | { |
4079 | int err; | 4079 | int err; |
4080 | struct sk_security_struct *sksec = sk->sk_security; | 4080 | struct sk_security_struct *sksec = sk->sk_security; |
4081 | u32 peer_sid; | 4081 | u32 peer_sid; |
4082 | u32 sk_sid = sksec->sid; | 4082 | u32 sk_sid = sksec->sid; |
4083 | struct avc_audit_data ad; | ||
4084 | char *addrp; | ||
4085 | |||
4086 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
4087 | ad.u.net.netif = skb->iif; | ||
4088 | ad.u.net.family = family; | ||
4089 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); | ||
4090 | if (err) | ||
4091 | return err; | ||
4083 | 4092 | ||
4084 | if (selinux_compat_net) | 4093 | if (selinux_compat_net) |
4085 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, ad, | 4094 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad, |
4086 | family, addrp); | 4095 | family, addrp); |
4087 | else | 4096 | else |
4088 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | 4097 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, |
4089 | PACKET__RECV, ad); | 4098 | PACKET__RECV, &ad); |
4090 | if (err) | 4099 | if (err) |
4091 | return err; | 4100 | return err; |
4092 | 4101 | ||
@@ -4095,12 +4104,14 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
4095 | if (err) | 4104 | if (err) |
4096 | return err; | 4105 | return err; |
4097 | err = avc_has_perm(sk_sid, peer_sid, | 4106 | err = avc_has_perm(sk_sid, peer_sid, |
4098 | SECCLASS_PEER, PEER__RECV, ad); | 4107 | SECCLASS_PEER, PEER__RECV, &ad); |
4108 | if (err) | ||
4109 | selinux_netlbl_err(skb, err, 0); | ||
4099 | } else { | 4110 | } else { |
4100 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, ad); | 4111 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad); |
4101 | if (err) | 4112 | if (err) |
4102 | return err; | 4113 | return err; |
4103 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, ad); | 4114 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); |
4104 | } | 4115 | } |
4105 | 4116 | ||
4106 | return err; | 4117 | return err; |
@@ -4114,6 +4125,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4114 | u32 sk_sid = sksec->sid; | 4125 | u32 sk_sid = sksec->sid; |
4115 | struct avc_audit_data ad; | 4126 | struct avc_audit_data ad; |
4116 | char *addrp; | 4127 | char *addrp; |
4128 | u8 secmark_active; | ||
4129 | u8 peerlbl_active; | ||
4117 | 4130 | ||
4118 | if (family != PF_INET && family != PF_INET6) | 4131 | if (family != PF_INET && family != PF_INET6) |
4119 | return 0; | 4132 | return 0; |
@@ -4122,6 +4135,18 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4122 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | 4135 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) |
4123 | family = PF_INET; | 4136 | family = PF_INET; |
4124 | 4137 | ||
4138 | /* If any sort of compatibility mode is enabled then handoff processing | ||
4139 | * to the selinux_sock_rcv_skb_compat() function to deal with the | ||
4140 | * special handling. We do this in an attempt to keep this function | ||
4141 | * as fast and as clean as possible. */ | ||
4142 | if (selinux_compat_net || !selinux_policycap_netpeer) | ||
4143 | return selinux_sock_rcv_skb_compat(sk, skb, family); | ||
4144 | |||
4145 | secmark_active = selinux_secmark_enabled(); | ||
4146 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); | ||
4147 | if (!secmark_active && !peerlbl_active) | ||
4148 | return 0; | ||
4149 | |||
4125 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4150 | AVC_AUDIT_DATA_INIT(&ad, NET); |
4126 | ad.u.net.netif = skb->iif; | 4151 | ad.u.net.netif = skb->iif; |
4127 | ad.u.net.family = family; | 4152 | ad.u.net.family = family; |
@@ -4129,15 +4154,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4129 | if (err) | 4154 | if (err) |
4130 | return err; | 4155 | return err; |
4131 | 4156 | ||
4132 | /* If any sort of compatibility mode is enabled then handoff processing | 4157 | if (peerlbl_active) { |
4133 | * to the selinux_sock_rcv_skb_compat() function to deal with the | ||
4134 | * special handling. We do this in an attempt to keep this function | ||
4135 | * as fast and as clean as possible. */ | ||
4136 | if (selinux_compat_net || !selinux_policycap_netpeer) | ||
4137 | return selinux_sock_rcv_skb_compat(sk, skb, &ad, | ||
4138 | family, addrp); | ||
4139 | |||
4140 | if (netlbl_enabled() || selinux_xfrm_enabled()) { | ||
4141 | u32 peer_sid; | 4158 | u32 peer_sid; |
4142 | 4159 | ||
4143 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); | 4160 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); |
@@ -4145,13 +4162,17 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4145 | return err; | 4162 | return err; |
4146 | err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family, | 4163 | err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family, |
4147 | peer_sid, &ad); | 4164 | peer_sid, &ad); |
4148 | if (err) | 4165 | if (err) { |
4166 | selinux_netlbl_err(skb, err, 0); | ||
4149 | return err; | 4167 | return err; |
4168 | } | ||
4150 | err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, | 4169 | err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, |
4151 | PEER__RECV, &ad); | 4170 | PEER__RECV, &ad); |
4171 | if (err) | ||
4172 | selinux_netlbl_err(skb, err, 0); | ||
4152 | } | 4173 | } |
4153 | 4174 | ||
4154 | if (selinux_secmark_enabled()) { | 4175 | if (secmark_active) { |
4155 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | 4176 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, |
4156 | PACKET__RECV, &ad); | 4177 | PACKET__RECV, &ad); |
4157 | if (err) | 4178 | if (err) |
@@ -4210,10 +4231,12 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff * | |||
4210 | u32 peer_secid = SECSID_NULL; | 4231 | u32 peer_secid = SECSID_NULL; |
4211 | u16 family; | 4232 | u16 family; |
4212 | 4233 | ||
4213 | if (sock) | 4234 | if (skb && skb->protocol == htons(ETH_P_IP)) |
4235 | family = PF_INET; | ||
4236 | else if (skb && skb->protocol == htons(ETH_P_IPV6)) | ||
4237 | family = PF_INET6; | ||
4238 | else if (sock) | ||
4214 | family = sock->sk->sk_family; | 4239 | family = sock->sk->sk_family; |
4215 | else if (skb && skb->sk) | ||
4216 | family = skb->sk->sk_family; | ||
4217 | else | 4240 | else |
4218 | goto out; | 4241 | goto out; |
4219 | 4242 | ||
@@ -4271,8 +4294,6 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent) | |||
4271 | sk->sk_family == PF_UNIX) | 4294 | sk->sk_family == PF_UNIX) |
4272 | isec->sid = sksec->sid; | 4295 | isec->sid = sksec->sid; |
4273 | sksec->sclass = isec->sclass; | 4296 | sksec->sclass = isec->sclass; |
4274 | |||
4275 | selinux_netlbl_sock_graft(sk, parent); | ||
4276 | } | 4297 | } |
4277 | 4298 | ||
4278 | static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | 4299 | static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, |
@@ -4280,10 +4301,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
4280 | { | 4301 | { |
4281 | struct sk_security_struct *sksec = sk->sk_security; | 4302 | struct sk_security_struct *sksec = sk->sk_security; |
4282 | int err; | 4303 | int err; |
4304 | u16 family = sk->sk_family; | ||
4283 | u32 newsid; | 4305 | u32 newsid; |
4284 | u32 peersid; | 4306 | u32 peersid; |
4285 | 4307 | ||
4286 | err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid); | 4308 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ |
4309 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | ||
4310 | family = PF_INET; | ||
4311 | |||
4312 | err = selinux_skb_peerlbl_sid(skb, family, &peersid); | ||
4287 | if (err) | 4313 | if (err) |
4288 | return err; | 4314 | return err; |
4289 | if (peersid == SECSID_NULL) { | 4315 | if (peersid == SECSID_NULL) { |
@@ -4318,12 +4344,18 @@ static void selinux_inet_csk_clone(struct sock *newsk, | |||
4318 | selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); | 4344 | selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); |
4319 | } | 4345 | } |
4320 | 4346 | ||
4321 | static void selinux_inet_conn_established(struct sock *sk, | 4347 | static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) |
4322 | struct sk_buff *skb) | ||
4323 | { | 4348 | { |
4349 | u16 family = sk->sk_family; | ||
4324 | struct sk_security_struct *sksec = sk->sk_security; | 4350 | struct sk_security_struct *sksec = sk->sk_security; |
4325 | 4351 | ||
4326 | selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid); | 4352 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ |
4353 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | ||
4354 | family = PF_INET; | ||
4355 | |||
4356 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); | ||
4357 | |||
4358 | selinux_netlbl_inet_conn_established(sk, family); | ||
4327 | } | 4359 | } |
4328 | 4360 | ||
4329 | static void selinux_req_classify_flow(const struct request_sock *req, | 4361 | static void selinux_req_classify_flow(const struct request_sock *req, |
@@ -4373,39 +4405,54 @@ out: | |||
4373 | static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | 4405 | static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, |
4374 | u16 family) | 4406 | u16 family) |
4375 | { | 4407 | { |
4408 | int err; | ||
4376 | char *addrp; | 4409 | char *addrp; |
4377 | u32 peer_sid; | 4410 | u32 peer_sid; |
4378 | struct avc_audit_data ad; | 4411 | struct avc_audit_data ad; |
4379 | u8 secmark_active; | 4412 | u8 secmark_active; |
4413 | u8 netlbl_active; | ||
4380 | u8 peerlbl_active; | 4414 | u8 peerlbl_active; |
4381 | 4415 | ||
4382 | if (!selinux_policycap_netpeer) | 4416 | if (!selinux_policycap_netpeer) |
4383 | return NF_ACCEPT; | 4417 | return NF_ACCEPT; |
4384 | 4418 | ||
4385 | secmark_active = selinux_secmark_enabled(); | 4419 | secmark_active = selinux_secmark_enabled(); |
4386 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); | 4420 | netlbl_active = netlbl_enabled(); |
4421 | peerlbl_active = netlbl_active || selinux_xfrm_enabled(); | ||
4387 | if (!secmark_active && !peerlbl_active) | 4422 | if (!secmark_active && !peerlbl_active) |
4388 | return NF_ACCEPT; | 4423 | return NF_ACCEPT; |
4389 | 4424 | ||
4425 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) | ||
4426 | return NF_DROP; | ||
4427 | |||
4390 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4428 | AVC_AUDIT_DATA_INIT(&ad, NET); |
4391 | ad.u.net.netif = ifindex; | 4429 | ad.u.net.netif = ifindex; |
4392 | ad.u.net.family = family; | 4430 | ad.u.net.family = family; |
4393 | if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) | 4431 | if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) |
4394 | return NF_DROP; | 4432 | return NF_DROP; |
4395 | 4433 | ||
4396 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) | 4434 | if (peerlbl_active) { |
4397 | return NF_DROP; | 4435 | err = selinux_inet_sys_rcv_skb(ifindex, addrp, family, |
4398 | 4436 | peer_sid, &ad); | |
4399 | if (peerlbl_active) | 4437 | if (err) { |
4400 | if (selinux_inet_sys_rcv_skb(ifindex, addrp, family, | 4438 | selinux_netlbl_err(skb, err, 1); |
4401 | peer_sid, &ad) != 0) | ||
4402 | return NF_DROP; | 4439 | return NF_DROP; |
4440 | } | ||
4441 | } | ||
4403 | 4442 | ||
4404 | if (secmark_active) | 4443 | if (secmark_active) |
4405 | if (avc_has_perm(peer_sid, skb->secmark, | 4444 | if (avc_has_perm(peer_sid, skb->secmark, |
4406 | SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) | 4445 | SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) |
4407 | return NF_DROP; | 4446 | return NF_DROP; |
4408 | 4447 | ||
4448 | if (netlbl_active) | ||
4449 | /* we do this in the FORWARD path and not the POST_ROUTING | ||
4450 | * path because we want to make sure we apply the necessary | ||
4451 | * labeling before IPsec is applied so we can leverage AH | ||
4452 | * protection */ | ||
4453 | if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0) | ||
4454 | return NF_DROP; | ||
4455 | |||
4409 | return NF_ACCEPT; | 4456 | return NF_ACCEPT; |
4410 | } | 4457 | } |
4411 | 4458 | ||
@@ -4429,6 +4476,37 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum, | |||
4429 | } | 4476 | } |
4430 | #endif /* IPV6 */ | 4477 | #endif /* IPV6 */ |
4431 | 4478 | ||
4479 | static unsigned int selinux_ip_output(struct sk_buff *skb, | ||
4480 | u16 family) | ||
4481 | { | ||
4482 | u32 sid; | ||
4483 | |||
4484 | if (!netlbl_enabled()) | ||
4485 | return NF_ACCEPT; | ||
4486 | |||
4487 | /* we do this in the LOCAL_OUT path and not the POST_ROUTING path | ||
4488 | * because we want to make sure we apply the necessary labeling | ||
4489 | * before IPsec is applied so we can leverage AH protection */ | ||
4490 | if (skb->sk) { | ||
4491 | struct sk_security_struct *sksec = skb->sk->sk_security; | ||
4492 | sid = sksec->sid; | ||
4493 | } else | ||
4494 | sid = SECINITSID_KERNEL; | ||
4495 | if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0) | ||
4496 | return NF_DROP; | ||
4497 | |||
4498 | return NF_ACCEPT; | ||
4499 | } | ||
4500 | |||
4501 | static unsigned int selinux_ipv4_output(unsigned int hooknum, | ||
4502 | struct sk_buff *skb, | ||
4503 | const struct net_device *in, | ||
4504 | const struct net_device *out, | ||
4505 | int (*okfn)(struct sk_buff *)) | ||
4506 | { | ||
4507 | return selinux_ip_output(skb, PF_INET); | ||
4508 | } | ||
4509 | |||
4432 | static int selinux_ip_postroute_iptables_compat(struct sock *sk, | 4510 | static int selinux_ip_postroute_iptables_compat(struct sock *sk, |
4433 | int ifindex, | 4511 | int ifindex, |
4434 | struct avc_audit_data *ad, | 4512 | struct avc_audit_data *ad, |
@@ -4496,30 +4574,36 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk, | |||
4496 | 4574 | ||
4497 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | 4575 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, |
4498 | int ifindex, | 4576 | int ifindex, |
4499 | struct avc_audit_data *ad, | 4577 | u16 family) |
4500 | u16 family, | ||
4501 | char *addrp, | ||
4502 | u8 proto) | ||
4503 | { | 4578 | { |
4504 | struct sock *sk = skb->sk; | 4579 | struct sock *sk = skb->sk; |
4505 | struct sk_security_struct *sksec; | 4580 | struct sk_security_struct *sksec; |
4581 | struct avc_audit_data ad; | ||
4582 | char *addrp; | ||
4583 | u8 proto; | ||
4506 | 4584 | ||
4507 | if (sk == NULL) | 4585 | if (sk == NULL) |
4508 | return NF_ACCEPT; | 4586 | return NF_ACCEPT; |
4509 | sksec = sk->sk_security; | 4587 | sksec = sk->sk_security; |
4510 | 4588 | ||
4589 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
4590 | ad.u.net.netif = ifindex; | ||
4591 | ad.u.net.family = family; | ||
4592 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) | ||
4593 | return NF_DROP; | ||
4594 | |||
4511 | if (selinux_compat_net) { | 4595 | if (selinux_compat_net) { |
4512 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, | 4596 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, |
4513 | ad, family, addrp)) | 4597 | &ad, family, addrp)) |
4514 | return NF_DROP; | 4598 | return NF_DROP; |
4515 | } else { | 4599 | } else { |
4516 | if (avc_has_perm(sksec->sid, skb->secmark, | 4600 | if (avc_has_perm(sksec->sid, skb->secmark, |
4517 | SECCLASS_PACKET, PACKET__SEND, ad)) | 4601 | SECCLASS_PACKET, PACKET__SEND, &ad)) |
4518 | return NF_DROP; | 4602 | return NF_DROP; |
4519 | } | 4603 | } |
4520 | 4604 | ||
4521 | if (selinux_policycap_netpeer) | 4605 | if (selinux_policycap_netpeer) |
4522 | if (selinux_xfrm_postroute_last(sksec->sid, skb, ad, proto)) | 4606 | if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) |
4523 | return NF_DROP; | 4607 | return NF_DROP; |
4524 | 4608 | ||
4525 | return NF_ACCEPT; | 4609 | return NF_ACCEPT; |
@@ -4533,23 +4617,15 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4533 | struct sock *sk; | 4617 | struct sock *sk; |
4534 | struct avc_audit_data ad; | 4618 | struct avc_audit_data ad; |
4535 | char *addrp; | 4619 | char *addrp; |
4536 | u8 proto; | ||
4537 | u8 secmark_active; | 4620 | u8 secmark_active; |
4538 | u8 peerlbl_active; | 4621 | u8 peerlbl_active; |
4539 | 4622 | ||
4540 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
4541 | ad.u.net.netif = ifindex; | ||
4542 | ad.u.net.family = family; | ||
4543 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) | ||
4544 | return NF_DROP; | ||
4545 | |||
4546 | /* If any sort of compatibility mode is enabled then handoff processing | 4623 | /* If any sort of compatibility mode is enabled then handoff processing |
4547 | * to the selinux_ip_postroute_compat() function to deal with the | 4624 | * to the selinux_ip_postroute_compat() function to deal with the |
4548 | * special handling. We do this in an attempt to keep this function | 4625 | * special handling. We do this in an attempt to keep this function |
4549 | * as fast and as clean as possible. */ | 4626 | * as fast and as clean as possible. */ |
4550 | if (selinux_compat_net || !selinux_policycap_netpeer) | 4627 | if (selinux_compat_net || !selinux_policycap_netpeer) |
4551 | return selinux_ip_postroute_compat(skb, ifindex, &ad, | 4628 | return selinux_ip_postroute_compat(skb, ifindex, family); |
4552 | family, addrp, proto); | ||
4553 | 4629 | ||
4554 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec | 4630 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec |
4555 | * packet transformation so allow the packet to pass without any checks | 4631 | * packet transformation so allow the packet to pass without any checks |
@@ -4565,21 +4641,45 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4565 | if (!secmark_active && !peerlbl_active) | 4641 | if (!secmark_active && !peerlbl_active) |
4566 | return NF_ACCEPT; | 4642 | return NF_ACCEPT; |
4567 | 4643 | ||
4568 | /* if the packet is locally generated (skb->sk != NULL) then use the | 4644 | /* if the packet is being forwarded then get the peer label from the |
4569 | * socket's label as the peer label, otherwise the packet is being | 4645 | * packet itself; otherwise check to see if it is from a local |
4570 | * forwarded through this system and we need to fetch the peer label | 4646 | * application or the kernel, if from an application get the peer label |
4571 | * directly from the packet */ | 4647 | * from the sending socket, otherwise use the kernel's sid */ |
4572 | sk = skb->sk; | 4648 | sk = skb->sk; |
4573 | if (sk) { | 4649 | if (sk == NULL) { |
4650 | switch (family) { | ||
4651 | case PF_INET: | ||
4652 | if (IPCB(skb)->flags & IPSKB_FORWARDED) | ||
4653 | secmark_perm = PACKET__FORWARD_OUT; | ||
4654 | else | ||
4655 | secmark_perm = PACKET__SEND; | ||
4656 | break; | ||
4657 | case PF_INET6: | ||
4658 | if (IP6CB(skb)->flags & IP6SKB_FORWARDED) | ||
4659 | secmark_perm = PACKET__FORWARD_OUT; | ||
4660 | else | ||
4661 | secmark_perm = PACKET__SEND; | ||
4662 | break; | ||
4663 | default: | ||
4664 | return NF_DROP; | ||
4665 | } | ||
4666 | if (secmark_perm == PACKET__FORWARD_OUT) { | ||
4667 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) | ||
4668 | return NF_DROP; | ||
4669 | } else | ||
4670 | peer_sid = SECINITSID_KERNEL; | ||
4671 | } else { | ||
4574 | struct sk_security_struct *sksec = sk->sk_security; | 4672 | struct sk_security_struct *sksec = sk->sk_security; |
4575 | peer_sid = sksec->sid; | 4673 | peer_sid = sksec->sid; |
4576 | secmark_perm = PACKET__SEND; | 4674 | secmark_perm = PACKET__SEND; |
4577 | } else { | ||
4578 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) | ||
4579 | return NF_DROP; | ||
4580 | secmark_perm = PACKET__FORWARD_OUT; | ||
4581 | } | 4675 | } |
4582 | 4676 | ||
4677 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
4678 | ad.u.net.netif = ifindex; | ||
4679 | ad.u.net.family = family; | ||
4680 | if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL)) | ||
4681 | return NF_DROP; | ||
4682 | |||
4583 | if (secmark_active) | 4683 | if (secmark_active) |
4584 | if (avc_has_perm(peer_sid, skb->secmark, | 4684 | if (avc_has_perm(peer_sid, skb->secmark, |
4585 | SECCLASS_PACKET, secmark_perm, &ad)) | 4685 | SECCLASS_PACKET, secmark_perm, &ad)) |
@@ -5222,8 +5322,12 @@ static int selinux_setprocattr(struct task_struct *p, | |||
5222 | 5322 | ||
5223 | if (sid == 0) | 5323 | if (sid == 0) |
5224 | return -EINVAL; | 5324 | return -EINVAL; |
5225 | 5325 | /* | |
5226 | /* Only allow single threaded processes to change context */ | 5326 | * SELinux allows to change context in the following case only. |
5327 | * - Single threaded processes. | ||
5328 | * - Multi threaded processes intend to change its context into | ||
5329 | * more restricted domain (defined by TYPEBOUNDS statement). | ||
5330 | */ | ||
5227 | if (atomic_read(&p->mm->mm_users) != 1) { | 5331 | if (atomic_read(&p->mm->mm_users) != 1) { |
5228 | struct task_struct *g, *t; | 5332 | struct task_struct *g, *t; |
5229 | struct mm_struct *mm = p->mm; | 5333 | struct mm_struct *mm = p->mm; |
@@ -5231,11 +5335,16 @@ static int selinux_setprocattr(struct task_struct *p, | |||
5231 | do_each_thread(g, t) { | 5335 | do_each_thread(g, t) { |
5232 | if (t->mm == mm && t != p) { | 5336 | if (t->mm == mm && t != p) { |
5233 | read_unlock(&tasklist_lock); | 5337 | read_unlock(&tasklist_lock); |
5234 | return -EPERM; | 5338 | error = security_bounded_transition(tsec->sid, sid); |
5339 | if (!error) | ||
5340 | goto boundary_ok; | ||
5341 | |||
5342 | return error; | ||
5235 | } | 5343 | } |
5236 | } while_each_thread(g, t); | 5344 | } while_each_thread(g, t); |
5237 | read_unlock(&tasklist_lock); | 5345 | read_unlock(&tasklist_lock); |
5238 | } | 5346 | } |
5347 | boundary_ok: | ||
5239 | 5348 | ||
5240 | /* Check permissions for the transition. */ | 5349 | /* Check permissions for the transition. */ |
5241 | error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, | 5350 | error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, |
@@ -5247,7 +5356,7 @@ static int selinux_setprocattr(struct task_struct *p, | |||
5247 | Otherwise, leave SID unchanged and fail. */ | 5356 | Otherwise, leave SID unchanged and fail. */ |
5248 | task_lock(p); | 5357 | task_lock(p); |
5249 | rcu_read_lock(); | 5358 | rcu_read_lock(); |
5250 | tracer = task_tracer_task(p); | 5359 | tracer = tracehook_tracer_task(p); |
5251 | if (tracer != NULL) { | 5360 | if (tracer != NULL) { |
5252 | struct task_security_struct *ptsec = tracer->security; | 5361 | struct task_security_struct *ptsec = tracer->security; |
5253 | u32 ptsid = ptsec->sid; | 5362 | u32 ptsid = ptsec->sid; |
@@ -5359,7 +5468,8 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) | |||
5359 | static struct security_operations selinux_ops = { | 5468 | static struct security_operations selinux_ops = { |
5360 | .name = "selinux", | 5469 | .name = "selinux", |
5361 | 5470 | ||
5362 | .ptrace = selinux_ptrace, | 5471 | .ptrace_may_access = selinux_ptrace_may_access, |
5472 | .ptrace_traceme = selinux_ptrace_traceme, | ||
5363 | .capget = selinux_capget, | 5473 | .capget = selinux_capget, |
5364 | .capset_check = selinux_capset_check, | 5474 | .capset_check = selinux_capset_check, |
5365 | .capset_set = selinux_capset_set, | 5475 | .capset_set = selinux_capset_set, |
@@ -5643,6 +5753,13 @@ static struct nf_hook_ops selinux_ipv4_ops[] = { | |||
5643 | .pf = PF_INET, | 5753 | .pf = PF_INET, |
5644 | .hooknum = NF_INET_FORWARD, | 5754 | .hooknum = NF_INET_FORWARD, |
5645 | .priority = NF_IP_PRI_SELINUX_FIRST, | 5755 | .priority = NF_IP_PRI_SELINUX_FIRST, |
5756 | }, | ||
5757 | { | ||
5758 | .hook = selinux_ipv4_output, | ||
5759 | .owner = THIS_MODULE, | ||
5760 | .pf = PF_INET, | ||
5761 | .hooknum = NF_INET_LOCAL_OUT, | ||
5762 | .priority = NF_IP_PRI_SELINUX_FIRST, | ||
5646 | } | 5763 | } |
5647 | }; | 5764 | }; |
5648 | 5765 | ||
@@ -5670,27 +5787,20 @@ static struct nf_hook_ops selinux_ipv6_ops[] = { | |||
5670 | static int __init selinux_nf_ip_init(void) | 5787 | static int __init selinux_nf_ip_init(void) |
5671 | { | 5788 | { |
5672 | int err = 0; | 5789 | int err = 0; |
5673 | u32 iter; | ||
5674 | 5790 | ||
5675 | if (!selinux_enabled) | 5791 | if (!selinux_enabled) |
5676 | goto out; | 5792 | goto out; |
5677 | 5793 | ||
5678 | printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n"); | 5794 | printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n"); |
5679 | 5795 | ||
5680 | for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++) { | 5796 | err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops)); |
5681 | err = nf_register_hook(&selinux_ipv4_ops[iter]); | 5797 | if (err) |
5682 | if (err) | 5798 | panic("SELinux: nf_register_hooks for IPv4: error %d\n", err); |
5683 | panic("SELinux: nf_register_hook for IPv4: error %d\n", | ||
5684 | err); | ||
5685 | } | ||
5686 | 5799 | ||
5687 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 5800 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
5688 | for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++) { | 5801 | err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops)); |
5689 | err = nf_register_hook(&selinux_ipv6_ops[iter]); | 5802 | if (err) |
5690 | if (err) | 5803 | panic("SELinux: nf_register_hooks for IPv6: error %d\n", err); |
5691 | panic("SELinux: nf_register_hook for IPv6: error %d\n", | ||
5692 | err); | ||
5693 | } | ||
5694 | #endif /* IPV6 */ | 5804 | #endif /* IPV6 */ |
5695 | 5805 | ||
5696 | out: | 5806 | out: |
@@ -5702,15 +5812,11 @@ __initcall(selinux_nf_ip_init); | |||
5702 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE | 5812 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE |
5703 | static void selinux_nf_ip_exit(void) | 5813 | static void selinux_nf_ip_exit(void) |
5704 | { | 5814 | { |
5705 | u32 iter; | ||
5706 | |||
5707 | printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n"); | 5815 | printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n"); |
5708 | 5816 | ||
5709 | for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++) | 5817 | nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops)); |
5710 | nf_unregister_hook(&selinux_ipv4_ops[iter]); | ||
5711 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 5818 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
5712 | for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++) | 5819 | nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops)); |
5713 | nf_unregister_hook(&selinux_ipv6_ops[iter]); | ||
5714 | #endif /* IPV6 */ | 5820 | #endif /* IPV6 */ |
5715 | } | 5821 | } |
5716 | #endif | 5822 | #endif |
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/netlabel.h b/security/selinux/include/netlabel.h index 487a7d81fe20..b913c8d06038 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h | |||
@@ -39,6 +39,9 @@ | |||
39 | #ifdef CONFIG_NETLABEL | 39 | #ifdef CONFIG_NETLABEL |
40 | void selinux_netlbl_cache_invalidate(void); | 40 | void selinux_netlbl_cache_invalidate(void); |
41 | 41 | ||
42 | void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); | ||
43 | |||
44 | void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec); | ||
42 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, | 45 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, |
43 | int family); | 46 | int family); |
44 | 47 | ||
@@ -46,8 +49,11 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
46 | u16 family, | 49 | u16 family, |
47 | u32 *type, | 50 | u32 *type, |
48 | u32 *sid); | 51 | u32 *sid); |
52 | int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | ||
53 | u16 family, | ||
54 | u32 sid); | ||
49 | 55 | ||
50 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); | 56 | void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family); |
51 | int selinux_netlbl_socket_post_create(struct socket *sock); | 57 | int selinux_netlbl_socket_post_create(struct socket *sock); |
52 | int selinux_netlbl_inode_permission(struct inode *inode, int mask); | 58 | int selinux_netlbl_inode_permission(struct inode *inode, int mask); |
53 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | 59 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, |
@@ -57,12 +63,27 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | |||
57 | int selinux_netlbl_socket_setsockopt(struct socket *sock, | 63 | int selinux_netlbl_socket_setsockopt(struct socket *sock, |
58 | int level, | 64 | int level, |
59 | int optname); | 65 | int optname); |
66 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr); | ||
67 | |||
60 | #else | 68 | #else |
61 | static inline void selinux_netlbl_cache_invalidate(void) | 69 | static inline void selinux_netlbl_cache_invalidate(void) |
62 | { | 70 | { |
63 | return; | 71 | return; |
64 | } | 72 | } |
65 | 73 | ||
74 | static inline void selinux_netlbl_err(struct sk_buff *skb, | ||
75 | int error, | ||
76 | int gateway) | ||
77 | { | ||
78 | return; | ||
79 | } | ||
80 | |||
81 | static inline void selinux_netlbl_sk_security_free( | ||
82 | struct sk_security_struct *ssec) | ||
83 | { | ||
84 | return; | ||
85 | } | ||
86 | |||
66 | static inline void selinux_netlbl_sk_security_reset( | 87 | static inline void selinux_netlbl_sk_security_reset( |
67 | struct sk_security_struct *ssec, | 88 | struct sk_security_struct *ssec, |
68 | int family) | 89 | int family) |
@@ -79,9 +100,21 @@ static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
79 | *sid = SECSID_NULL; | 100 | *sid = SECSID_NULL; |
80 | return 0; | 101 | return 0; |
81 | } | 102 | } |
103 | static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | ||
104 | u16 family, | ||
105 | u32 sid) | ||
106 | { | ||
107 | return 0; | ||
108 | } | ||
82 | 109 | ||
83 | static inline void selinux_netlbl_sock_graft(struct sock *sk, | 110 | static inline int selinux_netlbl_conn_setsid(struct sock *sk, |
84 | struct socket *sock) | 111 | struct sockaddr *addr) |
112 | { | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static inline void selinux_netlbl_inet_conn_established(struct sock *sk, | ||
117 | u16 family) | ||
85 | { | 118 | { |
86 | return; | 119 | return; |
87 | } | 120 | } |
@@ -107,6 +140,11 @@ static inline int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
107 | { | 140 | { |
108 | return 0; | 141 | return 0; |
109 | } | 142 | } |
143 | static inline int selinux_netlbl_socket_connect(struct sock *sk, | ||
144 | struct sockaddr *addr) | ||
145 | { | ||
146 | return 0; | ||
147 | } | ||
110 | #endif /* CONFIG_NETLABEL */ | 148 | #endif /* CONFIG_NETLABEL */ |
111 | 149 | ||
112 | #endif | 150 | #endif |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 91070ab874ce..f8be8d7fa26d 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -109,16 +109,19 @@ struct netport_security_struct { | |||
109 | }; | 109 | }; |
110 | 110 | ||
111 | struct sk_security_struct { | 111 | struct sk_security_struct { |
112 | u32 sid; /* SID of this object */ | ||
113 | u32 peer_sid; /* SID of peer */ | ||
114 | u16 sclass; /* sock security class */ | ||
115 | #ifdef CONFIG_NETLABEL | 112 | #ifdef CONFIG_NETLABEL |
116 | enum { /* NetLabel state */ | 113 | enum { /* NetLabel state */ |
117 | NLBL_UNSET = 0, | 114 | NLBL_UNSET = 0, |
118 | NLBL_REQUIRE, | 115 | NLBL_REQUIRE, |
119 | NLBL_LABELED, | 116 | NLBL_LABELED, |
117 | NLBL_REQSKB, | ||
118 | NLBL_CONNLABELED, | ||
120 | } nlbl_state; | 119 | } nlbl_state; |
120 | struct netlbl_lsm_secattr *nlbl_secattr; /* NetLabel sec attributes */ | ||
121 | #endif | 121 | #endif |
122 | u32 sid; /* SID of this object */ | ||
123 | u32 peer_sid; /* SID of peer */ | ||
124 | u16 sclass; /* sock security class */ | ||
122 | }; | 125 | }; |
123 | 126 | ||
124 | struct key_security_struct { | 127 | struct key_security_struct { |
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/netlabel.c b/security/selinux/netlabel.c index 89b418392f11..f58701a7b728 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
@@ -9,7 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | /* | 11 | /* |
12 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2007 | 12 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008 |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
@@ -29,8 +29,12 @@ | |||
29 | 29 | ||
30 | #include <linux/spinlock.h> | 30 | #include <linux/spinlock.h> |
31 | #include <linux/rcupdate.h> | 31 | #include <linux/rcupdate.h> |
32 | #include <linux/ip.h> | ||
33 | #include <linux/ipv6.h> | ||
32 | #include <net/sock.h> | 34 | #include <net/sock.h> |
33 | #include <net/netlabel.h> | 35 | #include <net/netlabel.h> |
36 | #include <net/ip.h> | ||
37 | #include <net/ipv6.h> | ||
34 | 38 | ||
35 | #include "objsec.h" | 39 | #include "objsec.h" |
36 | #include "security.h" | 40 | #include "security.h" |
@@ -64,32 +68,69 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, | |||
64 | } | 68 | } |
65 | 69 | ||
66 | /** | 70 | /** |
71 | * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr | ||
72 | * @sk: the socket | ||
73 | * | ||
74 | * Description: | ||
75 | * Generate the NetLabel security attributes for a socket, making full use of | ||
76 | * the socket's attribute cache. Returns a pointer to the security attributes | ||
77 | * on success, NULL on failure. | ||
78 | * | ||
79 | */ | ||
80 | static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) | ||
81 | { | ||
82 | int rc; | ||
83 | struct sk_security_struct *sksec = sk->sk_security; | ||
84 | struct netlbl_lsm_secattr *secattr; | ||
85 | |||
86 | if (sksec->nlbl_secattr != NULL) | ||
87 | return sksec->nlbl_secattr; | ||
88 | |||
89 | secattr = netlbl_secattr_alloc(GFP_ATOMIC); | ||
90 | if (secattr == NULL) | ||
91 | return NULL; | ||
92 | rc = security_netlbl_sid_to_secattr(sksec->sid, secattr); | ||
93 | if (rc != 0) { | ||
94 | netlbl_secattr_free(secattr); | ||
95 | return NULL; | ||
96 | } | ||
97 | sksec->nlbl_secattr = secattr; | ||
98 | |||
99 | return secattr; | ||
100 | } | ||
101 | |||
102 | /** | ||
67 | * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism | 103 | * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism |
68 | * @sk: the socket to label | 104 | * @sk: the socket to label |
69 | * @sid: the SID to use | ||
70 | * | 105 | * |
71 | * Description: | 106 | * Description: |
72 | * Attempt to label a socket using the NetLabel mechanism using the given | 107 | * Attempt to label a socket using the NetLabel mechanism. Returns zero values |
73 | * SID. Returns zero values on success, negative values on failure. | 108 | * on success, negative values on failure. |
74 | * | 109 | * |
75 | */ | 110 | */ |
76 | static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid) | 111 | static int selinux_netlbl_sock_setsid(struct sock *sk) |
77 | { | 112 | { |
78 | int rc; | 113 | int rc; |
79 | struct sk_security_struct *sksec = sk->sk_security; | 114 | struct sk_security_struct *sksec = sk->sk_security; |
80 | struct netlbl_lsm_secattr secattr; | 115 | struct netlbl_lsm_secattr *secattr; |
81 | 116 | ||
82 | netlbl_secattr_init(&secattr); | 117 | if (sksec->nlbl_state != NLBL_REQUIRE) |
118 | return 0; | ||
83 | 119 | ||
84 | rc = security_netlbl_sid_to_secattr(sid, &secattr); | 120 | secattr = selinux_netlbl_sock_genattr(sk); |
85 | if (rc != 0) | 121 | if (secattr == NULL) |
86 | goto sock_setsid_return; | 122 | return -ENOMEM; |
87 | rc = netlbl_sock_setattr(sk, &secattr); | 123 | rc = netlbl_sock_setattr(sk, secattr); |
88 | if (rc == 0) | 124 | switch (rc) { |
125 | case 0: | ||
89 | sksec->nlbl_state = NLBL_LABELED; | 126 | sksec->nlbl_state = NLBL_LABELED; |
127 | break; | ||
128 | case -EDESTADDRREQ: | ||
129 | sksec->nlbl_state = NLBL_REQSKB; | ||
130 | rc = 0; | ||
131 | break; | ||
132 | } | ||
90 | 133 | ||
91 | sock_setsid_return: | ||
92 | netlbl_secattr_destroy(&secattr); | ||
93 | return rc; | 134 | return rc; |
94 | } | 135 | } |
95 | 136 | ||
@@ -106,6 +147,38 @@ void selinux_netlbl_cache_invalidate(void) | |||
106 | } | 147 | } |
107 | 148 | ||
108 | /** | 149 | /** |
150 | * selinux_netlbl_err - Handle a NetLabel packet error | ||
151 | * @skb: the packet | ||
152 | * @error: the error code | ||
153 | * @gateway: true if host is acting as a gateway, false otherwise | ||
154 | * | ||
155 | * Description: | ||
156 | * When a packet is dropped due to a call to avc_has_perm() pass the error | ||
157 | * code to the NetLabel subsystem so any protocol specific processing can be | ||
158 | * done. This is safe to call even if you are unsure if NetLabel labeling is | ||
159 | * present on the packet, NetLabel is smart enough to only act when it should. | ||
160 | * | ||
161 | */ | ||
162 | void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway) | ||
163 | { | ||
164 | netlbl_skbuff_err(skb, error, gateway); | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * selinux_netlbl_sk_security_free - Free the NetLabel fields | ||
169 | * @sssec: the sk_security_struct | ||
170 | * | ||
171 | * Description: | ||
172 | * Free all of the memory in the NetLabel fields of a sk_security_struct. | ||
173 | * | ||
174 | */ | ||
175 | void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec) | ||
176 | { | ||
177 | if (ssec->nlbl_secattr != NULL) | ||
178 | netlbl_secattr_free(ssec->nlbl_secattr); | ||
179 | } | ||
180 | |||
181 | /** | ||
109 | * selinux_netlbl_sk_security_reset - Reset the NetLabel fields | 182 | * selinux_netlbl_sk_security_reset - Reset the NetLabel fields |
110 | * @ssec: the sk_security_struct | 183 | * @ssec: the sk_security_struct |
111 | * @family: the socket family | 184 | * @family: the socket family |
@@ -163,35 +236,118 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
163 | } | 236 | } |
164 | 237 | ||
165 | /** | 238 | /** |
166 | * selinux_netlbl_sock_graft - Netlabel the new socket | 239 | * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid |
240 | * @skb: the packet | ||
241 | * @family: protocol family | ||
242 | * @sid: the SID | ||
243 | * | ||
244 | * Description | ||
245 | * Call the NetLabel mechanism to set the label of a packet using @sid. | ||
246 | * Returns zero on auccess, negative values on failure. | ||
247 | * | ||
248 | */ | ||
249 | int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | ||
250 | u16 family, | ||
251 | u32 sid) | ||
252 | { | ||
253 | int rc; | ||
254 | struct netlbl_lsm_secattr secattr_storage; | ||
255 | struct netlbl_lsm_secattr *secattr = NULL; | ||
256 | struct sock *sk; | ||
257 | |||
258 | /* if this is a locally generated packet check to see if it is already | ||
259 | * being labeled by it's parent socket, if it is just exit */ | ||
260 | sk = skb->sk; | ||
261 | if (sk != NULL) { | ||
262 | struct sk_security_struct *sksec = sk->sk_security; | ||
263 | if (sksec->nlbl_state != NLBL_REQSKB) | ||
264 | return 0; | ||
265 | secattr = sksec->nlbl_secattr; | ||
266 | } | ||
267 | if (secattr == NULL) { | ||
268 | secattr = &secattr_storage; | ||
269 | netlbl_secattr_init(secattr); | ||
270 | rc = security_netlbl_sid_to_secattr(sid, secattr); | ||
271 | if (rc != 0) | ||
272 | goto skbuff_setsid_return; | ||
273 | } | ||
274 | |||
275 | rc = netlbl_skbuff_setattr(skb, family, secattr); | ||
276 | |||
277 | skbuff_setsid_return: | ||
278 | if (secattr == &secattr_storage) | ||
279 | netlbl_secattr_destroy(secattr); | ||
280 | return rc; | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection | ||
167 | * @sk: the new connection | 285 | * @sk: the new connection |
168 | * @sock: the new socket | ||
169 | * | 286 | * |
170 | * Description: | 287 | * Description: |
171 | * The connection represented by @sk is being grafted onto @sock so set the | 288 | * A new connection has been established on @sk so make sure it is labeled |
172 | * socket's NetLabel to match the SID of @sk. | 289 | * correctly with the NetLabel susbsystem. |
173 | * | 290 | * |
174 | */ | 291 | */ |
175 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) | 292 | void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) |
176 | { | 293 | { |
294 | int rc; | ||
177 | struct sk_security_struct *sksec = sk->sk_security; | 295 | struct sk_security_struct *sksec = sk->sk_security; |
178 | struct netlbl_lsm_secattr secattr; | 296 | struct netlbl_lsm_secattr *secattr; |
179 | u32 nlbl_peer_sid; | 297 | struct inet_sock *sk_inet = inet_sk(sk); |
298 | struct sockaddr_in addr; | ||
180 | 299 | ||
181 | if (sksec->nlbl_state != NLBL_REQUIRE) | 300 | if (sksec->nlbl_state != NLBL_REQUIRE) |
182 | return; | 301 | return; |
183 | 302 | ||
184 | netlbl_secattr_init(&secattr); | 303 | secattr = selinux_netlbl_sock_genattr(sk); |
185 | if (netlbl_sock_getattr(sk, &secattr) == 0 && | 304 | if (secattr == NULL) |
186 | secattr.flags != NETLBL_SECATTR_NONE && | 305 | return; |
187 | security_netlbl_secattr_to_sid(&secattr, &nlbl_peer_sid) == 0) | ||
188 | sksec->peer_sid = nlbl_peer_sid; | ||
189 | netlbl_secattr_destroy(&secattr); | ||
190 | 306 | ||
191 | /* Try to set the NetLabel on the socket to save time later, if we fail | 307 | rc = netlbl_sock_setattr(sk, secattr); |
192 | * here we will pick up the pieces in later calls to | 308 | switch (rc) { |
193 | * selinux_netlbl_inode_permission(). */ | 309 | case 0: |
194 | selinux_netlbl_sock_setsid(sk, sksec->sid); | 310 | sksec->nlbl_state = NLBL_LABELED; |
311 | break; | ||
312 | case -EDESTADDRREQ: | ||
313 | /* no PF_INET6 support yet because we don't support any IPv6 | ||
314 | * labeling protocols */ | ||
315 | if (family != PF_INET) { | ||
316 | sksec->nlbl_state = NLBL_UNSET; | ||
317 | return; | ||
318 | } | ||
319 | |||
320 | addr.sin_family = family; | ||
321 | addr.sin_addr.s_addr = sk_inet->daddr; | ||
322 | if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr, | ||
323 | secattr) != 0) { | ||
324 | /* we failed to label the connected socket (could be | ||
325 | * for a variety of reasons, the actual "why" isn't | ||
326 | * important here) so we have to go to our backup plan, | ||
327 | * labeling the packets individually in the netfilter | ||
328 | * local output hook. this is okay but we need to | ||
329 | * adjust the MSS of the connection to take into | ||
330 | * account any labeling overhead, since we don't know | ||
331 | * the exact overhead at this point we'll use the worst | ||
332 | * case value which is 40 bytes for IPv4 */ | ||
333 | struct inet_connection_sock *sk_conn = inet_csk(sk); | ||
334 | sk_conn->icsk_ext_hdr_len += 40 - | ||
335 | (sk_inet->opt ? sk_inet->opt->optlen : 0); | ||
336 | sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); | ||
337 | |||
338 | sksec->nlbl_state = NLBL_REQSKB; | ||
339 | } else | ||
340 | sksec->nlbl_state = NLBL_CONNLABELED; | ||
341 | break; | ||
342 | default: | ||
343 | /* note that we are failing to label the socket which could be | ||
344 | * a bad thing since it means traffic could leave the system | ||
345 | * without the desired labeling, however, all is not lost as | ||
346 | * we have a check in selinux_netlbl_inode_permission() to | ||
347 | * pick up the pieces that we might drop here because we can't | ||
348 | * return an error code */ | ||
349 | break; | ||
350 | } | ||
195 | } | 351 | } |
196 | 352 | ||
197 | /** | 353 | /** |
@@ -205,13 +361,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) | |||
205 | */ | 361 | */ |
206 | int selinux_netlbl_socket_post_create(struct socket *sock) | 362 | int selinux_netlbl_socket_post_create(struct socket *sock) |
207 | { | 363 | { |
208 | struct sock *sk = sock->sk; | 364 | return selinux_netlbl_sock_setsid(sock->sk); |
209 | struct sk_security_struct *sksec = sk->sk_security; | ||
210 | |||
211 | if (sksec->nlbl_state != NLBL_REQUIRE) | ||
212 | return 0; | ||
213 | |||
214 | return selinux_netlbl_sock_setsid(sk, sksec->sid); | ||
215 | } | 365 | } |
216 | 366 | ||
217 | /** | 367 | /** |
@@ -246,7 +396,7 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask) | |||
246 | local_bh_disable(); | 396 | local_bh_disable(); |
247 | bh_lock_sock_nested(sk); | 397 | bh_lock_sock_nested(sk); |
248 | if (likely(sksec->nlbl_state == NLBL_REQUIRE)) | 398 | if (likely(sksec->nlbl_state == NLBL_REQUIRE)) |
249 | rc = selinux_netlbl_sock_setsid(sk, sksec->sid); | 399 | rc = selinux_netlbl_sock_setsid(sk); |
250 | else | 400 | else |
251 | rc = 0; | 401 | rc = 0; |
252 | bh_unlock_sock(sk); | 402 | bh_unlock_sock(sk); |
@@ -307,7 +457,7 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | |||
307 | return 0; | 457 | return 0; |
308 | 458 | ||
309 | if (nlbl_sid != SECINITSID_UNLABELED) | 459 | if (nlbl_sid != SECINITSID_UNLABELED) |
310 | netlbl_skbuff_err(skb, rc); | 460 | netlbl_skbuff_err(skb, rc, 0); |
311 | return rc; | 461 | return rc; |
312 | } | 462 | } |
313 | 463 | ||
@@ -334,7 +484,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
334 | struct netlbl_lsm_secattr secattr; | 484 | struct netlbl_lsm_secattr secattr; |
335 | 485 | ||
336 | if (level == IPPROTO_IP && optname == IP_OPTIONS && | 486 | if (level == IPPROTO_IP && optname == IP_OPTIONS && |
337 | sksec->nlbl_state == NLBL_LABELED) { | 487 | (sksec->nlbl_state == NLBL_LABELED || |
488 | sksec->nlbl_state == NLBL_CONNLABELED)) { | ||
338 | netlbl_secattr_init(&secattr); | 489 | netlbl_secattr_init(&secattr); |
339 | lock_sock(sk); | 490 | lock_sock(sk); |
340 | rc = netlbl_sock_getattr(sk, &secattr); | 491 | rc = netlbl_sock_getattr(sk, &secattr); |
@@ -346,3 +497,50 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
346 | 497 | ||
347 | return rc; | 498 | return rc; |
348 | } | 499 | } |
500 | |||
501 | /** | ||
502 | * selinux_netlbl_socket_connect - Label a client-side socket on connect | ||
503 | * @sk: the socket to label | ||
504 | * @addr: the destination address | ||
505 | * | ||
506 | * Description: | ||
507 | * Attempt to label a connected socket with NetLabel using the given address. | ||
508 | * Returns zero values on success, negative values on failure. | ||
509 | * | ||
510 | */ | ||
511 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) | ||
512 | { | ||
513 | int rc; | ||
514 | struct sk_security_struct *sksec = sk->sk_security; | ||
515 | struct netlbl_lsm_secattr *secattr; | ||
516 | |||
517 | if (sksec->nlbl_state != NLBL_REQSKB && | ||
518 | sksec->nlbl_state != NLBL_CONNLABELED) | ||
519 | return 0; | ||
520 | |||
521 | local_bh_disable(); | ||
522 | bh_lock_sock_nested(sk); | ||
523 | |||
524 | /* connected sockets are allowed to disconnect when the address family | ||
525 | * is set to AF_UNSPEC, if that is what is happening we want to reset | ||
526 | * the socket */ | ||
527 | if (addr->sa_family == AF_UNSPEC) { | ||
528 | netlbl_sock_delattr(sk); | ||
529 | sksec->nlbl_state = NLBL_REQSKB; | ||
530 | rc = 0; | ||
531 | goto socket_connect_return; | ||
532 | } | ||
533 | secattr = selinux_netlbl_sock_genattr(sk); | ||
534 | if (secattr == NULL) { | ||
535 | rc = -ENOMEM; | ||
536 | goto socket_connect_return; | ||
537 | } | ||
538 | rc = netlbl_conn_setattr(sk, addr, secattr); | ||
539 | if (rc == 0) | ||
540 | sksec->nlbl_state = NLBL_CONNLABELED; | ||
541 | |||
542 | socket_connect_return: | ||
543 | bh_unlock_sock(sk); | ||
544 | local_bh_enable(); | ||
545 | return rc; | ||
546 | } | ||
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 b52f923ce680..343c8ab14af0 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; |
@@ -811,11 +981,12 @@ static int string_to_context_struct(struct policydb *pol, | |||
811 | /* Check the validity of the new context. */ | 981 | /* Check the validity of the new context. */ |
812 | if (!policydb_context_isvalid(pol, ctx)) { | 982 | if (!policydb_context_isvalid(pol, ctx)) { |
813 | rc = -EINVAL; | 983 | rc = -EINVAL; |
814 | context_destroy(ctx); | ||
815 | goto out; | 984 | goto out; |
816 | } | 985 | } |
817 | rc = 0; | 986 | rc = 0; |
818 | out: | 987 | out: |
988 | if (rc) | ||
989 | context_destroy(ctx); | ||
819 | return rc; | 990 | return rc; |
820 | } | 991 | } |
821 | 992 | ||
@@ -868,8 +1039,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | |||
868 | } else if (rc) | 1039 | } else if (rc) |
869 | goto out; | 1040 | goto out; |
870 | rc = sidtab_context_to_sid(&sidtab, &context, sid); | 1041 | rc = sidtab_context_to_sid(&sidtab, &context, sid); |
871 | if (rc) | 1042 | context_destroy(&context); |
872 | context_destroy(&context); | ||
873 | out: | 1043 | out: |
874 | read_unlock(&policy_rwlock); | 1044 | read_unlock(&policy_rwlock); |
875 | kfree(scontext2); | 1045 | kfree(scontext2); |
@@ -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; |
@@ -2737,6 +2907,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, | |||
2737 | if (ctx == NULL) | 2907 | if (ctx == NULL) |
2738 | goto netlbl_secattr_to_sid_return; | 2908 | goto netlbl_secattr_to_sid_return; |
2739 | 2909 | ||
2910 | context_init(&ctx_new); | ||
2740 | ctx_new.user = ctx->user; | 2911 | ctx_new.user = ctx->user; |
2741 | ctx_new.role = ctx->role; | 2912 | ctx_new.role = ctx->role; |
2742 | ctx_new.type = ctx->type; | 2913 | ctx_new.type = ctx->type; |
@@ -2745,13 +2916,9 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, | |||
2745 | if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat, | 2916 | if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat, |
2746 | secattr->attr.mls.cat) != 0) | 2917 | secattr->attr.mls.cat) != 0) |
2747 | goto netlbl_secattr_to_sid_return; | 2918 | goto netlbl_secattr_to_sid_return; |
2748 | ctx_new.range.level[1].cat.highbit = | 2919 | memcpy(&ctx_new.range.level[1].cat, |
2749 | ctx_new.range.level[0].cat.highbit; | 2920 | &ctx_new.range.level[0].cat, |
2750 | ctx_new.range.level[1].cat.node = | 2921 | sizeof(ctx_new.range.level[0].cat)); |
2751 | ctx_new.range.level[0].cat.node; | ||
2752 | } else { | ||
2753 | ebitmap_init(&ctx_new.range.level[0].cat); | ||
2754 | ebitmap_init(&ctx_new.range.level[1].cat); | ||
2755 | } | 2922 | } |
2756 | if (mls_context_isvalid(&policydb, &ctx_new) != 1) | 2923 | if (mls_context_isvalid(&policydb, &ctx_new) != 1) |
2757 | goto netlbl_secattr_to_sid_return_cleanup; | 2924 | goto netlbl_secattr_to_sid_return_cleanup; |
@@ -2788,7 +2955,7 @@ netlbl_secattr_to_sid_return_cleanup: | |||
2788 | */ | 2955 | */ |
2789 | int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) | 2956 | int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) |
2790 | { | 2957 | { |
2791 | int rc = -ENOENT; | 2958 | int rc; |
2792 | struct context *ctx; | 2959 | struct context *ctx; |
2793 | 2960 | ||
2794 | if (!ss_initialized) | 2961 | if (!ss_initialized) |
@@ -2796,11 +2963,18 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) | |||
2796 | 2963 | ||
2797 | read_lock(&policy_rwlock); | 2964 | read_lock(&policy_rwlock); |
2798 | ctx = sidtab_search(&sidtab, sid); | 2965 | ctx = sidtab_search(&sidtab, sid); |
2799 | if (ctx == NULL) | 2966 | if (ctx == NULL) { |
2967 | rc = -ENOENT; | ||
2800 | goto netlbl_sid_to_secattr_failure; | 2968 | goto netlbl_sid_to_secattr_failure; |
2969 | } | ||
2801 | secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], | 2970 | secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], |
2802 | GFP_ATOMIC); | 2971 | GFP_ATOMIC); |
2803 | secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY; | 2972 | if (secattr->domain == NULL) { |
2973 | rc = -ENOMEM; | ||
2974 | goto netlbl_sid_to_secattr_failure; | ||
2975 | } | ||
2976 | secattr->attr.secid = sid; | ||
2977 | secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID; | ||
2804 | mls_export_netlbl_lvl(ctx, secattr); | 2978 | mls_export_netlbl_lvl(ctx, secattr); |
2805 | rc = mls_export_netlbl_cat(ctx, secattr); | 2979 | rc = mls_export_netlbl_cat(ctx, secattr); |
2806 | if (rc != 0) | 2980 | if (rc != 0) |
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/smack_lsm.c b/security/smack/smack_lsm.c index ee5a51cbc5eb..6e2dc0bab70d 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -87,27 +87,46 @@ struct inode_smack *new_inode_smack(char *smack) | |||
87 | */ | 87 | */ |
88 | 88 | ||
89 | /** | 89 | /** |
90 | * smack_ptrace - Smack approval on ptrace | 90 | * smack_ptrace_may_access - Smack approval on PTRACE_ATTACH |
91 | * @ptp: parent task pointer | ||
92 | * @ctp: child task pointer | 91 | * @ctp: child task pointer |
93 | * | 92 | * |
94 | * Returns 0 if access is OK, an error code otherwise | 93 | * Returns 0 if access is OK, an error code otherwise |
95 | * | 94 | * |
96 | * Do the capability checks, and require read and write. | 95 | * Do the capability checks, and require read and write. |
97 | */ | 96 | */ |
98 | static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp, | 97 | static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode) |
99 | unsigned int mode) | ||
100 | { | 98 | { |
101 | int rc; | 99 | int rc; |
102 | 100 | ||
103 | rc = cap_ptrace(ptp, ctp, mode); | 101 | rc = cap_ptrace_may_access(ctp, mode); |
104 | if (rc != 0) | 102 | if (rc != 0) |
105 | return rc; | 103 | return rc; |
106 | 104 | ||
107 | rc = smk_access(ptp->security, ctp->security, MAY_READWRITE); | 105 | rc = smk_access(current->security, ctp->security, MAY_READWRITE); |
108 | if (rc != 0 && __capable(ptp, CAP_MAC_OVERRIDE)) | 106 | if (rc != 0 && capable(CAP_MAC_OVERRIDE)) |
109 | return 0; | 107 | return 0; |
108 | return rc; | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * smack_ptrace_traceme - Smack approval on PTRACE_TRACEME | ||
113 | * @ptp: parent task pointer | ||
114 | * | ||
115 | * Returns 0 if access is OK, an error code otherwise | ||
116 | * | ||
117 | * Do the capability checks, and require read and write. | ||
118 | */ | ||
119 | static int smack_ptrace_traceme(struct task_struct *ptp) | ||
120 | { | ||
121 | int rc; | ||
110 | 122 | ||
123 | rc = cap_ptrace_traceme(ptp); | ||
124 | if (rc != 0) | ||
125 | return rc; | ||
126 | |||
127 | rc = smk_access(ptp->security, current->security, MAY_READWRITE); | ||
128 | if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE)) | ||
129 | return 0; | ||
111 | return rc; | 130 | return rc; |
112 | } | 131 | } |
113 | 132 | ||
@@ -522,8 +541,7 @@ static int smack_inode_rename(struct inode *old_inode, | |||
522 | * | 541 | * |
523 | * Returns 0 if access is permitted, -EACCES otherwise | 542 | * Returns 0 if access is permitted, -EACCES otherwise |
524 | */ | 543 | */ |
525 | static int smack_inode_permission(struct inode *inode, int mask, | 544 | static int smack_inode_permission(struct inode *inode, int mask) |
526 | struct nameidata *nd) | ||
527 | { | 545 | { |
528 | /* | 546 | /* |
529 | * No permission to check. Existence test. Yup, it's there. | 547 | * No permission to check. Existence test. Yup, it's there. |
@@ -924,7 +942,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, | |||
924 | */ | 942 | */ |
925 | file = container_of(fown, struct file, f_owner); | 943 | file = container_of(fown, struct file, f_owner); |
926 | rc = smk_access(file->f_security, tsk->security, MAY_WRITE); | 944 | rc = smk_access(file->f_security, tsk->security, MAY_WRITE); |
927 | if (rc != 0 && __capable(tsk, CAP_MAC_OVERRIDE)) | 945 | if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE)) |
928 | return 0; | 946 | return 0; |
929 | return rc; | 947 | return rc; |
930 | } | 948 | } |
@@ -1165,12 +1183,12 @@ static int smack_task_wait(struct task_struct *p) | |||
1165 | * account for the smack labels having gotten to | 1183 | * account for the smack labels having gotten to |
1166 | * be different in the first place. | 1184 | * be different in the first place. |
1167 | * | 1185 | * |
1168 | * This breaks the strict subjet/object access | 1186 | * This breaks the strict subject/object access |
1169 | * control ideal, taking the object's privilege | 1187 | * control ideal, taking the object's privilege |
1170 | * state into account in the decision as well as | 1188 | * state into account in the decision as well as |
1171 | * the smack value. | 1189 | * the smack value. |
1172 | */ | 1190 | */ |
1173 | if (capable(CAP_MAC_OVERRIDE) || __capable(p, CAP_MAC_OVERRIDE)) | 1191 | if (capable(CAP_MAC_OVERRIDE) || has_capability(p, CAP_MAC_OVERRIDE)) |
1174 | return 0; | 1192 | return 0; |
1175 | 1193 | ||
1176 | return rc; | 1194 | return rc; |
@@ -2017,9 +2035,6 @@ static int smack_setprocattr(struct task_struct *p, char *name, | |||
2017 | { | 2035 | { |
2018 | char *newsmack; | 2036 | char *newsmack; |
2019 | 2037 | ||
2020 | if (!__capable(p, CAP_MAC_ADMIN)) | ||
2021 | return -EPERM; | ||
2022 | |||
2023 | /* | 2038 | /* |
2024 | * Changing another process' Smack value is too dangerous | 2039 | * Changing another process' Smack value is too dangerous |
2025 | * and supports no sane use case. | 2040 | * and supports no sane use case. |
@@ -2027,6 +2042,9 @@ static int smack_setprocattr(struct task_struct *p, char *name, | |||
2027 | if (p != current) | 2042 | if (p != current) |
2028 | return -EPERM; | 2043 | return -EPERM; |
2029 | 2044 | ||
2045 | if (!capable(CAP_MAC_ADMIN)) | ||
2046 | return -EPERM; | ||
2047 | |||
2030 | if (value == NULL || size == 0 || size >= SMK_LABELLEN) | 2048 | if (value == NULL || size == 0 || size >= SMK_LABELLEN) |
2031 | return -EINVAL; | 2049 | return -EINVAL; |
2032 | 2050 | ||
@@ -2161,7 +2179,10 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
2161 | * This is the simplist possible security model | 2179 | * This is the simplist possible security model |
2162 | * for networking. | 2180 | * for networking. |
2163 | */ | 2181 | */ |
2164 | return smk_access(smack, ssp->smk_in, MAY_WRITE); | 2182 | rc = smk_access(smack, ssp->smk_in, MAY_WRITE); |
2183 | if (rc != 0) | ||
2184 | netlbl_skbuff_err(skb, rc, 0); | ||
2185 | return rc; | ||
2165 | } | 2186 | } |
2166 | 2187 | ||
2167 | /** | 2188 | /** |
@@ -2553,7 +2574,8 @@ static void smack_release_secctx(char *secdata, u32 seclen) | |||
2553 | struct security_operations smack_ops = { | 2574 | struct security_operations smack_ops = { |
2554 | .name = "smack", | 2575 | .name = "smack", |
2555 | 2576 | ||
2556 | .ptrace = smack_ptrace, | 2577 | .ptrace_may_access = smack_ptrace_may_access, |
2578 | .ptrace_traceme = smack_ptrace_traceme, | ||
2557 | .capget = cap_capget, | 2579 | .capget = cap_capget, |
2558 | .capset_check = cap_capset_check, | 2580 | .capset_check = cap_capset_check, |
2559 | .capset_set = cap_capset_set, | 2581 | .capset_set = cap_capset_set, |
@@ -2730,4 +2752,3 @@ static __init int smack_init(void) | |||
2730 | * all processes and objects when they are created. | 2752 | * all processes and objects when they are created. |
2731 | */ | 2753 | */ |
2732 | security_initcall(smack_init); | 2754 | security_initcall(smack_init); |
2733 | |||
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 271a835fbbe3..c21d8c8bf0c7 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 | ||
@@ -343,9 +354,11 @@ static void smk_cipso_doi(void) | |||
343 | doip->tags[rc] = CIPSO_V4_TAG_INVALID; | 354 | doip->tags[rc] = CIPSO_V4_TAG_INVALID; |
344 | 355 | ||
345 | rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info); | 356 | rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info); |
346 | if (rc != 0) | 357 | if (rc != 0) { |
347 | printk(KERN_WARNING "%s:%d add rc = %d\n", | 358 | printk(KERN_WARNING "%s:%d add rc = %d\n", |
348 | __func__, __LINE__, rc); | 359 | __func__, __LINE__, rc); |
360 | kfree(doip); | ||
361 | } | ||
349 | } | 362 | } |
350 | 363 | ||
351 | /** | 364 | /** |
@@ -787,6 +800,85 @@ static const struct file_operations smk_ambient_ops = { | |||
787 | .write = smk_write_ambient, | 800 | .write = smk_write_ambient, |
788 | }; | 801 | }; |
789 | 802 | ||
803 | /** | ||
804 | * smk_read_onlycap - read() for /smack/onlycap | ||
805 | * @filp: file pointer, not actually used | ||
806 | * @buf: where to put the result | ||
807 | * @cn: maximum to send along | ||
808 | * @ppos: where to start | ||
809 | * | ||
810 | * Returns number of bytes read or error code, as appropriate | ||
811 | */ | ||
812 | static ssize_t smk_read_onlycap(struct file *filp, char __user *buf, | ||
813 | size_t cn, loff_t *ppos) | ||
814 | { | ||
815 | char *smack = ""; | ||
816 | ssize_t rc = -EINVAL; | ||
817 | int asize; | ||
818 | |||
819 | if (*ppos != 0) | ||
820 | return 0; | ||
821 | |||
822 | if (smack_onlycap != NULL) | ||
823 | smack = smack_onlycap; | ||
824 | |||
825 | asize = strlen(smack) + 1; | ||
826 | |||
827 | if (cn >= asize) | ||
828 | rc = simple_read_from_buffer(buf, cn, ppos, smack, asize); | ||
829 | |||
830 | return rc; | ||
831 | } | ||
832 | |||
833 | /** | ||
834 | * smk_write_onlycap - write() for /smack/onlycap | ||
835 | * @filp: file pointer, not actually used | ||
836 | * @buf: where to get the data from | ||
837 | * @count: bytes sent | ||
838 | * @ppos: where to start | ||
839 | * | ||
840 | * Returns number of bytes written or error code, as appropriate | ||
841 | */ | ||
842 | static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | ||
843 | size_t count, loff_t *ppos) | ||
844 | { | ||
845 | char in[SMK_LABELLEN]; | ||
846 | char *sp = current->security; | ||
847 | |||
848 | if (!capable(CAP_MAC_ADMIN)) | ||
849 | return -EPERM; | ||
850 | |||
851 | /* | ||
852 | * This can be done using smk_access() but is done | ||
853 | * explicitly for clarity. The smk_access() implementation | ||
854 | * would use smk_access(smack_onlycap, MAY_WRITE) | ||
855 | */ | ||
856 | if (smack_onlycap != NULL && smack_onlycap != sp) | ||
857 | return -EPERM; | ||
858 | |||
859 | if (count >= SMK_LABELLEN) | ||
860 | return -EINVAL; | ||
861 | |||
862 | if (copy_from_user(in, buf, count) != 0) | ||
863 | return -EFAULT; | ||
864 | |||
865 | /* | ||
866 | * Should the null string be passed in unset the onlycap value. | ||
867 | * This seems like something to be careful with as usually | ||
868 | * smk_import only expects to return NULL for errors. It | ||
869 | * is usually the case that a nullstring or "\n" would be | ||
870 | * bad to pass to smk_import but in fact this is useful here. | ||
871 | */ | ||
872 | smack_onlycap = smk_import(in, count); | ||
873 | |||
874 | return count; | ||
875 | } | ||
876 | |||
877 | static const struct file_operations smk_onlycap_ops = { | ||
878 | .read = smk_read_onlycap, | ||
879 | .write = smk_write_onlycap, | ||
880 | }; | ||
881 | |||
790 | struct option_names { | 882 | struct option_names { |
791 | int o_number; | 883 | int o_number; |
792 | char *o_name; | 884 | char *o_name; |
@@ -919,6 +1011,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
919 | {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, | 1011 | {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, |
920 | [SMK_NLTYPE] = | 1012 | [SMK_NLTYPE] = |
921 | {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR}, | 1013 | {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR}, |
1014 | [SMK_ONLYCAP] = | ||
1015 | {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, | ||
922 | /* last one */ {""} | 1016 | /* last one */ {""} |
923 | }; | 1017 | }; |
924 | 1018 | ||