diff options
author | James Morris <jmorris@namei.org> | 2010-02-28 17:36:31 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-02-28 17:36:31 -0500 |
commit | b4ccebdd37ff70d349321a198f416ba737a5e833 (patch) | |
tree | 275d717070346722c3aacd8355fb4f743216e03b | |
parent | 30ff056c42c665b9ea535d8515890857ae382540 (diff) | |
parent | ef57471a73b67a7b65fd8708fd55c77cb7c619af (diff) |
Merge branch 'next' into for-linus
30 files changed, 2030 insertions, 1708 deletions
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c index 7ca78346d3f0..cfe90a48a6e8 100644 --- a/fs/proc/kmsg.c +++ b/fs/proc/kmsg.c | |||
@@ -12,37 +12,37 @@ | |||
12 | #include <linux/poll.h> | 12 | #include <linux/poll.h> |
13 | #include <linux/proc_fs.h> | 13 | #include <linux/proc_fs.h> |
14 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
15 | #include <linux/syslog.h> | ||
15 | 16 | ||
16 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
17 | #include <asm/io.h> | 18 | #include <asm/io.h> |
18 | 19 | ||
19 | extern wait_queue_head_t log_wait; | 20 | extern wait_queue_head_t log_wait; |
20 | 21 | ||
21 | extern int do_syslog(int type, char __user *bug, int count); | ||
22 | |||
23 | static int kmsg_open(struct inode * inode, struct file * file) | 22 | static int kmsg_open(struct inode * inode, struct file * file) |
24 | { | 23 | { |
25 | return do_syslog(1,NULL,0); | 24 | return do_syslog(SYSLOG_ACTION_OPEN, NULL, 0, SYSLOG_FROM_FILE); |
26 | } | 25 | } |
27 | 26 | ||
28 | static int kmsg_release(struct inode * inode, struct file * file) | 27 | static int kmsg_release(struct inode * inode, struct file * file) |
29 | { | 28 | { |
30 | (void) do_syslog(0,NULL,0); | 29 | (void) do_syslog(SYSLOG_ACTION_CLOSE, NULL, 0, SYSLOG_FROM_FILE); |
31 | return 0; | 30 | return 0; |
32 | } | 31 | } |
33 | 32 | ||
34 | static ssize_t kmsg_read(struct file *file, char __user *buf, | 33 | static ssize_t kmsg_read(struct file *file, char __user *buf, |
35 | size_t count, loff_t *ppos) | 34 | size_t count, loff_t *ppos) |
36 | { | 35 | { |
37 | if ((file->f_flags & O_NONBLOCK) && !do_syslog(9, NULL, 0)) | 36 | if ((file->f_flags & O_NONBLOCK) && |
37 | !do_syslog(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0, SYSLOG_FROM_FILE)) | ||
38 | return -EAGAIN; | 38 | return -EAGAIN; |
39 | return do_syslog(2, buf, count); | 39 | return do_syslog(SYSLOG_ACTION_READ, buf, count, SYSLOG_FROM_FILE); |
40 | } | 40 | } |
41 | 41 | ||
42 | static unsigned int kmsg_poll(struct file *file, poll_table *wait) | 42 | static unsigned int kmsg_poll(struct file *file, poll_table *wait) |
43 | { | 43 | { |
44 | poll_wait(file, &log_wait, wait); | 44 | poll_wait(file, &log_wait, wait); |
45 | if (do_syslog(9, NULL, 0)) | 45 | if (do_syslog(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0, SYSLOG_FROM_FILE)) |
46 | return POLLIN | POLLRDNORM; | 46 | return POLLIN | POLLRDNORM; |
47 | return 0; | 47 | return 0; |
48 | } | 48 | } |
diff --git a/include/linux/security.h b/include/linux/security.h index 2c627d361c02..233d20b52c1b 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -76,7 +76,7 @@ extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
76 | extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp); | 76 | extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp); |
77 | extern int cap_task_setioprio(struct task_struct *p, int ioprio); | 77 | extern int cap_task_setioprio(struct task_struct *p, int ioprio); |
78 | extern int cap_task_setnice(struct task_struct *p, int nice); | 78 | extern int cap_task_setnice(struct task_struct *p, int nice); |
79 | extern int cap_syslog(int type); | 79 | extern int cap_syslog(int type, bool from_file); |
80 | extern int cap_vm_enough_memory(struct mm_struct *mm, long pages); | 80 | extern int cap_vm_enough_memory(struct mm_struct *mm, long pages); |
81 | 81 | ||
82 | struct msghdr; | 82 | struct msghdr; |
@@ -95,6 +95,8 @@ struct seq_file; | |||
95 | extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); | 95 | extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); |
96 | extern int cap_netlink_recv(struct sk_buff *skb, int cap); | 96 | extern int cap_netlink_recv(struct sk_buff *skb, int cap); |
97 | 97 | ||
98 | void reset_security_ops(void); | ||
99 | |||
98 | #ifdef CONFIG_MMU | 100 | #ifdef CONFIG_MMU |
99 | extern unsigned long mmap_min_addr; | 101 | extern unsigned long mmap_min_addr; |
100 | extern unsigned long dac_mmap_min_addr; | 102 | extern unsigned long dac_mmap_min_addr; |
@@ -985,6 +987,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
985 | * Check permissions on incoming network packets. This hook is distinct | 987 | * Check permissions on incoming network packets. This hook is distinct |
986 | * from Netfilter's IP input hooks since it is the first time that the | 988 | * from Netfilter's IP input hooks since it is the first time that the |
987 | * incoming sk_buff @skb has been associated with a particular socket, @sk. | 989 | * incoming sk_buff @skb has been associated with a particular socket, @sk. |
990 | * Must not sleep inside this hook because some callers hold spinlocks. | ||
988 | * @sk contains the sock (not socket) associated with the incoming sk_buff. | 991 | * @sk contains the sock (not socket) associated with the incoming sk_buff. |
989 | * @skb contains the incoming network data. | 992 | * @skb contains the incoming network data. |
990 | * @socket_getpeersec_stream: | 993 | * @socket_getpeersec_stream: |
@@ -1348,6 +1351,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
1348 | * logging to the console. | 1351 | * logging to the console. |
1349 | * See the syslog(2) manual page for an explanation of the @type values. | 1352 | * See the syslog(2) manual page for an explanation of the @type values. |
1350 | * @type contains the type of action. | 1353 | * @type contains the type of action. |
1354 | * @from_file indicates the context of action (if it came from /proc). | ||
1351 | * Return 0 if permission is granted. | 1355 | * Return 0 if permission is granted. |
1352 | * @settime: | 1356 | * @settime: |
1353 | * Check permission to change the system time. | 1357 | * Check permission to change the system time. |
@@ -1462,7 +1466,7 @@ struct security_operations { | |||
1462 | int (*sysctl) (struct ctl_table *table, int op); | 1466 | int (*sysctl) (struct ctl_table *table, int op); |
1463 | int (*quotactl) (int cmds, int type, int id, struct super_block *sb); | 1467 | int (*quotactl) (int cmds, int type, int id, struct super_block *sb); |
1464 | int (*quota_on) (struct dentry *dentry); | 1468 | int (*quota_on) (struct dentry *dentry); |
1465 | int (*syslog) (int type); | 1469 | int (*syslog) (int type, bool from_file); |
1466 | int (*settime) (struct timespec *ts, struct timezone *tz); | 1470 | int (*settime) (struct timespec *ts, struct timezone *tz); |
1467 | int (*vm_enough_memory) (struct mm_struct *mm, long pages); | 1471 | int (*vm_enough_memory) (struct mm_struct *mm, long pages); |
1468 | 1472 | ||
@@ -1761,7 +1765,7 @@ int security_acct(struct file *file); | |||
1761 | int security_sysctl(struct ctl_table *table, int op); | 1765 | int security_sysctl(struct ctl_table *table, int op); |
1762 | int security_quotactl(int cmds, int type, int id, struct super_block *sb); | 1766 | int security_quotactl(int cmds, int type, int id, struct super_block *sb); |
1763 | int security_quota_on(struct dentry *dentry); | 1767 | int security_quota_on(struct dentry *dentry); |
1764 | int security_syslog(int type); | 1768 | int security_syslog(int type, bool from_file); |
1765 | int security_settime(struct timespec *ts, struct timezone *tz); | 1769 | int security_settime(struct timespec *ts, struct timezone *tz); |
1766 | int security_vm_enough_memory(long pages); | 1770 | int security_vm_enough_memory(long pages); |
1767 | int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); | 1771 | int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); |
@@ -2007,9 +2011,9 @@ static inline int security_quota_on(struct dentry *dentry) | |||
2007 | return 0; | 2011 | return 0; |
2008 | } | 2012 | } |
2009 | 2013 | ||
2010 | static inline int security_syslog(int type) | 2014 | static inline int security_syslog(int type, bool from_file) |
2011 | { | 2015 | { |
2012 | return cap_syslog(type); | 2016 | return cap_syslog(type, from_file); |
2013 | } | 2017 | } |
2014 | 2018 | ||
2015 | static inline int security_settime(struct timespec *ts, struct timezone *tz) | 2019 | static inline int security_settime(struct timespec *ts, struct timezone *tz) |
diff --git a/include/linux/syslog.h b/include/linux/syslog.h new file mode 100644 index 000000000000..38911391a139 --- /dev/null +++ b/include/linux/syslog.h | |||
@@ -0,0 +1,52 @@ | |||
1 | /* Syslog internals | ||
2 | * | ||
3 | * Copyright 2010 Canonical, Ltd. | ||
4 | * Author: Kees Cook <kees.cook@canonical.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2, or (at your option) | ||
9 | * any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; see the file COPYING. If not, write to | ||
18 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef _LINUX_SYSLOG_H | ||
22 | #define _LINUX_SYSLOG_H | ||
23 | |||
24 | /* Close the log. Currently a NOP. */ | ||
25 | #define SYSLOG_ACTION_CLOSE 0 | ||
26 | /* Open the log. Currently a NOP. */ | ||
27 | #define SYSLOG_ACTION_OPEN 1 | ||
28 | /* Read from the log. */ | ||
29 | #define SYSLOG_ACTION_READ 2 | ||
30 | /* Read all messages remaining in the ring buffer. */ | ||
31 | #define SYSLOG_ACTION_READ_ALL 3 | ||
32 | /* Read and clear all messages remaining in the ring buffer */ | ||
33 | #define SYSLOG_ACTION_READ_CLEAR 4 | ||
34 | /* Clear ring buffer. */ | ||
35 | #define SYSLOG_ACTION_CLEAR 5 | ||
36 | /* Disable printk's to console */ | ||
37 | #define SYSLOG_ACTION_CONSOLE_OFF 6 | ||
38 | /* Enable printk's to console */ | ||
39 | #define SYSLOG_ACTION_CONSOLE_ON 7 | ||
40 | /* Set level of messages printed to console */ | ||
41 | #define SYSLOG_ACTION_CONSOLE_LEVEL 8 | ||
42 | /* Return number of unread characters in the log buffer */ | ||
43 | #define SYSLOG_ACTION_SIZE_UNREAD 9 | ||
44 | /* Return size of the log buffer */ | ||
45 | #define SYSLOG_ACTION_SIZE_BUFFER 10 | ||
46 | |||
47 | #define SYSLOG_FROM_CALL 0 | ||
48 | #define SYSLOG_FROM_FILE 1 | ||
49 | |||
50 | int do_syslog(int type, char __user *buf, int count, bool from_file); | ||
51 | |||
52 | #endif /* _LINUX_SYSLOG_H */ | ||
diff --git a/kernel/capability.c b/kernel/capability.c index 7f876e60521f..9e4697e9b276 100644 --- a/kernel/capability.c +++ b/kernel/capability.c | |||
@@ -135,7 +135,7 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, | |||
135 | if (pid && (pid != task_pid_vnr(current))) { | 135 | if (pid && (pid != task_pid_vnr(current))) { |
136 | struct task_struct *target; | 136 | struct task_struct *target; |
137 | 137 | ||
138 | read_lock(&tasklist_lock); | 138 | rcu_read_lock(); |
139 | 139 | ||
140 | target = find_task_by_vpid(pid); | 140 | target = find_task_by_vpid(pid); |
141 | if (!target) | 141 | if (!target) |
@@ -143,7 +143,7 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, | |||
143 | else | 143 | else |
144 | ret = security_capget(target, pEp, pIp, pPp); | 144 | ret = security_capget(target, pEp, pIp, pPp); |
145 | 145 | ||
146 | read_unlock(&tasklist_lock); | 146 | rcu_read_unlock(); |
147 | } else | 147 | } else |
148 | ret = security_capget(current, pEp, pIp, pPp); | 148 | ret = security_capget(current, pEp, pIp, pPp); |
149 | 149 | ||
diff --git a/kernel/printk.c b/kernel/printk.c index 1751c456b71f..40674122ecf2 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/kexec.h> | 35 | #include <linux/kexec.h> |
36 | #include <linux/ratelimit.h> | 36 | #include <linux/ratelimit.h> |
37 | #include <linux/kmsg_dump.h> | 37 | #include <linux/kmsg_dump.h> |
38 | #include <linux/syslog.h> | ||
38 | 39 | ||
39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
40 | 41 | ||
@@ -258,38 +259,23 @@ static inline void boot_delay_msec(void) | |||
258 | } | 259 | } |
259 | #endif | 260 | #endif |
260 | 261 | ||
261 | /* | 262 | int do_syslog(int type, char __user *buf, int len, bool from_file) |
262 | * Commands to do_syslog: | ||
263 | * | ||
264 | * 0 -- Close the log. Currently a NOP. | ||
265 | * 1 -- Open the log. Currently a NOP. | ||
266 | * 2 -- Read from the log. | ||
267 | * 3 -- Read all messages remaining in the ring buffer. | ||
268 | * 4 -- Read and clear all messages remaining in the ring buffer | ||
269 | * 5 -- Clear ring buffer. | ||
270 | * 6 -- Disable printk's to console | ||
271 | * 7 -- Enable printk's to console | ||
272 | * 8 -- Set level of messages printed to console | ||
273 | * 9 -- Return number of unread characters in the log buffer | ||
274 | * 10 -- Return size of the log buffer | ||
275 | */ | ||
276 | int do_syslog(int type, char __user *buf, int len) | ||
277 | { | 263 | { |
278 | unsigned i, j, limit, count; | 264 | unsigned i, j, limit, count; |
279 | int do_clear = 0; | 265 | int do_clear = 0; |
280 | char c; | 266 | char c; |
281 | int error = 0; | 267 | int error = 0; |
282 | 268 | ||
283 | error = security_syslog(type); | 269 | error = security_syslog(type, from_file); |
284 | if (error) | 270 | if (error) |
285 | return error; | 271 | return error; |
286 | 272 | ||
287 | switch (type) { | 273 | switch (type) { |
288 | case 0: /* Close log */ | 274 | case SYSLOG_ACTION_CLOSE: /* Close log */ |
289 | break; | 275 | break; |
290 | case 1: /* Open log */ | 276 | case SYSLOG_ACTION_OPEN: /* Open log */ |
291 | break; | 277 | break; |
292 | case 2: /* Read from log */ | 278 | case SYSLOG_ACTION_READ: /* Read from log */ |
293 | error = -EINVAL; | 279 | error = -EINVAL; |
294 | if (!buf || len < 0) | 280 | if (!buf || len < 0) |
295 | goto out; | 281 | goto out; |
@@ -320,10 +306,12 @@ int do_syslog(int type, char __user *buf, int len) | |||
320 | if (!error) | 306 | if (!error) |
321 | error = i; | 307 | error = i; |
322 | break; | 308 | break; |
323 | case 4: /* Read/clear last kernel messages */ | 309 | /* Read/clear last kernel messages */ |
310 | case SYSLOG_ACTION_READ_CLEAR: | ||
324 | do_clear = 1; | 311 | do_clear = 1; |
325 | /* FALL THRU */ | 312 | /* FALL THRU */ |
326 | case 3: /* Read last kernel messages */ | 313 | /* Read last kernel messages */ |
314 | case SYSLOG_ACTION_READ_ALL: | ||
327 | error = -EINVAL; | 315 | error = -EINVAL; |
328 | if (!buf || len < 0) | 316 | if (!buf || len < 0) |
329 | goto out; | 317 | goto out; |
@@ -376,21 +364,25 @@ int do_syslog(int type, char __user *buf, int len) | |||
376 | } | 364 | } |
377 | } | 365 | } |
378 | break; | 366 | break; |
379 | case 5: /* Clear ring buffer */ | 367 | /* Clear ring buffer */ |
368 | case SYSLOG_ACTION_CLEAR: | ||
380 | logged_chars = 0; | 369 | logged_chars = 0; |
381 | break; | 370 | break; |
382 | case 6: /* Disable logging to console */ | 371 | /* Disable logging to console */ |
372 | case SYSLOG_ACTION_CONSOLE_OFF: | ||
383 | if (saved_console_loglevel == -1) | 373 | if (saved_console_loglevel == -1) |
384 | saved_console_loglevel = console_loglevel; | 374 | saved_console_loglevel = console_loglevel; |
385 | console_loglevel = minimum_console_loglevel; | 375 | console_loglevel = minimum_console_loglevel; |
386 | break; | 376 | break; |
387 | case 7: /* Enable logging to console */ | 377 | /* Enable logging to console */ |
378 | case SYSLOG_ACTION_CONSOLE_ON: | ||
388 | if (saved_console_loglevel != -1) { | 379 | if (saved_console_loglevel != -1) { |
389 | console_loglevel = saved_console_loglevel; | 380 | console_loglevel = saved_console_loglevel; |
390 | saved_console_loglevel = -1; | 381 | saved_console_loglevel = -1; |
391 | } | 382 | } |
392 | break; | 383 | break; |
393 | case 8: /* Set level of messages printed to console */ | 384 | /* Set level of messages printed to console */ |
385 | case SYSLOG_ACTION_CONSOLE_LEVEL: | ||
394 | error = -EINVAL; | 386 | error = -EINVAL; |
395 | if (len < 1 || len > 8) | 387 | if (len < 1 || len > 8) |
396 | goto out; | 388 | goto out; |
@@ -401,10 +393,12 @@ int do_syslog(int type, char __user *buf, int len) | |||
401 | saved_console_loglevel = -1; | 393 | saved_console_loglevel = -1; |
402 | error = 0; | 394 | error = 0; |
403 | break; | 395 | break; |
404 | case 9: /* Number of chars in the log buffer */ | 396 | /* Number of chars in the log buffer */ |
397 | case SYSLOG_ACTION_SIZE_UNREAD: | ||
405 | error = log_end - log_start; | 398 | error = log_end - log_start; |
406 | break; | 399 | break; |
407 | case 10: /* Size of the log buffer */ | 400 | /* Size of the log buffer */ |
401 | case SYSLOG_ACTION_SIZE_BUFFER: | ||
408 | error = log_buf_len; | 402 | error = log_buf_len; |
409 | break; | 403 | break; |
410 | default: | 404 | default: |
@@ -417,7 +411,7 @@ out: | |||
417 | 411 | ||
418 | SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) | 412 | SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) |
419 | { | 413 | { |
420 | return do_syslog(type, buf, len); | 414 | return do_syslog(type, buf, len, SYSLOG_FROM_CALL); |
421 | } | 415 | } |
422 | 416 | ||
423 | /* | 417 | /* |
diff --git a/security/capability.c b/security/capability.c index 5c700e1a4fd3..4875142b858d 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -906,10 +906,6 @@ static void cap_audit_rule_free(void *lsmrule) | |||
906 | } | 906 | } |
907 | #endif /* CONFIG_AUDIT */ | 907 | #endif /* CONFIG_AUDIT */ |
908 | 908 | ||
909 | struct security_operations default_security_ops = { | ||
910 | .name = "default", | ||
911 | }; | ||
912 | |||
913 | #define set_to_cap_if_null(ops, function) \ | 909 | #define set_to_cap_if_null(ops, function) \ |
914 | do { \ | 910 | do { \ |
915 | if (!ops->function) { \ | 911 | if (!ops->function) { \ |
diff --git a/security/commoncap.c b/security/commoncap.c index f800fdb3de94..61669730da98 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/sched.h> | 27 | #include <linux/sched.h> |
28 | #include <linux/prctl.h> | 28 | #include <linux/prctl.h> |
29 | #include <linux/securebits.h> | 29 | #include <linux/securebits.h> |
30 | #include <linux/syslog.h> | ||
30 | 31 | ||
31 | /* | 32 | /* |
32 | * If a non-root user executes a setuid-root binary in | 33 | * If a non-root user executes a setuid-root binary in |
@@ -888,13 +889,17 @@ error: | |||
888 | /** | 889 | /** |
889 | * cap_syslog - Determine whether syslog function is permitted | 890 | * cap_syslog - Determine whether syslog function is permitted |
890 | * @type: Function requested | 891 | * @type: Function requested |
892 | * @from_file: Whether this request came from an open file (i.e. /proc) | ||
891 | * | 893 | * |
892 | * Determine whether the current process is permitted to use a particular | 894 | * Determine whether the current process is permitted to use a particular |
893 | * syslog function, returning 0 if permission is granted, -ve if not. | 895 | * syslog function, returning 0 if permission is granted, -ve if not. |
894 | */ | 896 | */ |
895 | int cap_syslog(int type) | 897 | int cap_syslog(int type, bool from_file) |
896 | { | 898 | { |
897 | if ((type != 3 && type != 10) && !capable(CAP_SYS_ADMIN)) | 899 | if (type != SYSLOG_ACTION_OPEN && from_file) |
900 | return 0; | ||
901 | if ((type != SYSLOG_ACTION_READ_ALL && | ||
902 | type != SYSLOG_ACTION_SIZE_BUFFER) && !capable(CAP_SYS_ADMIN)) | ||
898 | return -EPERM; | 903 | return -EPERM; |
899 | return 0; | 904 | return 0; |
900 | } | 905 | } |
diff --git a/security/security.c b/security/security.c index 122b748d0f4c..687c6fd14bb6 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -23,10 +23,12 @@ static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = | |||
23 | CONFIG_DEFAULT_SECURITY; | 23 | CONFIG_DEFAULT_SECURITY; |
24 | 24 | ||
25 | /* things that live in capability.c */ | 25 | /* things that live in capability.c */ |
26 | extern struct security_operations default_security_ops; | ||
27 | extern void security_fixup_ops(struct security_operations *ops); | 26 | extern void security_fixup_ops(struct security_operations *ops); |
28 | 27 | ||
29 | struct security_operations *security_ops; /* Initialized to NULL */ | 28 | static struct security_operations *security_ops; |
29 | static struct security_operations default_security_ops = { | ||
30 | .name = "default", | ||
31 | }; | ||
30 | 32 | ||
31 | static inline int verify(struct security_operations *ops) | 33 | static inline int verify(struct security_operations *ops) |
32 | { | 34 | { |
@@ -63,6 +65,11 @@ int __init security_init(void) | |||
63 | return 0; | 65 | return 0; |
64 | } | 66 | } |
65 | 67 | ||
68 | void reset_security_ops(void) | ||
69 | { | ||
70 | security_ops = &default_security_ops; | ||
71 | } | ||
72 | |||
66 | /* Save user chosen LSM */ | 73 | /* Save user chosen LSM */ |
67 | static int __init choose_lsm(char *str) | 74 | static int __init choose_lsm(char *str) |
68 | { | 75 | { |
@@ -203,9 +210,9 @@ int security_quota_on(struct dentry *dentry) | |||
203 | return security_ops->quota_on(dentry); | 210 | return security_ops->quota_on(dentry); |
204 | } | 211 | } |
205 | 212 | ||
206 | int security_syslog(int type) | 213 | int security_syslog(int type, bool from_file) |
207 | { | 214 | { |
208 | return security_ops->syslog(type); | 215 | return security_ops->syslog(type, from_file); |
209 | } | 216 | } |
210 | 217 | ||
211 | int security_settime(struct timespec *ts, struct timezone *tz) | 218 | int security_settime(struct timespec *ts, struct timezone *tz) |
@@ -389,42 +396,42 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, | |||
389 | EXPORT_SYMBOL(security_inode_init_security); | 396 | EXPORT_SYMBOL(security_inode_init_security); |
390 | 397 | ||
391 | #ifdef CONFIG_SECURITY_PATH | 398 | #ifdef CONFIG_SECURITY_PATH |
392 | int security_path_mknod(struct path *path, struct dentry *dentry, int mode, | 399 | int security_path_mknod(struct path *dir, struct dentry *dentry, int mode, |
393 | unsigned int dev) | 400 | unsigned int dev) |
394 | { | 401 | { |
395 | if (unlikely(IS_PRIVATE(path->dentry->d_inode))) | 402 | if (unlikely(IS_PRIVATE(dir->dentry->d_inode))) |
396 | return 0; | 403 | return 0; |
397 | return security_ops->path_mknod(path, dentry, mode, dev); | 404 | return security_ops->path_mknod(dir, dentry, mode, dev); |
398 | } | 405 | } |
399 | EXPORT_SYMBOL(security_path_mknod); | 406 | EXPORT_SYMBOL(security_path_mknod); |
400 | 407 | ||
401 | int security_path_mkdir(struct path *path, struct dentry *dentry, int mode) | 408 | int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode) |
402 | { | 409 | { |
403 | if (unlikely(IS_PRIVATE(path->dentry->d_inode))) | 410 | if (unlikely(IS_PRIVATE(dir->dentry->d_inode))) |
404 | return 0; | 411 | return 0; |
405 | return security_ops->path_mkdir(path, dentry, mode); | 412 | return security_ops->path_mkdir(dir, dentry, mode); |
406 | } | 413 | } |
407 | 414 | ||
408 | int security_path_rmdir(struct path *path, struct dentry *dentry) | 415 | int security_path_rmdir(struct path *dir, struct dentry *dentry) |
409 | { | 416 | { |
410 | if (unlikely(IS_PRIVATE(path->dentry->d_inode))) | 417 | if (unlikely(IS_PRIVATE(dir->dentry->d_inode))) |
411 | return 0; | 418 | return 0; |
412 | return security_ops->path_rmdir(path, dentry); | 419 | return security_ops->path_rmdir(dir, dentry); |
413 | } | 420 | } |
414 | 421 | ||
415 | int security_path_unlink(struct path *path, struct dentry *dentry) | 422 | int security_path_unlink(struct path *dir, struct dentry *dentry) |
416 | { | 423 | { |
417 | if (unlikely(IS_PRIVATE(path->dentry->d_inode))) | 424 | if (unlikely(IS_PRIVATE(dir->dentry->d_inode))) |
418 | return 0; | 425 | return 0; |
419 | return security_ops->path_unlink(path, dentry); | 426 | return security_ops->path_unlink(dir, dentry); |
420 | } | 427 | } |
421 | 428 | ||
422 | int security_path_symlink(struct path *path, struct dentry *dentry, | 429 | int security_path_symlink(struct path *dir, struct dentry *dentry, |
423 | const char *old_name) | 430 | const char *old_name) |
424 | { | 431 | { |
425 | if (unlikely(IS_PRIVATE(path->dentry->d_inode))) | 432 | if (unlikely(IS_PRIVATE(dir->dentry->d_inode))) |
426 | return 0; | 433 | return 0; |
427 | return security_ops->path_symlink(path, dentry, old_name); | 434 | return security_ops->path_symlink(dir, dentry, old_name); |
428 | } | 435 | } |
429 | 436 | ||
430 | int security_path_link(struct dentry *old_dentry, struct path *new_dir, | 437 | int security_path_link(struct dentry *old_dentry, struct path *new_dir, |
@@ -630,14 +637,14 @@ int security_inode_killpriv(struct dentry *dentry) | |||
630 | int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc) | 637 | int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc) |
631 | { | 638 | { |
632 | if (unlikely(IS_PRIVATE(inode))) | 639 | if (unlikely(IS_PRIVATE(inode))) |
633 | return 0; | 640 | return -EOPNOTSUPP; |
634 | return security_ops->inode_getsecurity(inode, name, buffer, alloc); | 641 | return security_ops->inode_getsecurity(inode, name, buffer, alloc); |
635 | } | 642 | } |
636 | 643 | ||
637 | int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags) | 644 | int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags) |
638 | { | 645 | { |
639 | if (unlikely(IS_PRIVATE(inode))) | 646 | if (unlikely(IS_PRIVATE(inode))) |
640 | return 0; | 647 | return -EOPNOTSUPP; |
641 | return security_ops->inode_setsecurity(inode, name, value, size, flags); | 648 | return security_ops->inode_setsecurity(inode, name, value, size, flags); |
642 | } | 649 | } |
643 | 650 | ||
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index f2dde268165a..db0fd9f33499 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -489,17 +489,14 @@ void avc_audit(u32 ssid, u32 tsid, | |||
489 | struct common_audit_data stack_data; | 489 | struct common_audit_data stack_data; |
490 | u32 denied, audited; | 490 | u32 denied, audited; |
491 | denied = requested & ~avd->allowed; | 491 | denied = requested & ~avd->allowed; |
492 | if (denied) { | 492 | if (denied) |
493 | audited = denied; | 493 | audited = denied & avd->auditdeny; |
494 | if (!(audited & avd->auditdeny)) | 494 | else if (result) |
495 | return; | ||
496 | } else if (result) { | ||
497 | audited = denied = requested; | 495 | audited = denied = requested; |
498 | } else { | 496 | else |
499 | audited = requested; | 497 | audited = requested & avd->auditallow; |
500 | if (!(audited & avd->auditallow)) | 498 | if (!audited) |
501 | return; | 499 | return; |
502 | } | ||
503 | if (!a) { | 500 | if (!a) { |
504 | a = &stack_data; | 501 | a = &stack_data; |
505 | memset(a, 0, sizeof(*a)); | 502 | memset(a, 0, sizeof(*a)); |
@@ -746,9 +743,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
746 | else | 743 | else |
747 | avd = &avd_entry; | 744 | avd = &avd_entry; |
748 | 745 | ||
749 | rc = security_compute_av(ssid, tsid, tclass, requested, avd); | 746 | security_compute_av(ssid, tsid, tclass, avd); |
750 | if (rc) | ||
751 | goto out; | ||
752 | rcu_read_lock(); | 747 | rcu_read_lock(); |
753 | node = avc_insert(ssid, tsid, tclass, avd); | 748 | node = avc_insert(ssid, tsid, tclass, avd); |
754 | } else { | 749 | } else { |
@@ -770,7 +765,6 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
770 | } | 765 | } |
771 | 766 | ||
772 | rcu_read_unlock(); | 767 | rcu_read_unlock(); |
773 | out: | ||
774 | return rc; | 768 | return rc; |
775 | } | 769 | } |
776 | 770 | ||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 9a2ee845e9d4..5feecb41009d 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -76,6 +76,7 @@ | |||
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 | #include <linux/posix-timers.h> |
79 | #include <linux/syslog.h> | ||
79 | 80 | ||
80 | #include "avc.h" | 81 | #include "avc.h" |
81 | #include "objsec.h" | 82 | #include "objsec.h" |
@@ -125,13 +126,6 @@ __setup("selinux=", selinux_enabled_setup); | |||
125 | int selinux_enabled = 1; | 126 | int selinux_enabled = 1; |
126 | #endif | 127 | #endif |
127 | 128 | ||
128 | |||
129 | /* | ||
130 | * Minimal support for a secondary security module, | ||
131 | * just to allow the use of the capability module. | ||
132 | */ | ||
133 | static struct security_operations *secondary_ops; | ||
134 | |||
135 | /* Lists of inode and superblock security structures initialized | 129 | /* Lists of inode and superblock security structures initialized |
136 | before the policy was loaded. */ | 130 | before the policy was loaded. */ |
137 | static LIST_HEAD(superblock_security_head); | 131 | static LIST_HEAD(superblock_security_head); |
@@ -2049,29 +2043,30 @@ static int selinux_quota_on(struct dentry *dentry) | |||
2049 | return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON); | 2043 | return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON); |
2050 | } | 2044 | } |
2051 | 2045 | ||
2052 | static int selinux_syslog(int type) | 2046 | static int selinux_syslog(int type, bool from_file) |
2053 | { | 2047 | { |
2054 | int rc; | 2048 | int rc; |
2055 | 2049 | ||
2056 | rc = cap_syslog(type); | 2050 | rc = cap_syslog(type, from_file); |
2057 | if (rc) | 2051 | if (rc) |
2058 | return rc; | 2052 | return rc; |
2059 | 2053 | ||
2060 | switch (type) { | 2054 | switch (type) { |
2061 | case 3: /* Read last kernel messages */ | 2055 | case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */ |
2062 | case 10: /* Return size of the log buffer */ | 2056 | case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */ |
2063 | rc = task_has_system(current, SYSTEM__SYSLOG_READ); | 2057 | rc = task_has_system(current, SYSTEM__SYSLOG_READ); |
2064 | break; | 2058 | break; |
2065 | case 6: /* Disable logging to console */ | 2059 | case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */ |
2066 | case 7: /* Enable logging to console */ | 2060 | case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */ |
2067 | case 8: /* Set level of messages printed to console */ | 2061 | /* Set level of messages printed to console */ |
2062 | case SYSLOG_ACTION_CONSOLE_LEVEL: | ||
2068 | rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE); | 2063 | rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE); |
2069 | break; | 2064 | break; |
2070 | case 0: /* Close log */ | 2065 | case SYSLOG_ACTION_CLOSE: /* Close log */ |
2071 | case 1: /* Open log */ | 2066 | case SYSLOG_ACTION_OPEN: /* Open log */ |
2072 | case 2: /* Read from log */ | 2067 | case SYSLOG_ACTION_READ: /* Read from log */ |
2073 | case 4: /* Read/clear last kernel messages */ | 2068 | case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */ |
2074 | case 5: /* Clear ring buffer */ | 2069 | case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */ |
2075 | default: | 2070 | default: |
2076 | rc = task_has_system(current, SYSTEM__SYSLOG_MOD); | 2071 | rc = task_has_system(current, SYSTEM__SYSLOG_MOD); |
2077 | break; | 2072 | break; |
@@ -3334,7 +3329,7 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) | |||
3334 | 3329 | ||
3335 | if (ret == 0) | 3330 | if (ret == 0) |
3336 | tsec->create_sid = isec->sid; | 3331 | tsec->create_sid = isec->sid; |
3337 | return 0; | 3332 | return ret; |
3338 | } | 3333 | } |
3339 | 3334 | ||
3340 | static int selinux_kernel_module_request(char *kmod_name) | 3335 | static int selinux_kernel_module_request(char *kmod_name) |
@@ -5672,9 +5667,6 @@ static __init int selinux_init(void) | |||
5672 | 0, SLAB_PANIC, NULL); | 5667 | 0, SLAB_PANIC, NULL); |
5673 | avc_init(); | 5668 | avc_init(); |
5674 | 5669 | ||
5675 | secondary_ops = security_ops; | ||
5676 | if (!secondary_ops) | ||
5677 | panic("SELinux: No initial security operations\n"); | ||
5678 | if (register_security(&selinux_ops)) | 5670 | if (register_security(&selinux_ops)) |
5679 | panic("SELinux: Unable to register with kernel.\n"); | 5671 | panic("SELinux: Unable to register with kernel.\n"); |
5680 | 5672 | ||
@@ -5835,8 +5827,7 @@ int selinux_disable(void) | |||
5835 | selinux_disabled = 1; | 5827 | selinux_disabled = 1; |
5836 | selinux_enabled = 0; | 5828 | selinux_enabled = 0; |
5837 | 5829 | ||
5838 | /* Reset security_ops to the secondary module, dummy or capability. */ | 5830 | reset_security_ops(); |
5839 | security_ops = secondary_ops; | ||
5840 | 5831 | ||
5841 | /* Try to destroy the avc node cache */ | 5832 | /* Try to destroy the avc node cache */ |
5842 | avc_disable(); | 5833 | avc_disable(); |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 2553266ad793..1f7c2491d3dc 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -57,7 +57,6 @@ | |||
57 | struct netlbl_lsm_secattr; | 57 | struct netlbl_lsm_secattr; |
58 | 58 | ||
59 | extern int selinux_enabled; | 59 | extern int selinux_enabled; |
60 | extern int selinux_mls_enabled; | ||
61 | 60 | ||
62 | /* Policy capabilities */ | 61 | /* Policy capabilities */ |
63 | enum { | 62 | enum { |
@@ -80,6 +79,8 @@ extern int selinux_policycap_openperm; | |||
80 | /* limitation of boundary depth */ | 79 | /* limitation of boundary depth */ |
81 | #define POLICYDB_BOUNDS_MAXDEPTH 4 | 80 | #define POLICYDB_BOUNDS_MAXDEPTH 4 |
82 | 81 | ||
82 | int security_mls_enabled(void); | ||
83 | |||
83 | int security_load_policy(void *data, size_t len); | 84 | int security_load_policy(void *data, size_t len); |
84 | 85 | ||
85 | int security_policycap_supported(unsigned int req_cap); | 86 | int security_policycap_supported(unsigned int req_cap); |
@@ -96,13 +97,11 @@ struct av_decision { | |||
96 | /* definitions of av_decision.flags */ | 97 | /* definitions of av_decision.flags */ |
97 | #define AVD_FLAGS_PERMISSIVE 0x0001 | 98 | #define AVD_FLAGS_PERMISSIVE 0x0001 |
98 | 99 | ||
99 | int security_compute_av(u32 ssid, u32 tsid, | 100 | void security_compute_av(u32 ssid, u32 tsid, |
100 | u16 tclass, u32 requested, | 101 | u16 tclass, struct av_decision *avd); |
101 | struct av_decision *avd); | ||
102 | 102 | ||
103 | int security_compute_av_user(u32 ssid, u32 tsid, | 103 | void security_compute_av_user(u32 ssid, u32 tsid, |
104 | u16 tclass, u32 requested, | 104 | u16 tclass, struct av_decision *avd); |
105 | struct av_decision *avd); | ||
106 | 105 | ||
107 | int security_transition_sid(u32 ssid, u32 tsid, | 106 | int security_transition_sid(u32 ssid, u32 tsid, |
108 | u16 tclass, u32 *out_sid); | 107 | u16 tclass, u32 *out_sid); |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index fab36fdf2769..cd191bbec03c 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -282,7 +282,8 @@ static ssize_t sel_read_mls(struct file *filp, char __user *buf, | |||
282 | char tmpbuf[TMPBUFLEN]; | 282 | char tmpbuf[TMPBUFLEN]; |
283 | ssize_t length; | 283 | ssize_t length; |
284 | 284 | ||
285 | length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_mls_enabled); | 285 | length = scnprintf(tmpbuf, TMPBUFLEN, "%d", |
286 | security_mls_enabled()); | ||
286 | return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); | 287 | return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); |
287 | } | 288 | } |
288 | 289 | ||
@@ -494,7 +495,6 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
494 | char *scon, *tcon; | 495 | char *scon, *tcon; |
495 | u32 ssid, tsid; | 496 | u32 ssid, tsid; |
496 | u16 tclass; | 497 | u16 tclass; |
497 | u32 req; | ||
498 | struct av_decision avd; | 498 | struct av_decision avd; |
499 | ssize_t length; | 499 | ssize_t length; |
500 | 500 | ||
@@ -512,7 +512,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
512 | goto out; | 512 | goto out; |
513 | 513 | ||
514 | length = -EINVAL; | 514 | length = -EINVAL; |
515 | if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4) | 515 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) |
516 | goto out2; | 516 | goto out2; |
517 | 517 | ||
518 | length = security_context_to_sid(scon, strlen(scon)+1, &ssid); | 518 | length = security_context_to_sid(scon, strlen(scon)+1, &ssid); |
@@ -522,9 +522,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
522 | if (length < 0) | 522 | if (length < 0) |
523 | goto out2; | 523 | goto out2; |
524 | 524 | ||
525 | length = security_compute_av_user(ssid, tsid, tclass, req, &avd); | 525 | security_compute_av_user(ssid, tsid, tclass, &avd); |
526 | if (length < 0) | ||
527 | goto out2; | ||
528 | 526 | ||
529 | length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, | 527 | length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, |
530 | "%x %x %x %x %u %x", | 528 | "%x %x %x %x %u %x", |
@@ -979,6 +977,8 @@ static int sel_make_bools(void) | |||
979 | u32 sid; | 977 | u32 sid; |
980 | 978 | ||
981 | /* remove any existing files */ | 979 | /* remove any existing files */ |
980 | for (i = 0; i < bool_num; i++) | ||
981 | kfree(bool_pending_names[i]); | ||
982 | kfree(bool_pending_names); | 982 | kfree(bool_pending_names); |
983 | kfree(bool_pending_values); | 983 | kfree(bool_pending_values); |
984 | bool_pending_names = NULL; | 984 | bool_pending_names = NULL; |
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index d9dd7a2f6a8a..45e8fb0515f8 100644 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h | |||
@@ -41,9 +41,6 @@ static inline int mls_context_cpy(struct context *dst, struct context *src) | |||
41 | { | 41 | { |
42 | int rc; | 42 | int rc; |
43 | 43 | ||
44 | if (!selinux_mls_enabled) | ||
45 | return 0; | ||
46 | |||
47 | dst->range.level[0].sens = src->range.level[0].sens; | 44 | dst->range.level[0].sens = src->range.level[0].sens; |
48 | rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); | 45 | rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); |
49 | if (rc) | 46 | if (rc) |
@@ -64,9 +61,6 @@ static inline int mls_context_cpy_low(struct context *dst, struct context *src) | |||
64 | { | 61 | { |
65 | int rc; | 62 | int rc; |
66 | 63 | ||
67 | if (!selinux_mls_enabled) | ||
68 | return 0; | ||
69 | |||
70 | dst->range.level[0].sens = src->range.level[0].sens; | 64 | dst->range.level[0].sens = src->range.level[0].sens; |
71 | rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); | 65 | rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); |
72 | if (rc) | 66 | if (rc) |
@@ -82,9 +76,6 @@ out: | |||
82 | 76 | ||
83 | static inline int mls_context_cmp(struct context *c1, struct context *c2) | 77 | static inline int mls_context_cmp(struct context *c1, struct context *c2) |
84 | { | 78 | { |
85 | if (!selinux_mls_enabled) | ||
86 | return 1; | ||
87 | |||
88 | return ((c1->range.level[0].sens == c2->range.level[0].sens) && | 79 | return ((c1->range.level[0].sens == c2->range.level[0].sens) && |
89 | ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) && | 80 | ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) && |
90 | (c1->range.level[1].sens == c2->range.level[1].sens) && | 81 | (c1->range.level[1].sens == c2->range.level[1].sens) && |
@@ -93,9 +84,6 @@ static inline int mls_context_cmp(struct context *c1, struct context *c2) | |||
93 | 84 | ||
94 | static inline void mls_context_destroy(struct context *c) | 85 | static inline void mls_context_destroy(struct context *c) |
95 | { | 86 | { |
96 | if (!selinux_mls_enabled) | ||
97 | return; | ||
98 | |||
99 | ebitmap_destroy(&c->range.level[0].cat); | 87 | ebitmap_destroy(&c->range.level[0].cat); |
100 | ebitmap_destroy(&c->range.level[1].cat); | 88 | ebitmap_destroy(&c->range.level[1].cat); |
101 | mls_context_init(c); | 89 | mls_context_init(c); |
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 3f2b2706b5bb..372b773f8210 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c | |||
@@ -39,7 +39,7 @@ int mls_compute_context_len(struct context *context) | |||
39 | struct ebitmap *e; | 39 | struct ebitmap *e; |
40 | struct ebitmap_node *node; | 40 | struct ebitmap_node *node; |
41 | 41 | ||
42 | if (!selinux_mls_enabled) | 42 | if (!policydb.mls_enabled) |
43 | return 0; | 43 | return 0; |
44 | 44 | ||
45 | len = 1; /* for the beginning ":" */ | 45 | len = 1; /* for the beginning ":" */ |
@@ -93,7 +93,7 @@ void mls_sid_to_context(struct context *context, | |||
93 | struct ebitmap *e; | 93 | struct ebitmap *e; |
94 | struct ebitmap_node *node; | 94 | struct ebitmap_node *node; |
95 | 95 | ||
96 | if (!selinux_mls_enabled) | 96 | if (!policydb.mls_enabled) |
97 | return; | 97 | return; |
98 | 98 | ||
99 | scontextp = *scontext; | 99 | scontextp = *scontext; |
@@ -200,7 +200,7 @@ int mls_context_isvalid(struct policydb *p, struct context *c) | |||
200 | { | 200 | { |
201 | struct user_datum *usrdatum; | 201 | struct user_datum *usrdatum; |
202 | 202 | ||
203 | if (!selinux_mls_enabled) | 203 | if (!p->mls_enabled) |
204 | return 1; | 204 | return 1; |
205 | 205 | ||
206 | if (!mls_range_isvalid(p, &c->range)) | 206 | if (!mls_range_isvalid(p, &c->range)) |
@@ -253,7 +253,7 @@ int mls_context_to_sid(struct policydb *pol, | |||
253 | struct cat_datum *catdatum, *rngdatum; | 253 | struct cat_datum *catdatum, *rngdatum; |
254 | int l, rc = -EINVAL; | 254 | int l, rc = -EINVAL; |
255 | 255 | ||
256 | if (!selinux_mls_enabled) { | 256 | if (!pol->mls_enabled) { |
257 | if (def_sid != SECSID_NULL && oldc) | 257 | if (def_sid != SECSID_NULL && oldc) |
258 | *scontext += strlen(*scontext)+1; | 258 | *scontext += strlen(*scontext)+1; |
259 | return 0; | 259 | return 0; |
@@ -387,7 +387,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) | |||
387 | char *tmpstr, *freestr; | 387 | char *tmpstr, *freestr; |
388 | int rc; | 388 | int rc; |
389 | 389 | ||
390 | if (!selinux_mls_enabled) | 390 | if (!policydb.mls_enabled) |
391 | return -EINVAL; | 391 | return -EINVAL; |
392 | 392 | ||
393 | /* we need freestr because mls_context_to_sid will change | 393 | /* we need freestr because mls_context_to_sid will change |
@@ -407,7 +407,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) | |||
407 | /* | 407 | /* |
408 | * Copies the MLS range `range' into `context'. | 408 | * Copies the MLS range `range' into `context'. |
409 | */ | 409 | */ |
410 | static inline int mls_range_set(struct context *context, | 410 | int mls_range_set(struct context *context, |
411 | struct mls_range *range) | 411 | struct mls_range *range) |
412 | { | 412 | { |
413 | int l, rc = 0; | 413 | int l, rc = 0; |
@@ -427,7 +427,7 @@ static inline int mls_range_set(struct context *context, | |||
427 | int mls_setup_user_range(struct context *fromcon, struct user_datum *user, | 427 | int mls_setup_user_range(struct context *fromcon, struct user_datum *user, |
428 | struct context *usercon) | 428 | struct context *usercon) |
429 | { | 429 | { |
430 | if (selinux_mls_enabled) { | 430 | if (policydb.mls_enabled) { |
431 | struct mls_level *fromcon_sen = &(fromcon->range.level[0]); | 431 | struct mls_level *fromcon_sen = &(fromcon->range.level[0]); |
432 | struct mls_level *fromcon_clr = &(fromcon->range.level[1]); | 432 | struct mls_level *fromcon_clr = &(fromcon->range.level[1]); |
433 | struct mls_level *user_low = &(user->range.level[0]); | 433 | struct mls_level *user_low = &(user->range.level[0]); |
@@ -477,7 +477,7 @@ int mls_convert_context(struct policydb *oldp, | |||
477 | struct ebitmap_node *node; | 477 | struct ebitmap_node *node; |
478 | int l, i; | 478 | int l, i; |
479 | 479 | ||
480 | if (!selinux_mls_enabled) | 480 | if (!policydb.mls_enabled) |
481 | return 0; | 481 | return 0; |
482 | 482 | ||
483 | for (l = 0; l < 2; l++) { | 483 | for (l = 0; l < 2; l++) { |
@@ -513,23 +513,21 @@ int mls_compute_sid(struct context *scontext, | |||
513 | u32 specified, | 513 | u32 specified, |
514 | struct context *newcontext) | 514 | struct context *newcontext) |
515 | { | 515 | { |
516 | struct range_trans *rtr; | 516 | struct range_trans rtr; |
517 | struct mls_range *r; | ||
517 | 518 | ||
518 | if (!selinux_mls_enabled) | 519 | if (!policydb.mls_enabled) |
519 | return 0; | 520 | return 0; |
520 | 521 | ||
521 | switch (specified) { | 522 | switch (specified) { |
522 | case AVTAB_TRANSITION: | 523 | case AVTAB_TRANSITION: |
523 | /* Look for a range transition rule. */ | 524 | /* Look for a range transition rule. */ |
524 | for (rtr = policydb.range_tr; rtr; rtr = rtr->next) { | 525 | rtr.source_type = scontext->type; |
525 | if (rtr->source_type == scontext->type && | 526 | rtr.target_type = tcontext->type; |
526 | rtr->target_type == tcontext->type && | 527 | rtr.target_class = tclass; |
527 | rtr->target_class == tclass) { | 528 | r = hashtab_search(policydb.range_tr, &rtr); |
528 | /* Set the range from the rule */ | 529 | if (r) |
529 | return mls_range_set(newcontext, | 530 | return mls_range_set(newcontext, r); |
530 | &rtr->target_range); | ||
531 | } | ||
532 | } | ||
533 | /* Fallthrough */ | 531 | /* Fallthrough */ |
534 | case AVTAB_CHANGE: | 532 | case AVTAB_CHANGE: |
535 | if (tclass == policydb.process_class) | 533 | if (tclass == policydb.process_class) |
@@ -541,8 +539,8 @@ int mls_compute_sid(struct context *scontext, | |||
541 | case AVTAB_MEMBER: | 539 | case AVTAB_MEMBER: |
542 | /* Use the process effective MLS attributes. */ | 540 | /* Use the process effective MLS attributes. */ |
543 | return mls_context_cpy_low(newcontext, scontext); | 541 | return mls_context_cpy_low(newcontext, scontext); |
544 | default: | 542 | |
545 | return -EINVAL; | 543 | /* fall through */ |
546 | } | 544 | } |
547 | return -EINVAL; | 545 | return -EINVAL; |
548 | } | 546 | } |
@@ -561,7 +559,7 @@ int mls_compute_sid(struct context *scontext, | |||
561 | void mls_export_netlbl_lvl(struct context *context, | 559 | void mls_export_netlbl_lvl(struct context *context, |
562 | struct netlbl_lsm_secattr *secattr) | 560 | struct netlbl_lsm_secattr *secattr) |
563 | { | 561 | { |
564 | if (!selinux_mls_enabled) | 562 | if (!policydb.mls_enabled) |
565 | return; | 563 | return; |
566 | 564 | ||
567 | secattr->attr.mls.lvl = context->range.level[0].sens - 1; | 565 | secattr->attr.mls.lvl = context->range.level[0].sens - 1; |
@@ -581,7 +579,7 @@ void mls_export_netlbl_lvl(struct context *context, | |||
581 | void mls_import_netlbl_lvl(struct context *context, | 579 | void mls_import_netlbl_lvl(struct context *context, |
582 | struct netlbl_lsm_secattr *secattr) | 580 | struct netlbl_lsm_secattr *secattr) |
583 | { | 581 | { |
584 | if (!selinux_mls_enabled) | 582 | if (!policydb.mls_enabled) |
585 | return; | 583 | return; |
586 | 584 | ||
587 | context->range.level[0].sens = secattr->attr.mls.lvl + 1; | 585 | context->range.level[0].sens = secattr->attr.mls.lvl + 1; |
@@ -603,7 +601,7 @@ int mls_export_netlbl_cat(struct context *context, | |||
603 | { | 601 | { |
604 | int rc; | 602 | int rc; |
605 | 603 | ||
606 | if (!selinux_mls_enabled) | 604 | if (!policydb.mls_enabled) |
607 | return 0; | 605 | return 0; |
608 | 606 | ||
609 | rc = ebitmap_netlbl_export(&context->range.level[0].cat, | 607 | rc = ebitmap_netlbl_export(&context->range.level[0].cat, |
@@ -631,7 +629,7 @@ int mls_import_netlbl_cat(struct context *context, | |||
631 | { | 629 | { |
632 | int rc; | 630 | int rc; |
633 | 631 | ||
634 | if (!selinux_mls_enabled) | 632 | if (!policydb.mls_enabled) |
635 | return 0; | 633 | return 0; |
636 | 634 | ||
637 | rc = ebitmap_netlbl_import(&context->range.level[0].cat, | 635 | rc = ebitmap_netlbl_import(&context->range.level[0].cat, |
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index 1276715aaa8b..cd9152632e54 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h | |||
@@ -39,6 +39,8 @@ int mls_context_to_sid(struct policydb *p, | |||
39 | 39 | ||
40 | int mls_from_string(char *str, struct context *context, gfp_t gfp_mask); | 40 | int mls_from_string(char *str, struct context *context, gfp_t gfp_mask); |
41 | 41 | ||
42 | int mls_range_set(struct context *context, struct mls_range *range); | ||
43 | |||
42 | int mls_convert_context(struct policydb *oldp, | 44 | int mls_convert_context(struct policydb *oldp, |
43 | struct policydb *newp, | 45 | struct policydb *newp, |
44 | struct context *context); | 46 | struct context *context); |
diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h index b6e943a21061..03bed52a8052 100644 --- a/security/selinux/ss/mls_types.h +++ b/security/selinux/ss/mls_types.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #define _SS_MLS_TYPES_H_ | 15 | #define _SS_MLS_TYPES_H_ |
16 | 16 | ||
17 | #include "security.h" | 17 | #include "security.h" |
18 | #include "ebitmap.h" | ||
18 | 19 | ||
19 | struct mls_level { | 20 | struct mls_level { |
20 | u32 sens; /* sensitivity */ | 21 | u32 sens; /* sensitivity */ |
@@ -27,18 +28,12 @@ struct mls_range { | |||
27 | 28 | ||
28 | static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2) | 29 | static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2) |
29 | { | 30 | { |
30 | if (!selinux_mls_enabled) | ||
31 | return 1; | ||
32 | |||
33 | return ((l1->sens == l2->sens) && | 31 | return ((l1->sens == l2->sens) && |
34 | ebitmap_cmp(&l1->cat, &l2->cat)); | 32 | ebitmap_cmp(&l1->cat, &l2->cat)); |
35 | } | 33 | } |
36 | 34 | ||
37 | static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2) | 35 | static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2) |
38 | { | 36 | { |
39 | if (!selinux_mls_enabled) | ||
40 | return 1; | ||
41 | |||
42 | return ((l1->sens >= l2->sens) && | 37 | return ((l1->sens >= l2->sens) && |
43 | ebitmap_contains(&l1->cat, &l2->cat)); | 38 | ebitmap_contains(&l1->cat, &l2->cat)); |
44 | } | 39 | } |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index f03667213ea8..23c6e53c102c 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -52,8 +52,6 @@ static char *symtab_name[SYM_NUM] = { | |||
52 | }; | 52 | }; |
53 | #endif | 53 | #endif |
54 | 54 | ||
55 | int selinux_mls_enabled; | ||
56 | |||
57 | static unsigned int symtab_sizes[SYM_NUM] = { | 55 | static unsigned int symtab_sizes[SYM_NUM] = { |
58 | 2, | 56 | 2, |
59 | 32, | 57 | 32, |
@@ -177,6 +175,21 @@ out_free_role: | |||
177 | goto out; | 175 | goto out; |
178 | } | 176 | } |
179 | 177 | ||
178 | static u32 rangetr_hash(struct hashtab *h, const void *k) | ||
179 | { | ||
180 | const struct range_trans *key = k; | ||
181 | return (key->source_type + (key->target_type << 3) + | ||
182 | (key->target_class << 5)) & (h->size - 1); | ||
183 | } | ||
184 | |||
185 | static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2) | ||
186 | { | ||
187 | const struct range_trans *key1 = k1, *key2 = k2; | ||
188 | return (key1->source_type != key2->source_type || | ||
189 | key1->target_type != key2->target_type || | ||
190 | key1->target_class != key2->target_class); | ||
191 | } | ||
192 | |||
180 | /* | 193 | /* |
181 | * Initialize a policy database structure. | 194 | * Initialize a policy database structure. |
182 | */ | 195 | */ |
@@ -204,6 +217,10 @@ static int policydb_init(struct policydb *p) | |||
204 | if (rc) | 217 | if (rc) |
205 | goto out_free_symtab; | 218 | goto out_free_symtab; |
206 | 219 | ||
220 | p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); | ||
221 | if (!p->range_tr) | ||
222 | goto out_free_symtab; | ||
223 | |||
207 | ebitmap_init(&p->policycaps); | 224 | ebitmap_init(&p->policycaps); |
208 | ebitmap_init(&p->permissive_map); | 225 | ebitmap_init(&p->permissive_map); |
209 | 226 | ||
@@ -408,6 +425,20 @@ static void symtab_hash_eval(struct symtab *s) | |||
408 | info.slots_used, h->size, info.max_chain_len); | 425 | info.slots_used, h->size, info.max_chain_len); |
409 | } | 426 | } |
410 | } | 427 | } |
428 | |||
429 | static void rangetr_hash_eval(struct hashtab *h) | ||
430 | { | ||
431 | struct hashtab_info info; | ||
432 | |||
433 | hashtab_stat(h, &info); | ||
434 | printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, " | ||
435 | "longest chain length %d\n", h->nel, | ||
436 | info.slots_used, h->size, info.max_chain_len); | ||
437 | } | ||
438 | #else | ||
439 | static inline void rangetr_hash_eval(struct hashtab *h) | ||
440 | { | ||
441 | } | ||
411 | #endif | 442 | #endif |
412 | 443 | ||
413 | /* | 444 | /* |
@@ -422,7 +453,7 @@ static int policydb_index_others(struct policydb *p) | |||
422 | 453 | ||
423 | printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools", | 454 | printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools", |
424 | p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); | 455 | p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); |
425 | if (selinux_mls_enabled) | 456 | if (p->mls_enabled) |
426 | printk(", %d sens, %d cats", p->p_levels.nprim, | 457 | printk(", %d sens, %d cats", p->p_levels.nprim, |
427 | p->p_cats.nprim); | 458 | p->p_cats.nprim); |
428 | printk("\n"); | 459 | printk("\n"); |
@@ -612,6 +643,17 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = | |||
612 | cat_destroy, | 643 | cat_destroy, |
613 | }; | 644 | }; |
614 | 645 | ||
646 | static int range_tr_destroy(void *key, void *datum, void *p) | ||
647 | { | ||
648 | struct mls_range *rt = datum; | ||
649 | kfree(key); | ||
650 | ebitmap_destroy(&rt->level[0].cat); | ||
651 | ebitmap_destroy(&rt->level[1].cat); | ||
652 | kfree(datum); | ||
653 | cond_resched(); | ||
654 | return 0; | ||
655 | } | ||
656 | |||
615 | static void ocontext_destroy(struct ocontext *c, int i) | 657 | static void ocontext_destroy(struct ocontext *c, int i) |
616 | { | 658 | { |
617 | context_destroy(&c->context[0]); | 659 | context_destroy(&c->context[0]); |
@@ -632,7 +674,6 @@ void policydb_destroy(struct policydb *p) | |||
632 | int i; | 674 | int i; |
633 | struct role_allow *ra, *lra = NULL; | 675 | struct role_allow *ra, *lra = NULL; |
634 | struct role_trans *tr, *ltr = NULL; | 676 | struct role_trans *tr, *ltr = NULL; |
635 | struct range_trans *rt, *lrt = NULL; | ||
636 | 677 | ||
637 | for (i = 0; i < SYM_NUM; i++) { | 678 | for (i = 0; i < SYM_NUM; i++) { |
638 | cond_resched(); | 679 | cond_resched(); |
@@ -693,20 +734,8 @@ void policydb_destroy(struct policydb *p) | |||
693 | } | 734 | } |
694 | kfree(lra); | 735 | kfree(lra); |
695 | 736 | ||
696 | for (rt = p->range_tr; rt; rt = rt->next) { | 737 | hashtab_map(p->range_tr, range_tr_destroy, NULL); |
697 | cond_resched(); | 738 | hashtab_destroy(p->range_tr); |
698 | if (lrt) { | ||
699 | ebitmap_destroy(&lrt->target_range.level[0].cat); | ||
700 | ebitmap_destroy(&lrt->target_range.level[1].cat); | ||
701 | kfree(lrt); | ||
702 | } | ||
703 | lrt = rt; | ||
704 | } | ||
705 | if (lrt) { | ||
706 | ebitmap_destroy(&lrt->target_range.level[0].cat); | ||
707 | ebitmap_destroy(&lrt->target_range.level[1].cat); | ||
708 | kfree(lrt); | ||
709 | } | ||
710 | 739 | ||
711 | if (p->type_attr_map) { | 740 | if (p->type_attr_map) { |
712 | for (i = 0; i < p->p_types.nprim; i++) | 741 | for (i = 0; i < p->p_types.nprim; i++) |
@@ -1686,12 +1715,11 @@ int policydb_read(struct policydb *p, void *fp) | |||
1686 | int i, j, rc; | 1715 | int i, j, rc; |
1687 | __le32 buf[4]; | 1716 | __le32 buf[4]; |
1688 | u32 nodebuf[8]; | 1717 | u32 nodebuf[8]; |
1689 | u32 len, len2, config, nprim, nel, nel2; | 1718 | u32 len, len2, nprim, nel, nel2; |
1690 | char *policydb_str; | 1719 | char *policydb_str; |
1691 | struct policydb_compat_info *info; | 1720 | struct policydb_compat_info *info; |
1692 | struct range_trans *rt, *lrt; | 1721 | struct range_trans *rt; |
1693 | 1722 | struct mls_range *r; | |
1694 | config = 0; | ||
1695 | 1723 | ||
1696 | rc = policydb_init(p); | 1724 | rc = policydb_init(p); |
1697 | if (rc) | 1725 | if (rc) |
@@ -1740,7 +1768,7 @@ int policydb_read(struct policydb *p, void *fp) | |||
1740 | kfree(policydb_str); | 1768 | kfree(policydb_str); |
1741 | policydb_str = NULL; | 1769 | policydb_str = NULL; |
1742 | 1770 | ||
1743 | /* Read the version, config, and table sizes. */ | 1771 | /* Read the version and table sizes. */ |
1744 | rc = next_entry(buf, fp, sizeof(u32)*4); | 1772 | rc = next_entry(buf, fp, sizeof(u32)*4); |
1745 | if (rc < 0) | 1773 | if (rc < 0) |
1746 | goto bad; | 1774 | goto bad; |
@@ -1755,13 +1783,7 @@ int policydb_read(struct policydb *p, void *fp) | |||
1755 | } | 1783 | } |
1756 | 1784 | ||
1757 | if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) { | 1785 | if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) { |
1758 | if (ss_initialized && !selinux_mls_enabled) { | 1786 | p->mls_enabled = 1; |
1759 | printk(KERN_ERR "SELinux: Cannot switch between non-MLS" | ||
1760 | " and MLS policies\n"); | ||
1761 | goto bad; | ||
1762 | } | ||
1763 | selinux_mls_enabled = 1; | ||
1764 | config |= POLICYDB_CONFIG_MLS; | ||
1765 | 1787 | ||
1766 | if (p->policyvers < POLICYDB_VERSION_MLS) { | 1788 | if (p->policyvers < POLICYDB_VERSION_MLS) { |
1767 | printk(KERN_ERR "SELinux: security policydb version %d " | 1789 | printk(KERN_ERR "SELinux: security policydb version %d " |
@@ -1769,12 +1791,6 @@ int policydb_read(struct policydb *p, void *fp) | |||
1769 | p->policyvers); | 1791 | p->policyvers); |
1770 | goto bad; | 1792 | goto bad; |
1771 | } | 1793 | } |
1772 | } else { | ||
1773 | if (ss_initialized && selinux_mls_enabled) { | ||
1774 | printk(KERN_ERR "SELinux: Cannot switch between MLS and" | ||
1775 | " non-MLS policies\n"); | ||
1776 | goto bad; | ||
1777 | } | ||
1778 | } | 1794 | } |
1779 | p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); | 1795 | p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); |
1780 | p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); | 1796 | p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); |
@@ -2122,44 +2138,61 @@ int policydb_read(struct policydb *p, void *fp) | |||
2122 | if (rc < 0) | 2138 | if (rc < 0) |
2123 | goto bad; | 2139 | goto bad; |
2124 | nel = le32_to_cpu(buf[0]); | 2140 | nel = le32_to_cpu(buf[0]); |
2125 | lrt = NULL; | ||
2126 | for (i = 0; i < nel; i++) { | 2141 | for (i = 0; i < nel; i++) { |
2127 | rt = kzalloc(sizeof(*rt), GFP_KERNEL); | 2142 | rt = kzalloc(sizeof(*rt), GFP_KERNEL); |
2128 | if (!rt) { | 2143 | if (!rt) { |
2129 | rc = -ENOMEM; | 2144 | rc = -ENOMEM; |
2130 | goto bad; | 2145 | goto bad; |
2131 | } | 2146 | } |
2132 | if (lrt) | ||
2133 | lrt->next = rt; | ||
2134 | else | ||
2135 | p->range_tr = rt; | ||
2136 | rc = next_entry(buf, fp, (sizeof(u32) * 2)); | 2147 | rc = next_entry(buf, fp, (sizeof(u32) * 2)); |
2137 | if (rc < 0) | 2148 | if (rc < 0) { |
2149 | kfree(rt); | ||
2138 | goto bad; | 2150 | goto bad; |
2151 | } | ||
2139 | rt->source_type = le32_to_cpu(buf[0]); | 2152 | rt->source_type = le32_to_cpu(buf[0]); |
2140 | rt->target_type = le32_to_cpu(buf[1]); | 2153 | rt->target_type = le32_to_cpu(buf[1]); |
2141 | if (new_rangetr) { | 2154 | if (new_rangetr) { |
2142 | rc = next_entry(buf, fp, sizeof(u32)); | 2155 | rc = next_entry(buf, fp, sizeof(u32)); |
2143 | if (rc < 0) | 2156 | if (rc < 0) { |
2157 | kfree(rt); | ||
2144 | goto bad; | 2158 | goto bad; |
2159 | } | ||
2145 | rt->target_class = le32_to_cpu(buf[0]); | 2160 | rt->target_class = le32_to_cpu(buf[0]); |
2146 | } else | 2161 | } else |
2147 | rt->target_class = p->process_class; | 2162 | rt->target_class = p->process_class; |
2148 | if (!policydb_type_isvalid(p, rt->source_type) || | 2163 | if (!policydb_type_isvalid(p, rt->source_type) || |
2149 | !policydb_type_isvalid(p, rt->target_type) || | 2164 | !policydb_type_isvalid(p, rt->target_type) || |
2150 | !policydb_class_isvalid(p, rt->target_class)) { | 2165 | !policydb_class_isvalid(p, rt->target_class)) { |
2166 | kfree(rt); | ||
2151 | rc = -EINVAL; | 2167 | rc = -EINVAL; |
2152 | goto bad; | 2168 | goto bad; |
2153 | } | 2169 | } |
2154 | rc = mls_read_range_helper(&rt->target_range, fp); | 2170 | r = kzalloc(sizeof(*r), GFP_KERNEL); |
2155 | if (rc) | 2171 | if (!r) { |
2172 | kfree(rt); | ||
2173 | rc = -ENOMEM; | ||
2156 | goto bad; | 2174 | goto bad; |
2157 | if (!mls_range_isvalid(p, &rt->target_range)) { | 2175 | } |
2176 | rc = mls_read_range_helper(r, fp); | ||
2177 | if (rc) { | ||
2178 | kfree(rt); | ||
2179 | kfree(r); | ||
2180 | goto bad; | ||
2181 | } | ||
2182 | if (!mls_range_isvalid(p, r)) { | ||
2158 | printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); | 2183 | printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); |
2184 | kfree(rt); | ||
2185 | kfree(r); | ||
2186 | goto bad; | ||
2187 | } | ||
2188 | rc = hashtab_insert(p->range_tr, rt, r); | ||
2189 | if (rc) { | ||
2190 | kfree(rt); | ||
2191 | kfree(r); | ||
2159 | goto bad; | 2192 | goto bad; |
2160 | } | 2193 | } |
2161 | lrt = rt; | ||
2162 | } | 2194 | } |
2195 | rangetr_hash_eval(p->range_tr); | ||
2163 | } | 2196 | } |
2164 | 2197 | ||
2165 | p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); | 2198 | p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); |
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index cdcc5700946f..26d9adf8542b 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
@@ -27,6 +27,8 @@ | |||
27 | #include "symtab.h" | 27 | #include "symtab.h" |
28 | #include "avtab.h" | 28 | #include "avtab.h" |
29 | #include "sidtab.h" | 29 | #include "sidtab.h" |
30 | #include "ebitmap.h" | ||
31 | #include "mls_types.h" | ||
30 | #include "context.h" | 32 | #include "context.h" |
31 | #include "constraint.h" | 33 | #include "constraint.h" |
32 | 34 | ||
@@ -113,8 +115,6 @@ struct range_trans { | |||
113 | u32 source_type; | 115 | u32 source_type; |
114 | u32 target_type; | 116 | u32 target_type; |
115 | u32 target_class; | 117 | u32 target_class; |
116 | struct mls_range target_range; | ||
117 | struct range_trans *next; | ||
118 | }; | 118 | }; |
119 | 119 | ||
120 | /* Boolean data type */ | 120 | /* Boolean data type */ |
@@ -187,6 +187,8 @@ struct genfs { | |||
187 | 187 | ||
188 | /* The policy database */ | 188 | /* The policy database */ |
189 | struct policydb { | 189 | struct policydb { |
190 | int mls_enabled; | ||
191 | |||
190 | /* symbol tables */ | 192 | /* symbol tables */ |
191 | struct symtab symtab[SYM_NUM]; | 193 | struct symtab symtab[SYM_NUM]; |
192 | #define p_commons symtab[SYM_COMMONS] | 194 | #define p_commons symtab[SYM_COMMONS] |
@@ -240,8 +242,8 @@ struct policydb { | |||
240 | fixed labeling behavior. */ | 242 | fixed labeling behavior. */ |
241 | struct genfs *genfs; | 243 | struct genfs *genfs; |
242 | 244 | ||
243 | /* range transitions */ | 245 | /* range transitions table (range_trans_key -> mls_range) */ |
244 | struct range_trans *range_tr; | 246 | struct hashtab *range_tr; |
245 | 247 | ||
246 | /* type -> attribute reverse mapping */ | 248 | /* type -> attribute reverse mapping */ |
247 | struct ebitmap *type_attr_map; | 249 | struct ebitmap *type_attr_map; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index b3efae204ac7..cf27b3ee1a95 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -26,6 +26,10 @@ | |||
26 | * | 26 | * |
27 | * Added support for bounds domain and audit messaged on masked permissions | 27 | * Added support for bounds domain and audit messaged on masked permissions |
28 | * | 28 | * |
29 | * Updated: Guido Trentalancia <guido@trentalancia.com> | ||
30 | * | ||
31 | * Added support for runtime switching of the policy type | ||
32 | * | ||
29 | * Copyright (C) 2008, 2009 NEC Corporation | 33 | * Copyright (C) 2008, 2009 NEC Corporation |
30 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. | 34 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. |
31 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. | 35 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. |
@@ -87,11 +91,10 @@ static u32 latest_granting; | |||
87 | static int context_struct_to_string(struct context *context, char **scontext, | 91 | static int context_struct_to_string(struct context *context, char **scontext, |
88 | u32 *scontext_len); | 92 | u32 *scontext_len); |
89 | 93 | ||
90 | static int context_struct_compute_av(struct context *scontext, | 94 | static void context_struct_compute_av(struct context *scontext, |
91 | struct context *tcontext, | 95 | struct context *tcontext, |
92 | u16 tclass, | 96 | u16 tclass, |
93 | u32 requested, | 97 | struct av_decision *avd); |
94 | struct av_decision *avd); | ||
95 | 98 | ||
96 | struct selinux_mapping { | 99 | struct selinux_mapping { |
97 | u16 value; /* policy value */ | 100 | u16 value; /* policy value */ |
@@ -196,23 +199,6 @@ static u16 unmap_class(u16 tclass) | |||
196 | return tclass; | 199 | return tclass; |
197 | } | 200 | } |
198 | 201 | ||
199 | static u32 unmap_perm(u16 tclass, u32 tperm) | ||
200 | { | ||
201 | if (tclass < current_mapping_size) { | ||
202 | unsigned i; | ||
203 | u32 kperm = 0; | ||
204 | |||
205 | for (i = 0; i < current_mapping[tclass].num_perms; i++) | ||
206 | if (tperm & (1<<i)) { | ||
207 | kperm |= current_mapping[tclass].perms[i]; | ||
208 | tperm &= ~(1<<i); | ||
209 | } | ||
210 | return kperm; | ||
211 | } | ||
212 | |||
213 | return tperm; | ||
214 | } | ||
215 | |||
216 | static void map_decision(u16 tclass, struct av_decision *avd, | 202 | static void map_decision(u16 tclass, struct av_decision *avd, |
217 | int allow_unknown) | 203 | int allow_unknown) |
218 | { | 204 | { |
@@ -250,6 +236,10 @@ static void map_decision(u16 tclass, struct av_decision *avd, | |||
250 | } | 236 | } |
251 | } | 237 | } |
252 | 238 | ||
239 | int security_mls_enabled(void) | ||
240 | { | ||
241 | return policydb.mls_enabled; | ||
242 | } | ||
253 | 243 | ||
254 | /* | 244 | /* |
255 | * Return the boolean value of a constraint expression | 245 | * Return the boolean value of a constraint expression |
@@ -465,7 +455,8 @@ static void security_dump_masked_av(struct context *scontext, | |||
465 | char *scontext_name = NULL; | 455 | char *scontext_name = NULL; |
466 | char *tcontext_name = NULL; | 456 | char *tcontext_name = NULL; |
467 | char *permission_names[32]; | 457 | char *permission_names[32]; |
468 | int index, length; | 458 | int index; |
459 | u32 length; | ||
469 | bool need_comma = false; | 460 | bool need_comma = false; |
470 | 461 | ||
471 | if (!permissions) | 462 | if (!permissions) |
@@ -532,7 +523,6 @@ out: | |||
532 | static void type_attribute_bounds_av(struct context *scontext, | 523 | static void type_attribute_bounds_av(struct context *scontext, |
533 | struct context *tcontext, | 524 | struct context *tcontext, |
534 | u16 tclass, | 525 | u16 tclass, |
535 | u32 requested, | ||
536 | struct av_decision *avd) | 526 | struct av_decision *avd) |
537 | { | 527 | { |
538 | struct context lo_scontext; | 528 | struct context lo_scontext; |
@@ -553,7 +543,6 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
553 | context_struct_compute_av(&lo_scontext, | 543 | context_struct_compute_av(&lo_scontext, |
554 | tcontext, | 544 | tcontext, |
555 | tclass, | 545 | tclass, |
556 | requested, | ||
557 | &lo_avd); | 546 | &lo_avd); |
558 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 547 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
559 | return; /* no masked permission */ | 548 | return; /* no masked permission */ |
@@ -569,7 +558,6 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
569 | context_struct_compute_av(scontext, | 558 | context_struct_compute_av(scontext, |
570 | &lo_tcontext, | 559 | &lo_tcontext, |
571 | tclass, | 560 | tclass, |
572 | requested, | ||
573 | &lo_avd); | 561 | &lo_avd); |
574 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 562 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
575 | return; /* no masked permission */ | 563 | return; /* no masked permission */ |
@@ -586,7 +574,6 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
586 | context_struct_compute_av(&lo_scontext, | 574 | context_struct_compute_av(&lo_scontext, |
587 | &lo_tcontext, | 575 | &lo_tcontext, |
588 | tclass, | 576 | tclass, |
589 | requested, | ||
590 | &lo_avd); | 577 | &lo_avd); |
591 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 578 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
592 | return; /* no masked permission */ | 579 | return; /* no masked permission */ |
@@ -607,11 +594,10 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
607 | * Compute access vectors based on a context structure pair for | 594 | * Compute access vectors based on a context structure pair for |
608 | * the permissions in a particular class. | 595 | * the permissions in a particular class. |
609 | */ | 596 | */ |
610 | static int context_struct_compute_av(struct context *scontext, | 597 | static void context_struct_compute_av(struct context *scontext, |
611 | struct context *tcontext, | 598 | struct context *tcontext, |
612 | u16 tclass, | 599 | u16 tclass, |
613 | u32 requested, | 600 | struct av_decision *avd) |
614 | struct av_decision *avd) | ||
615 | { | 601 | { |
616 | struct constraint_node *constraint; | 602 | struct constraint_node *constraint; |
617 | struct role_allow *ra; | 603 | struct role_allow *ra; |
@@ -622,19 +608,14 @@ static int context_struct_compute_av(struct context *scontext, | |||
622 | struct ebitmap_node *snode, *tnode; | 608 | struct ebitmap_node *snode, *tnode; |
623 | unsigned int i, j; | 609 | unsigned int i, j; |
624 | 610 | ||
625 | /* | ||
626 | * Initialize the access vectors to the default values. | ||
627 | */ | ||
628 | avd->allowed = 0; | 611 | avd->allowed = 0; |
629 | avd->auditallow = 0; | 612 | avd->auditallow = 0; |
630 | avd->auditdeny = 0xffffffff; | 613 | avd->auditdeny = 0xffffffff; |
631 | avd->seqno = latest_granting; | ||
632 | avd->flags = 0; | ||
633 | 614 | ||
634 | if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { | 615 | if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { |
635 | if (printk_ratelimit()) | 616 | if (printk_ratelimit()) |
636 | printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass); | 617 | printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass); |
637 | return -EINVAL; | 618 | return; |
638 | } | 619 | } |
639 | 620 | ||
640 | tclass_datum = policydb.class_val_to_struct[tclass - 1]; | 621 | tclass_datum = policydb.class_val_to_struct[tclass - 1]; |
@@ -705,9 +686,7 @@ static int context_struct_compute_av(struct context *scontext, | |||
705 | * permission and notice it to userspace via audit. | 686 | * permission and notice it to userspace via audit. |
706 | */ | 687 | */ |
707 | type_attribute_bounds_av(scontext, tcontext, | 688 | type_attribute_bounds_av(scontext, tcontext, |
708 | tclass, requested, avd); | 689 | tclass, avd); |
709 | |||
710 | return 0; | ||
711 | } | 690 | } |
712 | 691 | ||
713 | static int security_validtrans_handle_fail(struct context *ocontext, | 692 | static int security_validtrans_handle_fail(struct context *ocontext, |
@@ -864,7 +843,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) | |||
864 | if (rc) { | 843 | if (rc) { |
865 | char *old_name = NULL; | 844 | char *old_name = NULL; |
866 | char *new_name = NULL; | 845 | char *new_name = NULL; |
867 | int length; | 846 | u32 length; |
868 | 847 | ||
869 | if (!context_struct_to_string(old_context, | 848 | if (!context_struct_to_string(old_context, |
870 | &old_name, &length) && | 849 | &old_name, &length) && |
@@ -886,110 +865,116 @@ out: | |||
886 | return rc; | 865 | return rc; |
887 | } | 866 | } |
888 | 867 | ||
889 | 868 | static void avd_init(struct av_decision *avd) | |
890 | static int security_compute_av_core(u32 ssid, | ||
891 | u32 tsid, | ||
892 | u16 tclass, | ||
893 | u32 requested, | ||
894 | struct av_decision *avd) | ||
895 | { | 869 | { |
896 | struct context *scontext = NULL, *tcontext = NULL; | 870 | avd->allowed = 0; |
897 | int rc = 0; | 871 | avd->auditallow = 0; |
898 | 872 | avd->auditdeny = 0xffffffff; | |
899 | scontext = sidtab_search(&sidtab, ssid); | 873 | avd->seqno = latest_granting; |
900 | if (!scontext) { | 874 | avd->flags = 0; |
901 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
902 | __func__, ssid); | ||
903 | return -EINVAL; | ||
904 | } | ||
905 | tcontext = sidtab_search(&sidtab, tsid); | ||
906 | if (!tcontext) { | ||
907 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
908 | __func__, tsid); | ||
909 | return -EINVAL; | ||
910 | } | ||
911 | |||
912 | rc = context_struct_compute_av(scontext, tcontext, tclass, | ||
913 | requested, avd); | ||
914 | |||
915 | /* permissive domain? */ | ||
916 | if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) | ||
917 | avd->flags |= AVD_FLAGS_PERMISSIVE; | ||
918 | |||
919 | return rc; | ||
920 | } | 875 | } |
921 | 876 | ||
877 | |||
922 | /** | 878 | /** |
923 | * security_compute_av - Compute access vector decisions. | 879 | * security_compute_av - Compute access vector decisions. |
924 | * @ssid: source security identifier | 880 | * @ssid: source security identifier |
925 | * @tsid: target security identifier | 881 | * @tsid: target security identifier |
926 | * @tclass: target security class | 882 | * @tclass: target security class |
927 | * @requested: requested permissions | ||
928 | * @avd: access vector decisions | 883 | * @avd: access vector decisions |
929 | * | 884 | * |
930 | * Compute a set of access vector decisions based on the | 885 | * Compute a set of access vector decisions based on the |
931 | * SID pair (@ssid, @tsid) for the permissions in @tclass. | 886 | * SID pair (@ssid, @tsid) for the permissions in @tclass. |
932 | * Return -%EINVAL if any of the parameters are invalid or %0 | ||
933 | * if the access vector decisions were computed successfully. | ||
934 | */ | 887 | */ |
935 | int security_compute_av(u32 ssid, | 888 | void security_compute_av(u32 ssid, |
936 | u32 tsid, | 889 | u32 tsid, |
937 | u16 orig_tclass, | 890 | u16 orig_tclass, |
938 | u32 orig_requested, | 891 | struct av_decision *avd) |
939 | struct av_decision *avd) | ||
940 | { | 892 | { |
941 | u16 tclass; | 893 | u16 tclass; |
942 | u32 requested; | 894 | struct context *scontext = NULL, *tcontext = NULL; |
943 | int rc; | ||
944 | 895 | ||
945 | read_lock(&policy_rwlock); | 896 | read_lock(&policy_rwlock); |
946 | 897 | avd_init(avd); | |
947 | if (!ss_initialized) | 898 | if (!ss_initialized) |
948 | goto allow; | 899 | goto allow; |
949 | 900 | ||
950 | requested = unmap_perm(orig_tclass, orig_requested); | 901 | scontext = sidtab_search(&sidtab, ssid); |
902 | if (!scontext) { | ||
903 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
904 | __func__, ssid); | ||
905 | goto out; | ||
906 | } | ||
907 | |||
908 | /* permissive domain? */ | ||
909 | if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) | ||
910 | avd->flags |= AVD_FLAGS_PERMISSIVE; | ||
911 | |||
912 | tcontext = sidtab_search(&sidtab, tsid); | ||
913 | if (!tcontext) { | ||
914 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
915 | __func__, tsid); | ||
916 | goto out; | ||
917 | } | ||
918 | |||
951 | tclass = unmap_class(orig_tclass); | 919 | tclass = unmap_class(orig_tclass); |
952 | if (unlikely(orig_tclass && !tclass)) { | 920 | if (unlikely(orig_tclass && !tclass)) { |
953 | if (policydb.allow_unknown) | 921 | if (policydb.allow_unknown) |
954 | goto allow; | 922 | goto allow; |
955 | rc = -EINVAL; | ||
956 | goto out; | 923 | goto out; |
957 | } | 924 | } |
958 | rc = security_compute_av_core(ssid, tsid, tclass, requested, avd); | 925 | context_struct_compute_av(scontext, tcontext, tclass, avd); |
959 | map_decision(orig_tclass, avd, policydb.allow_unknown); | 926 | map_decision(orig_tclass, avd, policydb.allow_unknown); |
960 | out: | 927 | out: |
961 | read_unlock(&policy_rwlock); | 928 | read_unlock(&policy_rwlock); |
962 | return rc; | 929 | return; |
963 | allow: | 930 | allow: |
964 | avd->allowed = 0xffffffff; | 931 | avd->allowed = 0xffffffff; |
965 | avd->auditallow = 0; | ||
966 | avd->auditdeny = 0xffffffff; | ||
967 | avd->seqno = latest_granting; | ||
968 | avd->flags = 0; | ||
969 | rc = 0; | ||
970 | goto out; | 932 | goto out; |
971 | } | 933 | } |
972 | 934 | ||
973 | int security_compute_av_user(u32 ssid, | 935 | void security_compute_av_user(u32 ssid, |
974 | u32 tsid, | 936 | u32 tsid, |
975 | u16 tclass, | 937 | u16 tclass, |
976 | u32 requested, | 938 | struct av_decision *avd) |
977 | struct av_decision *avd) | ||
978 | { | 939 | { |
979 | int rc; | 940 | struct context *scontext = NULL, *tcontext = NULL; |
980 | 941 | ||
981 | if (!ss_initialized) { | 942 | read_lock(&policy_rwlock); |
982 | avd->allowed = 0xffffffff; | 943 | avd_init(avd); |
983 | avd->auditallow = 0; | 944 | if (!ss_initialized) |
984 | avd->auditdeny = 0xffffffff; | 945 | goto allow; |
985 | avd->seqno = latest_granting; | 946 | |
986 | return 0; | 947 | scontext = sidtab_search(&sidtab, ssid); |
948 | if (!scontext) { | ||
949 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
950 | __func__, ssid); | ||
951 | goto out; | ||
987 | } | 952 | } |
988 | 953 | ||
989 | read_lock(&policy_rwlock); | 954 | /* permissive domain? */ |
990 | rc = security_compute_av_core(ssid, tsid, tclass, requested, avd); | 955 | if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) |
956 | avd->flags |= AVD_FLAGS_PERMISSIVE; | ||
957 | |||
958 | tcontext = sidtab_search(&sidtab, tsid); | ||
959 | if (!tcontext) { | ||
960 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
961 | __func__, tsid); | ||
962 | goto out; | ||
963 | } | ||
964 | |||
965 | if (unlikely(!tclass)) { | ||
966 | if (policydb.allow_unknown) | ||
967 | goto allow; | ||
968 | goto out; | ||
969 | } | ||
970 | |||
971 | context_struct_compute_av(scontext, tcontext, tclass, avd); | ||
972 | out: | ||
991 | read_unlock(&policy_rwlock); | 973 | read_unlock(&policy_rwlock); |
992 | return rc; | 974 | return; |
975 | allow: | ||
976 | avd->allowed = 0xffffffff; | ||
977 | goto out; | ||
993 | } | 978 | } |
994 | 979 | ||
995 | /* | 980 | /* |
@@ -1565,7 +1550,10 @@ static int clone_sid(u32 sid, | |||
1565 | { | 1550 | { |
1566 | struct sidtab *s = arg; | 1551 | struct sidtab *s = arg; |
1567 | 1552 | ||
1568 | return sidtab_insert(s, sid, context); | 1553 | if (sid > SECINITSID_NUM) |
1554 | return sidtab_insert(s, sid, context); | ||
1555 | else | ||
1556 | return 0; | ||
1569 | } | 1557 | } |
1570 | 1558 | ||
1571 | static inline int convert_context_handle_invalid_context(struct context *context) | 1559 | static inline int convert_context_handle_invalid_context(struct context *context) |
@@ -1606,12 +1594,17 @@ static int convert_context(u32 key, | |||
1606 | { | 1594 | { |
1607 | struct convert_context_args *args; | 1595 | struct convert_context_args *args; |
1608 | struct context oldc; | 1596 | struct context oldc; |
1597 | struct ocontext *oc; | ||
1598 | struct mls_range *range; | ||
1609 | struct role_datum *role; | 1599 | struct role_datum *role; |
1610 | struct type_datum *typdatum; | 1600 | struct type_datum *typdatum; |
1611 | struct user_datum *usrdatum; | 1601 | struct user_datum *usrdatum; |
1612 | char *s; | 1602 | char *s; |
1613 | u32 len; | 1603 | u32 len; |
1614 | int rc; | 1604 | int rc = 0; |
1605 | |||
1606 | if (key <= SECINITSID_NUM) | ||
1607 | goto out; | ||
1615 | 1608 | ||
1616 | args = p; | 1609 | args = p; |
1617 | 1610 | ||
@@ -1673,9 +1666,39 @@ static int convert_context(u32 key, | |||
1673 | goto bad; | 1666 | goto bad; |
1674 | c->type = typdatum->value; | 1667 | c->type = typdatum->value; |
1675 | 1668 | ||
1676 | rc = mls_convert_context(args->oldp, args->newp, c); | 1669 | /* Convert the MLS fields if dealing with MLS policies */ |
1677 | if (rc) | 1670 | if (args->oldp->mls_enabled && args->newp->mls_enabled) { |
1678 | goto bad; | 1671 | rc = mls_convert_context(args->oldp, args->newp, c); |
1672 | if (rc) | ||
1673 | goto bad; | ||
1674 | } else if (args->oldp->mls_enabled && !args->newp->mls_enabled) { | ||
1675 | /* | ||
1676 | * Switching between MLS and non-MLS policy: | ||
1677 | * free any storage used by the MLS fields in the | ||
1678 | * context for all existing entries in the sidtab. | ||
1679 | */ | ||
1680 | mls_context_destroy(c); | ||
1681 | } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) { | ||
1682 | /* | ||
1683 | * Switching between non-MLS and MLS policy: | ||
1684 | * ensure that the MLS fields of the context for all | ||
1685 | * existing entries in the sidtab are filled in with a | ||
1686 | * suitable default value, likely taken from one of the | ||
1687 | * initial SIDs. | ||
1688 | */ | ||
1689 | oc = args->newp->ocontexts[OCON_ISID]; | ||
1690 | while (oc && oc->sid[0] != SECINITSID_UNLABELED) | ||
1691 | oc = oc->next; | ||
1692 | if (!oc) { | ||
1693 | printk(KERN_ERR "SELinux: unable to look up" | ||
1694 | " the initial SIDs list\n"); | ||
1695 | goto bad; | ||
1696 | } | ||
1697 | range = &oc->context[0].range; | ||
1698 | rc = mls_range_set(c, range); | ||
1699 | if (rc) | ||
1700 | goto bad; | ||
1701 | } | ||
1679 | 1702 | ||
1680 | /* Check the validity of the new context. */ | 1703 | /* Check the validity of the new context. */ |
1681 | if (!policydb_context_isvalid(args->newp, c)) { | 1704 | if (!policydb_context_isvalid(args->newp, c)) { |
@@ -1771,9 +1794,17 @@ int security_load_policy(void *data, size_t len) | |||
1771 | if (policydb_read(&newpolicydb, fp)) | 1794 | if (policydb_read(&newpolicydb, fp)) |
1772 | return -EINVAL; | 1795 | return -EINVAL; |
1773 | 1796 | ||
1774 | if (sidtab_init(&newsidtab)) { | 1797 | /* If switching between different policy types, log MLS status */ |
1798 | if (policydb.mls_enabled && !newpolicydb.mls_enabled) | ||
1799 | printk(KERN_INFO "SELinux: Disabling MLS support...\n"); | ||
1800 | else if (!policydb.mls_enabled && newpolicydb.mls_enabled) | ||
1801 | printk(KERN_INFO "SELinux: Enabling MLS support...\n"); | ||
1802 | |||
1803 | rc = policydb_load_isids(&newpolicydb, &newsidtab); | ||
1804 | if (rc) { | ||
1805 | printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); | ||
1775 | policydb_destroy(&newpolicydb); | 1806 | policydb_destroy(&newpolicydb); |
1776 | return -ENOMEM; | 1807 | return rc; |
1777 | } | 1808 | } |
1778 | 1809 | ||
1779 | if (selinux_set_mapping(&newpolicydb, secclass_map, | 1810 | if (selinux_set_mapping(&newpolicydb, secclass_map, |
@@ -1800,8 +1831,12 @@ int security_load_policy(void *data, size_t len) | |||
1800 | args.oldp = &policydb; | 1831 | args.oldp = &policydb; |
1801 | args.newp = &newpolicydb; | 1832 | args.newp = &newpolicydb; |
1802 | rc = sidtab_map(&newsidtab, convert_context, &args); | 1833 | rc = sidtab_map(&newsidtab, convert_context, &args); |
1803 | if (rc) | 1834 | if (rc) { |
1835 | printk(KERN_ERR "SELinux: unable to convert the internal" | ||
1836 | " representation of contexts in the new SID" | ||
1837 | " table\n"); | ||
1804 | goto err; | 1838 | goto err; |
1839 | } | ||
1805 | 1840 | ||
1806 | /* Save the old policydb and SID table to free later. */ | 1841 | /* Save the old policydb and SID table to free later. */ |
1807 | memcpy(&oldpolicydb, &policydb, sizeof policydb); | 1842 | memcpy(&oldpolicydb, &policydb, sizeof policydb); |
@@ -2397,7 +2432,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) | |||
2397 | u32 len; | 2432 | u32 len; |
2398 | int rc = 0; | 2433 | int rc = 0; |
2399 | 2434 | ||
2400 | if (!ss_initialized || !selinux_mls_enabled) { | 2435 | if (!ss_initialized || !policydb.mls_enabled) { |
2401 | *new_sid = sid; | 2436 | *new_sid = sid; |
2402 | goto out; | 2437 | goto out; |
2403 | } | 2438 | } |
@@ -2498,7 +2533,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, | |||
2498 | /* we don't need to check ss_initialized here since the only way both | 2533 | /* we don't need to check ss_initialized here since the only way both |
2499 | * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the | 2534 | * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the |
2500 | * security server was initialized and ss_initialized was true */ | 2535 | * security server was initialized and ss_initialized was true */ |
2501 | if (!selinux_mls_enabled) { | 2536 | if (!policydb.mls_enabled) { |
2502 | *peer_sid = SECSID_NULL; | 2537 | *peer_sid = SECSID_NULL; |
2503 | return 0; | 2538 | return 0; |
2504 | } | 2539 | } |
@@ -2555,7 +2590,7 @@ int security_get_classes(char ***classes, int *nclasses) | |||
2555 | read_lock(&policy_rwlock); | 2590 | read_lock(&policy_rwlock); |
2556 | 2591 | ||
2557 | *nclasses = policydb.p_classes.nprim; | 2592 | *nclasses = policydb.p_classes.nprim; |
2558 | *classes = kcalloc(*nclasses, sizeof(*classes), GFP_ATOMIC); | 2593 | *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC); |
2559 | if (!*classes) | 2594 | if (!*classes) |
2560 | goto out; | 2595 | goto out; |
2561 | 2596 | ||
@@ -2602,7 +2637,7 @@ int security_get_permissions(char *class, char ***perms, int *nperms) | |||
2602 | } | 2637 | } |
2603 | 2638 | ||
2604 | *nperms = match->permissions.nprim; | 2639 | *nperms = match->permissions.nprim; |
2605 | *perms = kcalloc(*nperms, sizeof(*perms), GFP_ATOMIC); | 2640 | *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC); |
2606 | if (!*perms) | 2641 | if (!*perms) |
2607 | goto out; | 2642 | goto out; |
2608 | 2643 | ||
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 529c9ca65878..a5721b373f53 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -157,12 +157,12 @@ static int smack_ptrace_traceme(struct task_struct *ptp) | |||
157 | * | 157 | * |
158 | * Returns 0 on success, error code otherwise. | 158 | * Returns 0 on success, error code otherwise. |
159 | */ | 159 | */ |
160 | static int smack_syslog(int type) | 160 | static int smack_syslog(int type, bool from_file) |
161 | { | 161 | { |
162 | int rc; | 162 | int rc; |
163 | char *sp = current_security(); | 163 | char *sp = current_security(); |
164 | 164 | ||
165 | rc = cap_syslog(type); | 165 | rc = cap_syslog(type, from_file); |
166 | if (rc != 0) | 166 | if (rc != 0) |
167 | return rc; | 167 | return rc; |
168 | 168 | ||
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index 10ccd686b290..60a9e2002da1 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile | |||
@@ -1 +1 @@ | |||
obj-y = common.o realpath.o tomoyo.o domain.o file.o | obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o | ||
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index e0d0354008b7..ff51f1026b57 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -12,9 +12,10 @@ | |||
12 | #include <linux/uaccess.h> | 12 | #include <linux/uaccess.h> |
13 | #include <linux/security.h> | 13 | #include <linux/security.h> |
14 | #include <linux/hardirq.h> | 14 | #include <linux/hardirq.h> |
15 | #include "realpath.h" | ||
16 | #include "common.h" | 15 | #include "common.h" |
17 | #include "tomoyo.h" | 16 | |
17 | /* Lock for protecting policy. */ | ||
18 | DEFINE_MUTEX(tomoyo_policy_lock); | ||
18 | 19 | ||
19 | /* Has loading policy done? */ | 20 | /* Has loading policy done? */ |
20 | bool tomoyo_policy_loaded; | 21 | bool tomoyo_policy_loaded; |
@@ -178,14 +179,12 @@ static void tomoyo_normalize_line(unsigned char *buffer) | |||
178 | * 1 = must / -1 = must not / 0 = don't care | 179 | * 1 = must / -1 = must not / 0 = don't care |
179 | * @end_type: Should the pathname end with '/'? | 180 | * @end_type: Should the pathname end with '/'? |
180 | * 1 = must / -1 = must not / 0 = don't care | 181 | * 1 = must / -1 = must not / 0 = don't care |
181 | * @function: The name of function calling me. | ||
182 | * | 182 | * |
183 | * Check whether the given filename follows the naming rules. | 183 | * Check whether the given filename follows the naming rules. |
184 | * Returns true if @filename follows the naming rules, false otherwise. | 184 | * Returns true if @filename follows the naming rules, false otherwise. |
185 | */ | 185 | */ |
186 | bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | 186 | bool tomoyo_is_correct_path(const char *filename, const s8 start_type, |
187 | const s8 pattern_type, const s8 end_type, | 187 | const s8 pattern_type, const s8 end_type) |
188 | const char *function) | ||
189 | { | 188 | { |
190 | const char *const start = filename; | 189 | const char *const start = filename; |
191 | bool in_repetition = false; | 190 | bool in_repetition = false; |
@@ -193,7 +192,6 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | |||
193 | unsigned char c; | 192 | unsigned char c; |
194 | unsigned char d; | 193 | unsigned char d; |
195 | unsigned char e; | 194 | unsigned char e; |
196 | const char *original_filename = filename; | ||
197 | 195 | ||
198 | if (!filename) | 196 | if (!filename) |
199 | goto out; | 197 | goto out; |
@@ -282,25 +280,20 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | |||
282 | goto out; | 280 | goto out; |
283 | return true; | 281 | return true; |
284 | out: | 282 | out: |
285 | printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function, | ||
286 | original_filename); | ||
287 | return false; | 283 | return false; |
288 | } | 284 | } |
289 | 285 | ||
290 | /** | 286 | /** |
291 | * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules. | 287 | * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules. |
292 | * @domainname: The domainname to check. | 288 | * @domainname: The domainname to check. |
293 | * @function: The name of function calling me. | ||
294 | * | 289 | * |
295 | * Returns true if @domainname follows the naming rules, false otherwise. | 290 | * Returns true if @domainname follows the naming rules, false otherwise. |
296 | */ | 291 | */ |
297 | bool tomoyo_is_correct_domain(const unsigned char *domainname, | 292 | bool tomoyo_is_correct_domain(const unsigned char *domainname) |
298 | const char *function) | ||
299 | { | 293 | { |
300 | unsigned char c; | 294 | unsigned char c; |
301 | unsigned char d; | 295 | unsigned char d; |
302 | unsigned char e; | 296 | unsigned char e; |
303 | const char *org_domainname = domainname; | ||
304 | 297 | ||
305 | if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME, | 298 | if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME, |
306 | TOMOYO_ROOT_NAME_LEN)) | 299 | TOMOYO_ROOT_NAME_LEN)) |
@@ -343,8 +336,6 @@ bool tomoyo_is_correct_domain(const unsigned char *domainname, | |||
343 | } while (*domainname); | 336 | } while (*domainname); |
344 | return true; | 337 | return true; |
345 | out: | 338 | out: |
346 | printk(KERN_DEBUG "%s: Invalid domainname '%s'\n", function, | ||
347 | org_domainname); | ||
348 | return false; | 339 | return false; |
349 | } | 340 | } |
350 | 341 | ||
@@ -365,10 +356,9 @@ bool tomoyo_is_domain_def(const unsigned char *buffer) | |||
365 | * | 356 | * |
366 | * @domainname: The domainname to find. | 357 | * @domainname: The domainname to find. |
367 | * | 358 | * |
368 | * Caller must call down_read(&tomoyo_domain_list_lock); or | ||
369 | * down_write(&tomoyo_domain_list_lock); . | ||
370 | * | ||
371 | * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. | 359 | * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. |
360 | * | ||
361 | * Caller holds tomoyo_read_lock(). | ||
372 | */ | 362 | */ |
373 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) | 363 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) |
374 | { | 364 | { |
@@ -377,7 +367,7 @@ struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) | |||
377 | 367 | ||
378 | name.name = domainname; | 368 | name.name = domainname; |
379 | tomoyo_fill_path_info(&name); | 369 | tomoyo_fill_path_info(&name); |
380 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | 370 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
381 | if (!domain->is_deleted && | 371 | if (!domain->is_deleted && |
382 | !tomoyo_pathcmp(&name, domain->domainname)) | 372 | !tomoyo_pathcmp(&name, domain->domainname)) |
383 | return domain; | 373 | return domain; |
@@ -748,7 +738,7 @@ bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | |||
748 | * | 738 | * |
749 | * Returns the tomoyo_realpath() of current process on success, NULL otherwise. | 739 | * Returns the tomoyo_realpath() of current process on success, NULL otherwise. |
750 | * | 740 | * |
751 | * This function uses tomoyo_alloc(), so the caller must call tomoyo_free() | 741 | * This function uses kzalloc(), so the caller must call kfree() |
752 | * if this function didn't return NULL. | 742 | * if this function didn't return NULL. |
753 | */ | 743 | */ |
754 | static const char *tomoyo_get_exe(void) | 744 | static const char *tomoyo_get_exe(void) |
@@ -829,6 +819,8 @@ bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain) | |||
829 | * @domain: Pointer to "struct tomoyo_domain_info". | 819 | * @domain: Pointer to "struct tomoyo_domain_info". |
830 | * | 820 | * |
831 | * Returns true if the domain is not exceeded quota, false otherwise. | 821 | * Returns true if the domain is not exceeded quota, false otherwise. |
822 | * | ||
823 | * Caller holds tomoyo_read_lock(). | ||
832 | */ | 824 | */ |
833 | bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) | 825 | bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) |
834 | { | 826 | { |
@@ -837,61 +829,29 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) | |||
837 | 829 | ||
838 | if (!domain) | 830 | if (!domain) |
839 | return true; | 831 | return true; |
840 | down_read(&tomoyo_domain_acl_info_list_lock); | 832 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
841 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 833 | switch (ptr->type) { |
842 | if (ptr->type & TOMOYO_ACL_DELETED) | 834 | struct tomoyo_path_acl *acl; |
843 | continue; | 835 | u32 perm; |
844 | switch (tomoyo_acl_type2(ptr)) { | 836 | u8 i; |
845 | struct tomoyo_single_path_acl_record *acl1; | 837 | case TOMOYO_TYPE_PATH_ACL: |
846 | struct tomoyo_double_path_acl_record *acl2; | 838 | acl = container_of(ptr, struct tomoyo_path_acl, head); |
847 | u16 perm; | 839 | perm = acl->perm | (((u32) acl->perm_high) << 16); |
848 | case TOMOYO_TYPE_SINGLE_PATH_ACL: | 840 | for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++) |
849 | acl1 = container_of(ptr, | 841 | if (perm & (1 << i)) |
850 | struct tomoyo_single_path_acl_record, | 842 | count++; |
851 | head); | 843 | if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) |
852 | perm = acl1->perm; | 844 | count -= 2; |
853 | if (perm & (1 << TOMOYO_TYPE_EXECUTE_ACL)) | ||
854 | count++; | ||
855 | if (perm & | ||
856 | ((1 << TOMOYO_TYPE_READ_ACL) | | ||
857 | (1 << TOMOYO_TYPE_WRITE_ACL))) | ||
858 | count++; | ||
859 | if (perm & (1 << TOMOYO_TYPE_CREATE_ACL)) | ||
860 | count++; | ||
861 | if (perm & (1 << TOMOYO_TYPE_UNLINK_ACL)) | ||
862 | count++; | ||
863 | if (perm & (1 << TOMOYO_TYPE_MKDIR_ACL)) | ||
864 | count++; | ||
865 | if (perm & (1 << TOMOYO_TYPE_RMDIR_ACL)) | ||
866 | count++; | ||
867 | if (perm & (1 << TOMOYO_TYPE_MKFIFO_ACL)) | ||
868 | count++; | ||
869 | if (perm & (1 << TOMOYO_TYPE_MKSOCK_ACL)) | ||
870 | count++; | ||
871 | if (perm & (1 << TOMOYO_TYPE_MKBLOCK_ACL)) | ||
872 | count++; | ||
873 | if (perm & (1 << TOMOYO_TYPE_MKCHAR_ACL)) | ||
874 | count++; | ||
875 | if (perm & (1 << TOMOYO_TYPE_TRUNCATE_ACL)) | ||
876 | count++; | ||
877 | if (perm & (1 << TOMOYO_TYPE_SYMLINK_ACL)) | ||
878 | count++; | ||
879 | if (perm & (1 << TOMOYO_TYPE_REWRITE_ACL)) | ||
880 | count++; | ||
881 | break; | 845 | break; |
882 | case TOMOYO_TYPE_DOUBLE_PATH_ACL: | 846 | case TOMOYO_TYPE_PATH2_ACL: |
883 | acl2 = container_of(ptr, | 847 | perm = container_of(ptr, struct tomoyo_path2_acl, head) |
884 | struct tomoyo_double_path_acl_record, | 848 | ->perm; |
885 | head); | 849 | for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++) |
886 | perm = acl2->perm; | 850 | if (perm & (1 << i)) |
887 | if (perm & (1 << TOMOYO_TYPE_LINK_ACL)) | 851 | count++; |
888 | count++; | ||
889 | if (perm & (1 << TOMOYO_TYPE_RENAME_ACL)) | ||
890 | count++; | ||
891 | break; | 852 | break; |
892 | } | 853 | } |
893 | } | 854 | } |
894 | up_read(&tomoyo_domain_acl_info_list_lock); | ||
895 | if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY)) | 855 | if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY)) |
896 | return true; | 856 | return true; |
897 | if (!domain->quota_warned) { | 857 | if (!domain->quota_warned) { |
@@ -923,9 +883,11 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned | |||
923 | ptr = tomoyo_profile_ptr[profile]; | 883 | ptr = tomoyo_profile_ptr[profile]; |
924 | if (ptr) | 884 | if (ptr) |
925 | goto ok; | 885 | goto ok; |
926 | ptr = tomoyo_alloc_element(sizeof(*ptr)); | 886 | ptr = kmalloc(sizeof(*ptr), GFP_KERNEL); |
927 | if (!ptr) | 887 | if (!tomoyo_memory_ok(ptr)) { |
888 | kfree(ptr); | ||
928 | goto ok; | 889 | goto ok; |
890 | } | ||
929 | for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) | 891 | for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) |
930 | ptr->value[i] = tomoyo_control_array[i].current_value; | 892 | ptr->value[i] = tomoyo_control_array[i].current_value; |
931 | mb(); /* Avoid out-of-order execution. */ | 893 | mb(); /* Avoid out-of-order execution. */ |
@@ -966,7 +928,9 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | |||
966 | return -EINVAL; | 928 | return -EINVAL; |
967 | *cp = '\0'; | 929 | *cp = '\0'; |
968 | if (!strcmp(data, "COMMENT")) { | 930 | if (!strcmp(data, "COMMENT")) { |
969 | profile->comment = tomoyo_save_name(cp + 1); | 931 | const struct tomoyo_path_info *old_comment = profile->comment; |
932 | profile->comment = tomoyo_get_name(cp + 1); | ||
933 | tomoyo_put_name(old_comment); | ||
970 | return 0; | 934 | return 0; |
971 | } | 935 | } |
972 | for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) { | 936 | for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) { |
@@ -1061,27 +1025,6 @@ static int tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
1061 | } | 1025 | } |
1062 | 1026 | ||
1063 | /* | 1027 | /* |
1064 | * tomoyo_policy_manager_entry is a structure which is used for holding list of | ||
1065 | * domainnames or programs which are permitted to modify configuration via | ||
1066 | * /sys/kernel/security/tomoyo/ interface. | ||
1067 | * It has following fields. | ||
1068 | * | ||
1069 | * (1) "list" which is linked to tomoyo_policy_manager_list . | ||
1070 | * (2) "manager" is a domainname or a program's pathname. | ||
1071 | * (3) "is_domain" is a bool which is true if "manager" is a domainname, false | ||
1072 | * otherwise. | ||
1073 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
1074 | * otherwise. | ||
1075 | */ | ||
1076 | struct tomoyo_policy_manager_entry { | ||
1077 | struct list_head list; | ||
1078 | /* A path to program or a domainname. */ | ||
1079 | const struct tomoyo_path_info *manager; | ||
1080 | bool is_domain; /* True if manager is a domainname. */ | ||
1081 | bool is_deleted; /* True if this entry is deleted. */ | ||
1082 | }; | ||
1083 | |||
1084 | /* | ||
1085 | * tomoyo_policy_manager_list is used for holding list of domainnames or | 1028 | * tomoyo_policy_manager_list is used for holding list of domainnames or |
1086 | * programs which are permitted to modify configuration via | 1029 | * programs which are permitted to modify configuration via |
1087 | * /sys/kernel/security/tomoyo/ interface. | 1030 | * /sys/kernel/security/tomoyo/ interface. |
@@ -1111,8 +1054,7 @@ struct tomoyo_policy_manager_entry { | |||
1111 | * | 1054 | * |
1112 | * # cat /sys/kernel/security/tomoyo/manager | 1055 | * # cat /sys/kernel/security/tomoyo/manager |
1113 | */ | 1056 | */ |
1114 | static LIST_HEAD(tomoyo_policy_manager_list); | 1057 | LIST_HEAD(tomoyo_policy_manager_list); |
1115 | static DECLARE_RWSEM(tomoyo_policy_manager_list_lock); | ||
1116 | 1058 | ||
1117 | /** | 1059 | /** |
1118 | * tomoyo_update_manager_entry - Add a manager entry. | 1060 | * tomoyo_update_manager_entry - Add a manager entry. |
@@ -1121,48 +1063,50 @@ static DECLARE_RWSEM(tomoyo_policy_manager_list_lock); | |||
1121 | * @is_delete: True if it is a delete request. | 1063 | * @is_delete: True if it is a delete request. |
1122 | * | 1064 | * |
1123 | * Returns 0 on success, negative value otherwise. | 1065 | * Returns 0 on success, negative value otherwise. |
1066 | * | ||
1067 | * Caller holds tomoyo_read_lock(). | ||
1124 | */ | 1068 | */ |
1125 | static int tomoyo_update_manager_entry(const char *manager, | 1069 | static int tomoyo_update_manager_entry(const char *manager, |
1126 | const bool is_delete) | 1070 | const bool is_delete) |
1127 | { | 1071 | { |
1128 | struct tomoyo_policy_manager_entry *new_entry; | 1072 | struct tomoyo_policy_manager_entry *entry = NULL; |
1129 | struct tomoyo_policy_manager_entry *ptr; | 1073 | struct tomoyo_policy_manager_entry *ptr; |
1130 | const struct tomoyo_path_info *saved_manager; | 1074 | const struct tomoyo_path_info *saved_manager; |
1131 | int error = -ENOMEM; | 1075 | int error = is_delete ? -ENOENT : -ENOMEM; |
1132 | bool is_domain = false; | 1076 | bool is_domain = false; |
1133 | 1077 | ||
1134 | if (tomoyo_is_domain_def(manager)) { | 1078 | if (tomoyo_is_domain_def(manager)) { |
1135 | if (!tomoyo_is_correct_domain(manager, __func__)) | 1079 | if (!tomoyo_is_correct_domain(manager)) |
1136 | return -EINVAL; | 1080 | return -EINVAL; |
1137 | is_domain = true; | 1081 | is_domain = true; |
1138 | } else { | 1082 | } else { |
1139 | if (!tomoyo_is_correct_path(manager, 1, -1, -1, __func__)) | 1083 | if (!tomoyo_is_correct_path(manager, 1, -1, -1)) |
1140 | return -EINVAL; | 1084 | return -EINVAL; |
1141 | } | 1085 | } |
1142 | saved_manager = tomoyo_save_name(manager); | 1086 | saved_manager = tomoyo_get_name(manager); |
1143 | if (!saved_manager) | 1087 | if (!saved_manager) |
1144 | return -ENOMEM; | 1088 | return -ENOMEM; |
1145 | down_write(&tomoyo_policy_manager_list_lock); | 1089 | if (!is_delete) |
1146 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { | 1090 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
1091 | mutex_lock(&tomoyo_policy_lock); | ||
1092 | list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { | ||
1147 | if (ptr->manager != saved_manager) | 1093 | if (ptr->manager != saved_manager) |
1148 | continue; | 1094 | continue; |
1149 | ptr->is_deleted = is_delete; | 1095 | ptr->is_deleted = is_delete; |
1150 | error = 0; | 1096 | error = 0; |
1151 | goto out; | 1097 | break; |
1152 | } | 1098 | } |
1153 | if (is_delete) { | 1099 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
1154 | error = -ENOENT; | 1100 | entry->manager = saved_manager; |
1155 | goto out; | 1101 | saved_manager = NULL; |
1102 | entry->is_domain = is_domain; | ||
1103 | list_add_tail_rcu(&entry->list, &tomoyo_policy_manager_list); | ||
1104 | entry = NULL; | ||
1105 | error = 0; | ||
1156 | } | 1106 | } |
1157 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 1107 | mutex_unlock(&tomoyo_policy_lock); |
1158 | if (!new_entry) | 1108 | tomoyo_put_name(saved_manager); |
1159 | goto out; | 1109 | kfree(entry); |
1160 | new_entry->manager = saved_manager; | ||
1161 | new_entry->is_domain = is_domain; | ||
1162 | list_add_tail(&new_entry->list, &tomoyo_policy_manager_list); | ||
1163 | error = 0; | ||
1164 | out: | ||
1165 | up_write(&tomoyo_policy_manager_list_lock); | ||
1166 | return error; | 1110 | return error; |
1167 | } | 1111 | } |
1168 | 1112 | ||
@@ -1172,6 +1116,8 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
1172 | * @head: Pointer to "struct tomoyo_io_buffer". | 1116 | * @head: Pointer to "struct tomoyo_io_buffer". |
1173 | * | 1117 | * |
1174 | * Returns 0 on success, negative value otherwise. | 1118 | * Returns 0 on success, negative value otherwise. |
1119 | * | ||
1120 | * Caller holds tomoyo_read_lock(). | ||
1175 | */ | 1121 | */ |
1176 | static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head) | 1122 | static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head) |
1177 | { | 1123 | { |
@@ -1191,6 +1137,8 @@ static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head) | |||
1191 | * @head: Pointer to "struct tomoyo_io_buffer". | 1137 | * @head: Pointer to "struct tomoyo_io_buffer". |
1192 | * | 1138 | * |
1193 | * Returns 0. | 1139 | * Returns 0. |
1140 | * | ||
1141 | * Caller holds tomoyo_read_lock(). | ||
1194 | */ | 1142 | */ |
1195 | static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) | 1143 | static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) |
1196 | { | 1144 | { |
@@ -1199,7 +1147,6 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) | |||
1199 | 1147 | ||
1200 | if (head->read_eof) | 1148 | if (head->read_eof) |
1201 | return 0; | 1149 | return 0; |
1202 | down_read(&tomoyo_policy_manager_list_lock); | ||
1203 | list_for_each_cookie(pos, head->read_var2, | 1150 | list_for_each_cookie(pos, head->read_var2, |
1204 | &tomoyo_policy_manager_list) { | 1151 | &tomoyo_policy_manager_list) { |
1205 | struct tomoyo_policy_manager_entry *ptr; | 1152 | struct tomoyo_policy_manager_entry *ptr; |
@@ -1211,7 +1158,6 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) | |||
1211 | if (!done) | 1158 | if (!done) |
1212 | break; | 1159 | break; |
1213 | } | 1160 | } |
1214 | up_read(&tomoyo_policy_manager_list_lock); | ||
1215 | head->read_eof = done; | 1161 | head->read_eof = done; |
1216 | return 0; | 1162 | return 0; |
1217 | } | 1163 | } |
@@ -1221,6 +1167,8 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) | |||
1221 | * | 1167 | * |
1222 | * Returns true if the current process is permitted to modify policy | 1168 | * Returns true if the current process is permitted to modify policy |
1223 | * via /sys/kernel/security/tomoyo/ interface. | 1169 | * via /sys/kernel/security/tomoyo/ interface. |
1170 | * | ||
1171 | * Caller holds tomoyo_read_lock(). | ||
1224 | */ | 1172 | */ |
1225 | static bool tomoyo_is_policy_manager(void) | 1173 | static bool tomoyo_is_policy_manager(void) |
1226 | { | 1174 | { |
@@ -1234,29 +1182,25 @@ static bool tomoyo_is_policy_manager(void) | |||
1234 | return true; | 1182 | return true; |
1235 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) | 1183 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) |
1236 | return false; | 1184 | return false; |
1237 | down_read(&tomoyo_policy_manager_list_lock); | 1185 | list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { |
1238 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { | ||
1239 | if (!ptr->is_deleted && ptr->is_domain | 1186 | if (!ptr->is_deleted && ptr->is_domain |
1240 | && !tomoyo_pathcmp(domainname, ptr->manager)) { | 1187 | && !tomoyo_pathcmp(domainname, ptr->manager)) { |
1241 | found = true; | 1188 | found = true; |
1242 | break; | 1189 | break; |
1243 | } | 1190 | } |
1244 | } | 1191 | } |
1245 | up_read(&tomoyo_policy_manager_list_lock); | ||
1246 | if (found) | 1192 | if (found) |
1247 | return true; | 1193 | return true; |
1248 | exe = tomoyo_get_exe(); | 1194 | exe = tomoyo_get_exe(); |
1249 | if (!exe) | 1195 | if (!exe) |
1250 | return false; | 1196 | return false; |
1251 | down_read(&tomoyo_policy_manager_list_lock); | 1197 | list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { |
1252 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { | ||
1253 | if (!ptr->is_deleted && !ptr->is_domain | 1198 | if (!ptr->is_deleted && !ptr->is_domain |
1254 | && !strcmp(exe, ptr->manager->name)) { | 1199 | && !strcmp(exe, ptr->manager->name)) { |
1255 | found = true; | 1200 | found = true; |
1256 | break; | 1201 | break; |
1257 | } | 1202 | } |
1258 | } | 1203 | } |
1259 | up_read(&tomoyo_policy_manager_list_lock); | ||
1260 | if (!found) { /* Reduce error messages. */ | 1204 | if (!found) { /* Reduce error messages. */ |
1261 | static pid_t last_pid; | 1205 | static pid_t last_pid; |
1262 | const pid_t pid = current->pid; | 1206 | const pid_t pid = current->pid; |
@@ -1266,7 +1210,7 @@ static bool tomoyo_is_policy_manager(void) | |||
1266 | last_pid = pid; | 1210 | last_pid = pid; |
1267 | } | 1211 | } |
1268 | } | 1212 | } |
1269 | tomoyo_free(exe); | 1213 | kfree(exe); |
1270 | return found; | 1214 | return found; |
1271 | } | 1215 | } |
1272 | 1216 | ||
@@ -1277,6 +1221,8 @@ static bool tomoyo_is_policy_manager(void) | |||
1277 | * @data: String to parse. | 1221 | * @data: String to parse. |
1278 | * | 1222 | * |
1279 | * Returns true on success, false otherwise. | 1223 | * Returns true on success, false otherwise. |
1224 | * | ||
1225 | * Caller holds tomoyo_read_lock(). | ||
1280 | */ | 1226 | */ |
1281 | static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, | 1227 | static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, |
1282 | const char *data) | 1228 | const char *data) |
@@ -1286,17 +1232,16 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, | |||
1286 | 1232 | ||
1287 | if (sscanf(data, "pid=%u", &pid) == 1) { | 1233 | if (sscanf(data, "pid=%u", &pid) == 1) { |
1288 | struct task_struct *p; | 1234 | struct task_struct *p; |
1235 | rcu_read_lock(); | ||
1289 | read_lock(&tasklist_lock); | 1236 | read_lock(&tasklist_lock); |
1290 | p = find_task_by_vpid(pid); | 1237 | p = find_task_by_vpid(pid); |
1291 | if (p) | 1238 | if (p) |
1292 | domain = tomoyo_real_domain(p); | 1239 | domain = tomoyo_real_domain(p); |
1293 | read_unlock(&tasklist_lock); | 1240 | read_unlock(&tasklist_lock); |
1241 | rcu_read_unlock(); | ||
1294 | } else if (!strncmp(data, "domain=", 7)) { | 1242 | } else if (!strncmp(data, "domain=", 7)) { |
1295 | if (tomoyo_is_domain_def(data + 7)) { | 1243 | if (tomoyo_is_domain_def(data + 7)) |
1296 | down_read(&tomoyo_domain_list_lock); | ||
1297 | domain = tomoyo_find_domain(data + 7); | 1244 | domain = tomoyo_find_domain(data + 7); |
1298 | up_read(&tomoyo_domain_list_lock); | ||
1299 | } | ||
1300 | } else | 1245 | } else |
1301 | return false; | 1246 | return false; |
1302 | head->write_var1 = domain; | 1247 | head->write_var1 = domain; |
@@ -1310,13 +1255,11 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, | |||
1310 | if (domain) { | 1255 | if (domain) { |
1311 | struct tomoyo_domain_info *d; | 1256 | struct tomoyo_domain_info *d; |
1312 | head->read_var1 = NULL; | 1257 | head->read_var1 = NULL; |
1313 | down_read(&tomoyo_domain_list_lock); | 1258 | list_for_each_entry_rcu(d, &tomoyo_domain_list, list) { |
1314 | list_for_each_entry(d, &tomoyo_domain_list, list) { | ||
1315 | if (d == domain) | 1259 | if (d == domain) |
1316 | break; | 1260 | break; |
1317 | head->read_var1 = &d->list; | 1261 | head->read_var1 = &d->list; |
1318 | } | 1262 | } |
1319 | up_read(&tomoyo_domain_list_lock); | ||
1320 | head->read_var2 = NULL; | 1263 | head->read_var2 = NULL; |
1321 | head->read_bit = 0; | 1264 | head->read_bit = 0; |
1322 | head->read_step = 0; | 1265 | head->read_step = 0; |
@@ -1332,6 +1275,8 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, | |||
1332 | * @domainname: The name of domain. | 1275 | * @domainname: The name of domain. |
1333 | * | 1276 | * |
1334 | * Returns 0. | 1277 | * Returns 0. |
1278 | * | ||
1279 | * Caller holds tomoyo_read_lock(). | ||
1335 | */ | 1280 | */ |
1336 | static int tomoyo_delete_domain(char *domainname) | 1281 | static int tomoyo_delete_domain(char *domainname) |
1337 | { | 1282 | { |
@@ -1340,9 +1285,9 @@ static int tomoyo_delete_domain(char *domainname) | |||
1340 | 1285 | ||
1341 | name.name = domainname; | 1286 | name.name = domainname; |
1342 | tomoyo_fill_path_info(&name); | 1287 | tomoyo_fill_path_info(&name); |
1343 | down_write(&tomoyo_domain_list_lock); | 1288 | mutex_lock(&tomoyo_policy_lock); |
1344 | /* Is there an active domain? */ | 1289 | /* Is there an active domain? */ |
1345 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | 1290 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
1346 | /* Never delete tomoyo_kernel_domain */ | 1291 | /* Never delete tomoyo_kernel_domain */ |
1347 | if (domain == &tomoyo_kernel_domain) | 1292 | if (domain == &tomoyo_kernel_domain) |
1348 | continue; | 1293 | continue; |
@@ -1352,7 +1297,7 @@ static int tomoyo_delete_domain(char *domainname) | |||
1352 | domain->is_deleted = true; | 1297 | domain->is_deleted = true; |
1353 | break; | 1298 | break; |
1354 | } | 1299 | } |
1355 | up_write(&tomoyo_domain_list_lock); | 1300 | mutex_unlock(&tomoyo_policy_lock); |
1356 | return 0; | 1301 | return 0; |
1357 | } | 1302 | } |
1358 | 1303 | ||
@@ -1362,6 +1307,8 @@ static int tomoyo_delete_domain(char *domainname) | |||
1362 | * @head: Pointer to "struct tomoyo_io_buffer". | 1307 | * @head: Pointer to "struct tomoyo_io_buffer". |
1363 | * | 1308 | * |
1364 | * Returns 0 on success, negative value otherwise. | 1309 | * Returns 0 on success, negative value otherwise. |
1310 | * | ||
1311 | * Caller holds tomoyo_read_lock(). | ||
1365 | */ | 1312 | */ |
1366 | static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) | 1313 | static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) |
1367 | { | 1314 | { |
@@ -1384,11 +1331,9 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) | |||
1384 | domain = NULL; | 1331 | domain = NULL; |
1385 | if (is_delete) | 1332 | if (is_delete) |
1386 | tomoyo_delete_domain(data); | 1333 | tomoyo_delete_domain(data); |
1387 | else if (is_select) { | 1334 | else if (is_select) |
1388 | down_read(&tomoyo_domain_list_lock); | ||
1389 | domain = tomoyo_find_domain(data); | 1335 | domain = tomoyo_find_domain(data); |
1390 | up_read(&tomoyo_domain_list_lock); | 1336 | else |
1391 | } else | ||
1392 | domain = tomoyo_find_or_assign_new_domain(data, 0); | 1337 | domain = tomoyo_find_or_assign_new_domain(data, 0); |
1393 | head->write_var1 = domain; | 1338 | head->write_var1 = domain; |
1394 | return 0; | 1339 | return 0; |
@@ -1403,43 +1348,39 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) | |||
1403 | return 0; | 1348 | return 0; |
1404 | } | 1349 | } |
1405 | if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) { | 1350 | if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) { |
1406 | tomoyo_set_domain_flag(domain, is_delete, | 1351 | domain->ignore_global_allow_read = !is_delete; |
1407 | TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ); | ||
1408 | return 0; | 1352 | return 0; |
1409 | } | 1353 | } |
1410 | return tomoyo_write_file_policy(data, domain, is_delete); | 1354 | return tomoyo_write_file_policy(data, domain, is_delete); |
1411 | } | 1355 | } |
1412 | 1356 | ||
1413 | /** | 1357 | /** |
1414 | * tomoyo_print_single_path_acl - Print a single path ACL entry. | 1358 | * tomoyo_print_path_acl - Print a single path ACL entry. |
1415 | * | 1359 | * |
1416 | * @head: Pointer to "struct tomoyo_io_buffer". | 1360 | * @head: Pointer to "struct tomoyo_io_buffer". |
1417 | * @ptr: Pointer to "struct tomoyo_single_path_acl_record". | 1361 | * @ptr: Pointer to "struct tomoyo_path_acl". |
1418 | * | 1362 | * |
1419 | * Returns true on success, false otherwise. | 1363 | * Returns true on success, false otherwise. |
1420 | */ | 1364 | */ |
1421 | static bool tomoyo_print_single_path_acl(struct tomoyo_io_buffer *head, | 1365 | static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head, |
1422 | struct tomoyo_single_path_acl_record * | 1366 | struct tomoyo_path_acl *ptr) |
1423 | ptr) | ||
1424 | { | 1367 | { |
1425 | int pos; | 1368 | int pos; |
1426 | u8 bit; | 1369 | u8 bit; |
1427 | const char *atmark = ""; | 1370 | const char *atmark = ""; |
1428 | const char *filename; | 1371 | const char *filename; |
1429 | const u16 perm = ptr->perm; | 1372 | const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16); |
1430 | 1373 | ||
1431 | filename = ptr->filename->name; | 1374 | filename = ptr->filename->name; |
1432 | for (bit = head->read_bit; bit < TOMOYO_MAX_SINGLE_PATH_OPERATION; | 1375 | for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { |
1433 | bit++) { | ||
1434 | const char *msg; | 1376 | const char *msg; |
1435 | if (!(perm & (1 << bit))) | 1377 | if (!(perm & (1 << bit))) |
1436 | continue; | 1378 | continue; |
1437 | /* Print "read/write" instead of "read" and "write". */ | 1379 | /* Print "read/write" instead of "read" and "write". */ |
1438 | if ((bit == TOMOYO_TYPE_READ_ACL || | 1380 | if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE) |
1439 | bit == TOMOYO_TYPE_WRITE_ACL) | 1381 | && (perm & (1 << TOMOYO_TYPE_READ_WRITE))) |
1440 | && (perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) | ||
1441 | continue; | 1382 | continue; |
1442 | msg = tomoyo_sp2keyword(bit); | 1383 | msg = tomoyo_path2keyword(bit); |
1443 | pos = head->read_avail; | 1384 | pos = head->read_avail; |
1444 | if (!tomoyo_io_printf(head, "allow_%s %s%s\n", msg, | 1385 | if (!tomoyo_io_printf(head, "allow_%s %s%s\n", msg, |
1445 | atmark, filename)) | 1386 | atmark, filename)) |
@@ -1454,16 +1395,15 @@ static bool tomoyo_print_single_path_acl(struct tomoyo_io_buffer *head, | |||
1454 | } | 1395 | } |
1455 | 1396 | ||
1456 | /** | 1397 | /** |
1457 | * tomoyo_print_double_path_acl - Print a double path ACL entry. | 1398 | * tomoyo_print_path2_acl - Print a double path ACL entry. |
1458 | * | 1399 | * |
1459 | * @head: Pointer to "struct tomoyo_io_buffer". | 1400 | * @head: Pointer to "struct tomoyo_io_buffer". |
1460 | * @ptr: Pointer to "struct tomoyo_double_path_acl_record". | 1401 | * @ptr: Pointer to "struct tomoyo_path2_acl". |
1461 | * | 1402 | * |
1462 | * Returns true on success, false otherwise. | 1403 | * Returns true on success, false otherwise. |
1463 | */ | 1404 | */ |
1464 | static bool tomoyo_print_double_path_acl(struct tomoyo_io_buffer *head, | 1405 | static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head, |
1465 | struct tomoyo_double_path_acl_record * | 1406 | struct tomoyo_path2_acl *ptr) |
1466 | ptr) | ||
1467 | { | 1407 | { |
1468 | int pos; | 1408 | int pos; |
1469 | const char *atmark1 = ""; | 1409 | const char *atmark1 = ""; |
@@ -1475,12 +1415,11 @@ static bool tomoyo_print_double_path_acl(struct tomoyo_io_buffer *head, | |||
1475 | 1415 | ||
1476 | filename1 = ptr->filename1->name; | 1416 | filename1 = ptr->filename1->name; |
1477 | filename2 = ptr->filename2->name; | 1417 | filename2 = ptr->filename2->name; |
1478 | for (bit = head->read_bit; bit < TOMOYO_MAX_DOUBLE_PATH_OPERATION; | 1418 | for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { |
1479 | bit++) { | ||
1480 | const char *msg; | 1419 | const char *msg; |
1481 | if (!(perm & (1 << bit))) | 1420 | if (!(perm & (1 << bit))) |
1482 | continue; | 1421 | continue; |
1483 | msg = tomoyo_dp2keyword(bit); | 1422 | msg = tomoyo_path22keyword(bit); |
1484 | pos = head->read_avail; | 1423 | pos = head->read_avail; |
1485 | if (!tomoyo_io_printf(head, "allow_%s %s%s %s%s\n", msg, | 1424 | if (!tomoyo_io_printf(head, "allow_%s %s%s %s%s\n", msg, |
1486 | atmark1, filename1, atmark2, filename2)) | 1425 | atmark1, filename1, atmark2, filename2)) |
@@ -1505,23 +1444,17 @@ static bool tomoyo_print_double_path_acl(struct tomoyo_io_buffer *head, | |||
1505 | static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | 1444 | static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, |
1506 | struct tomoyo_acl_info *ptr) | 1445 | struct tomoyo_acl_info *ptr) |
1507 | { | 1446 | { |
1508 | const u8 acl_type = tomoyo_acl_type2(ptr); | 1447 | const u8 acl_type = ptr->type; |
1509 | 1448 | ||
1510 | if (acl_type & TOMOYO_ACL_DELETED) | 1449 | if (acl_type == TOMOYO_TYPE_PATH_ACL) { |
1511 | return true; | 1450 | struct tomoyo_path_acl *acl |
1512 | if (acl_type == TOMOYO_TYPE_SINGLE_PATH_ACL) { | 1451 | = container_of(ptr, struct tomoyo_path_acl, head); |
1513 | struct tomoyo_single_path_acl_record *acl | 1452 | return tomoyo_print_path_acl(head, acl); |
1514 | = container_of(ptr, | ||
1515 | struct tomoyo_single_path_acl_record, | ||
1516 | head); | ||
1517 | return tomoyo_print_single_path_acl(head, acl); | ||
1518 | } | 1453 | } |
1519 | if (acl_type == TOMOYO_TYPE_DOUBLE_PATH_ACL) { | 1454 | if (acl_type == TOMOYO_TYPE_PATH2_ACL) { |
1520 | struct tomoyo_double_path_acl_record *acl | 1455 | struct tomoyo_path2_acl *acl |
1521 | = container_of(ptr, | 1456 | = container_of(ptr, struct tomoyo_path2_acl, head); |
1522 | struct tomoyo_double_path_acl_record, | 1457 | return tomoyo_print_path2_acl(head, acl); |
1523 | head); | ||
1524 | return tomoyo_print_double_path_acl(head, acl); | ||
1525 | } | 1458 | } |
1526 | BUG(); /* This must not happen. */ | 1459 | BUG(); /* This must not happen. */ |
1527 | return false; | 1460 | return false; |
@@ -1533,6 +1466,8 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
1533 | * @head: Pointer to "struct tomoyo_io_buffer". | 1466 | * @head: Pointer to "struct tomoyo_io_buffer". |
1534 | * | 1467 | * |
1535 | * Returns 0. | 1468 | * Returns 0. |
1469 | * | ||
1470 | * Caller holds tomoyo_read_lock(). | ||
1536 | */ | 1471 | */ |
1537 | static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) | 1472 | static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) |
1538 | { | 1473 | { |
@@ -1544,7 +1479,6 @@ static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) | |||
1544 | return 0; | 1479 | return 0; |
1545 | if (head->read_step == 0) | 1480 | if (head->read_step == 0) |
1546 | head->read_step = 1; | 1481 | head->read_step = 1; |
1547 | down_read(&tomoyo_domain_list_lock); | ||
1548 | list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) { | 1482 | list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) { |
1549 | struct tomoyo_domain_info *domain; | 1483 | struct tomoyo_domain_info *domain; |
1550 | const char *quota_exceeded = ""; | 1484 | const char *quota_exceeded = ""; |
@@ -1558,10 +1492,9 @@ static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) | |||
1558 | /* Print domainname and flags. */ | 1492 | /* Print domainname and flags. */ |
1559 | if (domain->quota_warned) | 1493 | if (domain->quota_warned) |
1560 | quota_exceeded = "quota_exceeded\n"; | 1494 | quota_exceeded = "quota_exceeded\n"; |
1561 | if (domain->flags & TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED) | 1495 | if (domain->transition_failed) |
1562 | transition_failed = "transition_failed\n"; | 1496 | transition_failed = "transition_failed\n"; |
1563 | if (domain->flags & | 1497 | if (domain->ignore_global_allow_read) |
1564 | TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) | ||
1565 | ignore_global_allow_read | 1498 | ignore_global_allow_read |
1566 | = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; | 1499 | = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; |
1567 | done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE | 1500 | done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE |
@@ -1577,7 +1510,6 @@ acl_loop: | |||
1577 | if (head->read_step == 3) | 1510 | if (head->read_step == 3) |
1578 | goto tail_mark; | 1511 | goto tail_mark; |
1579 | /* Print ACL entries in the domain. */ | 1512 | /* Print ACL entries in the domain. */ |
1580 | down_read(&tomoyo_domain_acl_info_list_lock); | ||
1581 | list_for_each_cookie(apos, head->read_var2, | 1513 | list_for_each_cookie(apos, head->read_var2, |
1582 | &domain->acl_info_list) { | 1514 | &domain->acl_info_list) { |
1583 | struct tomoyo_acl_info *ptr | 1515 | struct tomoyo_acl_info *ptr |
@@ -1587,7 +1519,6 @@ acl_loop: | |||
1587 | if (!done) | 1519 | if (!done) |
1588 | break; | 1520 | break; |
1589 | } | 1521 | } |
1590 | up_read(&tomoyo_domain_acl_info_list_lock); | ||
1591 | if (!done) | 1522 | if (!done) |
1592 | break; | 1523 | break; |
1593 | head->read_step = 3; | 1524 | head->read_step = 3; |
@@ -1599,7 +1530,6 @@ tail_mark: | |||
1599 | if (head->read_single_domain) | 1530 | if (head->read_single_domain) |
1600 | break; | 1531 | break; |
1601 | } | 1532 | } |
1602 | up_read(&tomoyo_domain_list_lock); | ||
1603 | head->read_eof = done; | 1533 | head->read_eof = done; |
1604 | return 0; | 1534 | return 0; |
1605 | } | 1535 | } |
@@ -1615,6 +1545,8 @@ tail_mark: | |||
1615 | * | 1545 | * |
1616 | * ( echo "select " $domainname; echo "use_profile " $profile ) | | 1546 | * ( echo "select " $domainname; echo "use_profile " $profile ) | |
1617 | * /usr/lib/ccs/loadpolicy -d | 1547 | * /usr/lib/ccs/loadpolicy -d |
1548 | * | ||
1549 | * Caller holds tomoyo_read_lock(). | ||
1618 | */ | 1550 | */ |
1619 | static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) | 1551 | static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) |
1620 | { | 1552 | { |
@@ -1626,9 +1558,7 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) | |||
1626 | if (!cp) | 1558 | if (!cp) |
1627 | return -EINVAL; | 1559 | return -EINVAL; |
1628 | *cp = '\0'; | 1560 | *cp = '\0'; |
1629 | down_read(&tomoyo_domain_list_lock); | ||
1630 | domain = tomoyo_find_domain(cp + 1); | 1561 | domain = tomoyo_find_domain(cp + 1); |
1631 | up_read(&tomoyo_domain_list_lock); | ||
1632 | if (strict_strtoul(data, 10, &profile)) | 1562 | if (strict_strtoul(data, 10, &profile)) |
1633 | return -EINVAL; | 1563 | return -EINVAL; |
1634 | if (domain && profile < TOMOYO_MAX_PROFILES | 1564 | if (domain && profile < TOMOYO_MAX_PROFILES |
@@ -1650,6 +1580,8 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) | |||
1650 | * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" ) | 1580 | * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" ) |
1651 | * domainname = $0; } else if ( $1 == "use_profile" ) { | 1581 | * domainname = $0; } else if ( $1 == "use_profile" ) { |
1652 | * print $2 " " domainname; domainname = ""; } } ; ' | 1582 | * print $2 " " domainname; domainname = ""; } } ; ' |
1583 | * | ||
1584 | * Caller holds tomoyo_read_lock(). | ||
1653 | */ | 1585 | */ |
1654 | static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) | 1586 | static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) |
1655 | { | 1587 | { |
@@ -1658,7 +1590,6 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) | |||
1658 | 1590 | ||
1659 | if (head->read_eof) | 1591 | if (head->read_eof) |
1660 | return 0; | 1592 | return 0; |
1661 | down_read(&tomoyo_domain_list_lock); | ||
1662 | list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) { | 1593 | list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) { |
1663 | struct tomoyo_domain_info *domain; | 1594 | struct tomoyo_domain_info *domain; |
1664 | domain = list_entry(pos, struct tomoyo_domain_info, list); | 1595 | domain = list_entry(pos, struct tomoyo_domain_info, list); |
@@ -1669,7 +1600,6 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) | |||
1669 | if (!done) | 1600 | if (!done) |
1670 | break; | 1601 | break; |
1671 | } | 1602 | } |
1672 | up_read(&tomoyo_domain_list_lock); | ||
1673 | head->read_eof = done; | 1603 | head->read_eof = done; |
1674 | return 0; | 1604 | return 0; |
1675 | } | 1605 | } |
@@ -1707,11 +1637,13 @@ static int tomoyo_read_pid(struct tomoyo_io_buffer *head) | |||
1707 | const int pid = head->read_step; | 1637 | const int pid = head->read_step; |
1708 | struct task_struct *p; | 1638 | struct task_struct *p; |
1709 | struct tomoyo_domain_info *domain = NULL; | 1639 | struct tomoyo_domain_info *domain = NULL; |
1640 | rcu_read_lock(); | ||
1710 | read_lock(&tasklist_lock); | 1641 | read_lock(&tasklist_lock); |
1711 | p = find_task_by_vpid(pid); | 1642 | p = find_task_by_vpid(pid); |
1712 | if (p) | 1643 | if (p) |
1713 | domain = tomoyo_real_domain(p); | 1644 | domain = tomoyo_real_domain(p); |
1714 | read_unlock(&tasklist_lock); | 1645 | read_unlock(&tasklist_lock); |
1646 | rcu_read_unlock(); | ||
1715 | if (domain) | 1647 | if (domain) |
1716 | tomoyo_io_printf(head, "%d %u %s", pid, domain->profile, | 1648 | tomoyo_io_printf(head, "%d %u %s", pid, domain->profile, |
1717 | domain->domainname->name); | 1649 | domain->domainname->name); |
@@ -1726,6 +1658,8 @@ static int tomoyo_read_pid(struct tomoyo_io_buffer *head) | |||
1726 | * @head: Pointer to "struct tomoyo_io_buffer". | 1658 | * @head: Pointer to "struct tomoyo_io_buffer". |
1727 | * | 1659 | * |
1728 | * Returns 0 on success, negative value otherwise. | 1660 | * Returns 0 on success, negative value otherwise. |
1661 | * | ||
1662 | * Caller holds tomoyo_read_lock(). | ||
1729 | */ | 1663 | */ |
1730 | static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) | 1664 | static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) |
1731 | { | 1665 | { |
@@ -1760,6 +1694,8 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) | |||
1760 | * @head: Pointer to "struct tomoyo_io_buffer". | 1694 | * @head: Pointer to "struct tomoyo_io_buffer". |
1761 | * | 1695 | * |
1762 | * Returns 0 on success, -EINVAL otherwise. | 1696 | * Returns 0 on success, -EINVAL otherwise. |
1697 | * | ||
1698 | * Caller holds tomoyo_read_lock(). | ||
1763 | */ | 1699 | */ |
1764 | static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) | 1700 | static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) |
1765 | { | 1701 | { |
@@ -1889,15 +1825,13 @@ void tomoyo_load_policy(const char *filename) | |||
1889 | tomoyo_policy_loaded = true; | 1825 | tomoyo_policy_loaded = true; |
1890 | { /* Check all profiles currently assigned to domains are defined. */ | 1826 | { /* Check all profiles currently assigned to domains are defined. */ |
1891 | struct tomoyo_domain_info *domain; | 1827 | struct tomoyo_domain_info *domain; |
1892 | down_read(&tomoyo_domain_list_lock); | 1828 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
1893 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | ||
1894 | const u8 profile = domain->profile; | 1829 | const u8 profile = domain->profile; |
1895 | if (tomoyo_profile_ptr[profile]) | 1830 | if (tomoyo_profile_ptr[profile]) |
1896 | continue; | 1831 | continue; |
1897 | panic("Profile %u (used by '%s') not defined.\n", | 1832 | panic("Profile %u (used by '%s') not defined.\n", |
1898 | profile, domain->domainname->name); | 1833 | profile, domain->domainname->name); |
1899 | } | 1834 | } |
1900 | up_read(&tomoyo_domain_list_lock); | ||
1901 | } | 1835 | } |
1902 | } | 1836 | } |
1903 | 1837 | ||
@@ -1945,10 +1879,12 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head) | |||
1945 | * @file: Pointer to "struct file". | 1879 | * @file: Pointer to "struct file". |
1946 | * | 1880 | * |
1947 | * Associates policy handler and returns 0 on success, -ENOMEM otherwise. | 1881 | * Associates policy handler and returns 0 on success, -ENOMEM otherwise. |
1882 | * | ||
1883 | * Caller acquires tomoyo_read_lock(). | ||
1948 | */ | 1884 | */ |
1949 | static int tomoyo_open_control(const u8 type, struct file *file) | 1885 | static int tomoyo_open_control(const u8 type, struct file *file) |
1950 | { | 1886 | { |
1951 | struct tomoyo_io_buffer *head = tomoyo_alloc(sizeof(*head)); | 1887 | struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_KERNEL); |
1952 | 1888 | ||
1953 | if (!head) | 1889 | if (!head) |
1954 | return -ENOMEM; | 1890 | return -ENOMEM; |
@@ -2009,9 +1945,9 @@ static int tomoyo_open_control(const u8 type, struct file *file) | |||
2009 | } else { | 1945 | } else { |
2010 | if (!head->readbuf_size) | 1946 | if (!head->readbuf_size) |
2011 | head->readbuf_size = 4096 * 2; | 1947 | head->readbuf_size = 4096 * 2; |
2012 | head->read_buf = tomoyo_alloc(head->readbuf_size); | 1948 | head->read_buf = kzalloc(head->readbuf_size, GFP_KERNEL); |
2013 | if (!head->read_buf) { | 1949 | if (!head->read_buf) { |
2014 | tomoyo_free(head); | 1950 | kfree(head); |
2015 | return -ENOMEM; | 1951 | return -ENOMEM; |
2016 | } | 1952 | } |
2017 | } | 1953 | } |
@@ -2023,13 +1959,14 @@ static int tomoyo_open_control(const u8 type, struct file *file) | |||
2023 | head->write = NULL; | 1959 | head->write = NULL; |
2024 | } else if (head->write) { | 1960 | } else if (head->write) { |
2025 | head->writebuf_size = 4096 * 2; | 1961 | head->writebuf_size = 4096 * 2; |
2026 | head->write_buf = tomoyo_alloc(head->writebuf_size); | 1962 | head->write_buf = kzalloc(head->writebuf_size, GFP_KERNEL); |
2027 | if (!head->write_buf) { | 1963 | if (!head->write_buf) { |
2028 | tomoyo_free(head->read_buf); | 1964 | kfree(head->read_buf); |
2029 | tomoyo_free(head); | 1965 | kfree(head); |
2030 | return -ENOMEM; | 1966 | return -ENOMEM; |
2031 | } | 1967 | } |
2032 | } | 1968 | } |
1969 | head->reader_idx = tomoyo_read_lock(); | ||
2033 | file->private_data = head; | 1970 | file->private_data = head; |
2034 | /* | 1971 | /* |
2035 | * Call the handler now if the file is | 1972 | * Call the handler now if the file is |
@@ -2051,6 +1988,8 @@ static int tomoyo_open_control(const u8 type, struct file *file) | |||
2051 | * @buffer_len: Size of @buffer. | 1988 | * @buffer_len: Size of @buffer. |
2052 | * | 1989 | * |
2053 | * Returns bytes read on success, negative value otherwise. | 1990 | * Returns bytes read on success, negative value otherwise. |
1991 | * | ||
1992 | * Caller holds tomoyo_read_lock(). | ||
2054 | */ | 1993 | */ |
2055 | static int tomoyo_read_control(struct file *file, char __user *buffer, | 1994 | static int tomoyo_read_control(struct file *file, char __user *buffer, |
2056 | const int buffer_len) | 1995 | const int buffer_len) |
@@ -2094,6 +2033,8 @@ static int tomoyo_read_control(struct file *file, char __user *buffer, | |||
2094 | * @buffer_len: Size of @buffer. | 2033 | * @buffer_len: Size of @buffer. |
2095 | * | 2034 | * |
2096 | * Returns @buffer_len on success, negative value otherwise. | 2035 | * Returns @buffer_len on success, negative value otherwise. |
2036 | * | ||
2037 | * Caller holds tomoyo_read_lock(). | ||
2097 | */ | 2038 | */ |
2098 | static int tomoyo_write_control(struct file *file, const char __user *buffer, | 2039 | static int tomoyo_write_control(struct file *file, const char __user *buffer, |
2099 | const int buffer_len) | 2040 | const int buffer_len) |
@@ -2144,52 +2085,29 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer, | |||
2144 | * @file: Pointer to "struct file". | 2085 | * @file: Pointer to "struct file". |
2145 | * | 2086 | * |
2146 | * Releases memory and returns 0. | 2087 | * Releases memory and returns 0. |
2088 | * | ||
2089 | * Caller looses tomoyo_read_lock(). | ||
2147 | */ | 2090 | */ |
2148 | static int tomoyo_close_control(struct file *file) | 2091 | static int tomoyo_close_control(struct file *file) |
2149 | { | 2092 | { |
2150 | struct tomoyo_io_buffer *head = file->private_data; | 2093 | struct tomoyo_io_buffer *head = file->private_data; |
2094 | const bool is_write = !!head->write_buf; | ||
2151 | 2095 | ||
2096 | tomoyo_read_unlock(head->reader_idx); | ||
2152 | /* Release memory used for policy I/O. */ | 2097 | /* Release memory used for policy I/O. */ |
2153 | tomoyo_free(head->read_buf); | 2098 | kfree(head->read_buf); |
2154 | head->read_buf = NULL; | 2099 | head->read_buf = NULL; |
2155 | tomoyo_free(head->write_buf); | 2100 | kfree(head->write_buf); |
2156 | head->write_buf = NULL; | 2101 | head->write_buf = NULL; |
2157 | tomoyo_free(head); | 2102 | kfree(head); |
2158 | head = NULL; | 2103 | head = NULL; |
2159 | file->private_data = NULL; | 2104 | file->private_data = NULL; |
2105 | if (is_write) | ||
2106 | tomoyo_run_gc(); | ||
2160 | return 0; | 2107 | return 0; |
2161 | } | 2108 | } |
2162 | 2109 | ||
2163 | /** | 2110 | /** |
2164 | * tomoyo_alloc_acl_element - Allocate permanent memory for ACL entry. | ||
2165 | * | ||
2166 | * @acl_type: Type of ACL entry. | ||
2167 | * | ||
2168 | * Returns pointer to the ACL entry on success, NULL otherwise. | ||
2169 | */ | ||
2170 | void *tomoyo_alloc_acl_element(const u8 acl_type) | ||
2171 | { | ||
2172 | int len; | ||
2173 | struct tomoyo_acl_info *ptr; | ||
2174 | |||
2175 | switch (acl_type) { | ||
2176 | case TOMOYO_TYPE_SINGLE_PATH_ACL: | ||
2177 | len = sizeof(struct tomoyo_single_path_acl_record); | ||
2178 | break; | ||
2179 | case TOMOYO_TYPE_DOUBLE_PATH_ACL: | ||
2180 | len = sizeof(struct tomoyo_double_path_acl_record); | ||
2181 | break; | ||
2182 | default: | ||
2183 | return NULL; | ||
2184 | } | ||
2185 | ptr = tomoyo_alloc_element(len); | ||
2186 | if (!ptr) | ||
2187 | return NULL; | ||
2188 | ptr->type = acl_type; | ||
2189 | return ptr; | ||
2190 | } | ||
2191 | |||
2192 | /** | ||
2193 | * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. | 2111 | * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. |
2194 | * | 2112 | * |
2195 | * @inode: Pointer to "struct inode". | 2113 | * @inode: Pointer to "struct inode". |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 92169d29b2db..67bd22dd3e68 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -1,12 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/common.h | 2 | * security/tomoyo/common.h |
3 | * | 3 | * |
4 | * Common functions for TOMOYO. | 4 | * Header file for TOMOYO. |
5 | * | ||
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | ||
7 | * | ||
8 | * Version: 2.2.0 2009/04/01 | ||
9 | * | 5 | * |
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
10 | */ | 7 | */ |
11 | 8 | ||
12 | #ifndef _SECURITY_TOMOYO_COMMON_H | 9 | #ifndef _SECURITY_TOMOYO_COMMON_H |
@@ -22,9 +19,119 @@ | |||
22 | #include <linux/namei.h> | 19 | #include <linux/namei.h> |
23 | #include <linux/mount.h> | 20 | #include <linux/mount.h> |
24 | #include <linux/list.h> | 21 | #include <linux/list.h> |
22 | #include <linux/cred.h> | ||
23 | struct linux_binprm; | ||
24 | |||
25 | /********** Constants definitions. **********/ | ||
26 | |||
27 | /* | ||
28 | * TOMOYO uses this hash only when appending a string into the string | ||
29 | * table. Frequency of appending strings is very low. So we don't need | ||
30 | * large (e.g. 64k) hash size. 256 will be sufficient. | ||
31 | */ | ||
32 | #define TOMOYO_HASH_BITS 8 | ||
33 | #define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS) | ||
34 | |||
35 | /* | ||
36 | * This is the max length of a token. | ||
37 | * | ||
38 | * A token consists of only ASCII printable characters. | ||
39 | * Non printable characters in a token is represented in \ooo style | ||
40 | * octal string. Thus, \ itself is represented as \\. | ||
41 | */ | ||
42 | #define TOMOYO_MAX_PATHNAME_LEN 4000 | ||
43 | |||
44 | /* Profile number is an integer between 0 and 255. */ | ||
45 | #define TOMOYO_MAX_PROFILES 256 | ||
46 | |||
47 | /* Keywords for ACLs. */ | ||
48 | #define TOMOYO_KEYWORD_ALIAS "alias " | ||
49 | #define TOMOYO_KEYWORD_ALLOW_READ "allow_read " | ||
50 | #define TOMOYO_KEYWORD_DELETE "delete " | ||
51 | #define TOMOYO_KEYWORD_DENY_REWRITE "deny_rewrite " | ||
52 | #define TOMOYO_KEYWORD_FILE_PATTERN "file_pattern " | ||
53 | #define TOMOYO_KEYWORD_INITIALIZE_DOMAIN "initialize_domain " | ||
54 | #define TOMOYO_KEYWORD_KEEP_DOMAIN "keep_domain " | ||
55 | #define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_domain " | ||
56 | #define TOMOYO_KEYWORD_NO_KEEP_DOMAIN "no_keep_domain " | ||
57 | #define TOMOYO_KEYWORD_SELECT "select " | ||
58 | #define TOMOYO_KEYWORD_USE_PROFILE "use_profile " | ||
59 | #define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read" | ||
60 | /* A domain definition starts with <kernel>. */ | ||
61 | #define TOMOYO_ROOT_NAME "<kernel>" | ||
62 | #define TOMOYO_ROOT_NAME_LEN (sizeof(TOMOYO_ROOT_NAME) - 1) | ||
63 | |||
64 | /* Index numbers for Access Controls. */ | ||
65 | enum tomoyo_mac_index { | ||
66 | TOMOYO_MAC_FOR_FILE, /* domain_policy.conf */ | ||
67 | TOMOYO_MAX_ACCEPT_ENTRY, | ||
68 | TOMOYO_VERBOSE, | ||
69 | TOMOYO_MAX_CONTROL_INDEX | ||
70 | }; | ||
71 | |||
72 | /* Index numbers for Access Controls. */ | ||
73 | enum tomoyo_acl_entry_type_index { | ||
74 | TOMOYO_TYPE_PATH_ACL, | ||
75 | TOMOYO_TYPE_PATH2_ACL, | ||
76 | }; | ||
77 | |||
78 | /* Index numbers for File Controls. */ | ||
79 | |||
80 | /* | ||
81 | * TYPE_READ_WRITE_ACL is special. TYPE_READ_WRITE_ACL is automatically set | ||
82 | * if both TYPE_READ_ACL and TYPE_WRITE_ACL are set. Both TYPE_READ_ACL and | ||
83 | * TYPE_WRITE_ACL are automatically set if TYPE_READ_WRITE_ACL is set. | ||
84 | * TYPE_READ_WRITE_ACL is automatically cleared if either TYPE_READ_ACL or | ||
85 | * TYPE_WRITE_ACL is cleared. Both TYPE_READ_ACL and TYPE_WRITE_ACL are | ||
86 | * automatically cleared if TYPE_READ_WRITE_ACL is cleared. | ||
87 | */ | ||
88 | |||
89 | enum tomoyo_path_acl_index { | ||
90 | TOMOYO_TYPE_READ_WRITE, | ||
91 | TOMOYO_TYPE_EXECUTE, | ||
92 | TOMOYO_TYPE_READ, | ||
93 | TOMOYO_TYPE_WRITE, | ||
94 | TOMOYO_TYPE_CREATE, | ||
95 | TOMOYO_TYPE_UNLINK, | ||
96 | TOMOYO_TYPE_MKDIR, | ||
97 | TOMOYO_TYPE_RMDIR, | ||
98 | TOMOYO_TYPE_MKFIFO, | ||
99 | TOMOYO_TYPE_MKSOCK, | ||
100 | TOMOYO_TYPE_MKBLOCK, | ||
101 | TOMOYO_TYPE_MKCHAR, | ||
102 | TOMOYO_TYPE_TRUNCATE, | ||
103 | TOMOYO_TYPE_SYMLINK, | ||
104 | TOMOYO_TYPE_REWRITE, | ||
105 | TOMOYO_TYPE_IOCTL, | ||
106 | TOMOYO_TYPE_CHMOD, | ||
107 | TOMOYO_TYPE_CHOWN, | ||
108 | TOMOYO_TYPE_CHGRP, | ||
109 | TOMOYO_TYPE_CHROOT, | ||
110 | TOMOYO_TYPE_MOUNT, | ||
111 | TOMOYO_TYPE_UMOUNT, | ||
112 | TOMOYO_MAX_PATH_OPERATION | ||
113 | }; | ||
25 | 114 | ||
26 | struct dentry; | 115 | enum tomoyo_path2_acl_index { |
27 | struct vfsmount; | 116 | TOMOYO_TYPE_LINK, |
117 | TOMOYO_TYPE_RENAME, | ||
118 | TOMOYO_TYPE_PIVOT_ROOT, | ||
119 | TOMOYO_MAX_PATH2_OPERATION | ||
120 | }; | ||
121 | |||
122 | enum tomoyo_securityfs_interface_index { | ||
123 | TOMOYO_DOMAINPOLICY, | ||
124 | TOMOYO_EXCEPTIONPOLICY, | ||
125 | TOMOYO_DOMAIN_STATUS, | ||
126 | TOMOYO_PROCESS_STATUS, | ||
127 | TOMOYO_MEMINFO, | ||
128 | TOMOYO_SELFDOMAIN, | ||
129 | TOMOYO_VERSION, | ||
130 | TOMOYO_PROFILE, | ||
131 | TOMOYO_MANAGER | ||
132 | }; | ||
133 | |||
134 | /********** Structure definitions. **********/ | ||
28 | 135 | ||
29 | /* | 136 | /* |
30 | * tomoyo_page_buffer is a structure which is used for holding a pathname | 137 | * tomoyo_page_buffer is a structure which is used for holding a pathname |
@@ -66,13 +173,14 @@ struct tomoyo_path_info { | |||
66 | }; | 173 | }; |
67 | 174 | ||
68 | /* | 175 | /* |
69 | * This is the max length of a token. | 176 | * tomoyo_name_entry is a structure which is used for linking |
70 | * | 177 | * "struct tomoyo_path_info" into tomoyo_name_list . |
71 | * A token consists of only ASCII printable characters. | ||
72 | * Non printable characters in a token is represented in \ooo style | ||
73 | * octal string. Thus, \ itself is represented as \\. | ||
74 | */ | 178 | */ |
75 | #define TOMOYO_MAX_PATHNAME_LEN 4000 | 179 | struct tomoyo_name_entry { |
180 | struct list_head list; | ||
181 | atomic_t users; | ||
182 | struct tomoyo_path_info entry; | ||
183 | }; | ||
76 | 184 | ||
77 | /* | 185 | /* |
78 | * tomoyo_path_info_with_data is a structure which is used for holding a | 186 | * tomoyo_path_info_with_data is a structure which is used for holding a |
@@ -89,7 +197,7 @@ struct tomoyo_path_info { | |||
89 | * "struct tomoyo_path_info_with_data". | 197 | * "struct tomoyo_path_info_with_data". |
90 | */ | 198 | */ |
91 | struct tomoyo_path_info_with_data { | 199 | struct tomoyo_path_info_with_data { |
92 | /* Keep "head" first, for this pointer is passed to tomoyo_free(). */ | 200 | /* Keep "head" first, for this pointer is passed to kfree(). */ |
93 | struct tomoyo_path_info head; | 201 | struct tomoyo_path_info head; |
94 | char barrier1[16]; /* Safeguard for overrun. */ | 202 | char barrier1[16]; /* Safeguard for overrun. */ |
95 | char body[TOMOYO_MAX_PATHNAME_LEN]; | 203 | char body[TOMOYO_MAX_PATHNAME_LEN]; |
@@ -101,30 +209,19 @@ struct tomoyo_path_info_with_data { | |||
101 | * | 209 | * |
102 | * (1) "list" which is linked to the ->acl_info_list of | 210 | * (1) "list" which is linked to the ->acl_info_list of |
103 | * "struct tomoyo_domain_info" | 211 | * "struct tomoyo_domain_info" |
104 | * (2) "type" which tells | 212 | * (2) "type" which tells type of the entry (either |
105 | * (a) type & 0x7F : type of the entry (either | 213 | * "struct tomoyo_path_acl" or "struct tomoyo_path2_acl"). |
106 | * "struct tomoyo_single_path_acl_record" or | ||
107 | * "struct tomoyo_double_path_acl_record") | ||
108 | * (b) type & 0x80 : whether the entry is marked as "deleted". | ||
109 | * | 214 | * |
110 | * Packing "struct tomoyo_acl_info" allows | 215 | * Packing "struct tomoyo_acl_info" allows |
111 | * "struct tomoyo_single_path_acl_record" to embed "u16" and | 216 | * "struct tomoyo_path_acl" to embed "u8" + "u16" and |
112 | * "struct tomoyo_double_path_acl_record" to embed "u8" | 217 | * "struct tomoyo_path2_acl" to embed "u8" |
113 | * without enlarging their structure size. | 218 | * without enlarging their structure size. |
114 | */ | 219 | */ |
115 | struct tomoyo_acl_info { | 220 | struct tomoyo_acl_info { |
116 | struct list_head list; | 221 | struct list_head list; |
117 | /* | ||
118 | * Type of this ACL entry. | ||
119 | * | ||
120 | * MSB is is_deleted flag. | ||
121 | */ | ||
122 | u8 type; | 222 | u8 type; |
123 | } __packed; | 223 | } __packed; |
124 | 224 | ||
125 | /* This ACL entry is deleted. */ | ||
126 | #define TOMOYO_ACL_DELETED 0x80 | ||
127 | |||
128 | /* | 225 | /* |
129 | * tomoyo_domain_info is a structure which is used for holding permissions | 226 | * tomoyo_domain_info is a structure which is used for holding permissions |
130 | * (e.g. "allow_read /lib/libc-2.5.so") given to each domain. | 227 | * (e.g. "allow_read /lib/libc-2.5.so") given to each domain. |
@@ -138,7 +235,17 @@ struct tomoyo_acl_info { | |||
138 | * "deleted", false otherwise. | 235 | * "deleted", false otherwise. |
139 | * (6) "quota_warned" is a bool which is used for suppressing warning message | 236 | * (6) "quota_warned" is a bool which is used for suppressing warning message |
140 | * when learning mode learned too much entries. | 237 | * when learning mode learned too much entries. |
141 | * (7) "flags" which remembers this domain's attributes. | 238 | * (7) "ignore_global_allow_read" is a bool which is true if this domain |
239 | * should ignore "allow_read" directive in exception policy. | ||
240 | * (8) "transition_failed" is a bool which is set to true when this domain was | ||
241 | * unable to create a new domain at tomoyo_find_next_domain() because the | ||
242 | * name of the domain to be created was too long or it could not allocate | ||
243 | * memory. If set to true, more than one process continued execve() | ||
244 | * without domain transition. | ||
245 | * (9) "users" is an atomic_t that holds how many "struct cred"->security | ||
246 | * are referring this "struct tomoyo_domain_info". If is_deleted == true | ||
247 | * and users == 0, this struct will be kfree()d upon next garbage | ||
248 | * collection. | ||
142 | * | 249 | * |
143 | * A domain's lifecycle is an analogy of files on / directory. | 250 | * A domain's lifecycle is an analogy of files on / directory. |
144 | * Multiple domains with the same domainname cannot be created (as with | 251 | * Multiple domains with the same domainname cannot be created (as with |
@@ -155,25 +262,13 @@ struct tomoyo_domain_info { | |||
155 | u8 profile; /* Profile number to use. */ | 262 | u8 profile; /* Profile number to use. */ |
156 | bool is_deleted; /* Delete flag. */ | 263 | bool is_deleted; /* Delete flag. */ |
157 | bool quota_warned; /* Quota warnning flag. */ | 264 | bool quota_warned; /* Quota warnning flag. */ |
158 | /* DOMAIN_FLAGS_*. Use tomoyo_set_domain_flag() to modify. */ | 265 | bool ignore_global_allow_read; /* Ignore "allow_read" flag. */ |
159 | u8 flags; | 266 | bool transition_failed; /* Domain transition failed flag. */ |
267 | atomic_t users; /* Number of referring credentials. */ | ||
160 | }; | 268 | }; |
161 | 269 | ||
162 | /* Profile number is an integer between 0 and 255. */ | ||
163 | #define TOMOYO_MAX_PROFILES 256 | ||
164 | |||
165 | /* Ignore "allow_read" directive in exception policy. */ | ||
166 | #define TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ 1 | ||
167 | /* | ||
168 | * This domain was unable to create a new domain at tomoyo_find_next_domain() | ||
169 | * because the name of the domain to be created was too long or | ||
170 | * it could not allocate memory. | ||
171 | * More than one process continued execve() without domain transition. | ||
172 | */ | ||
173 | #define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED 2 | ||
174 | |||
175 | /* | 270 | /* |
176 | * tomoyo_single_path_acl_record is a structure which is used for holding an | 271 | * tomoyo_path_acl is a structure which is used for holding an |
177 | * entry with one pathname operation (e.g. open(), mkdir()). | 272 | * entry with one pathname operation (e.g. open(), mkdir()). |
178 | * It has following fields. | 273 | * It has following fields. |
179 | * | 274 | * |
@@ -184,18 +279,21 @@ struct tomoyo_domain_info { | |||
184 | * Directives held by this structure are "allow_read/write", "allow_execute", | 279 | * Directives held by this structure are "allow_read/write", "allow_execute", |
185 | * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir", | 280 | * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir", |
186 | * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock", | 281 | * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock", |
187 | * "allow_mkchar", "allow_truncate", "allow_symlink" and "allow_rewrite". | 282 | * "allow_mkchar", "allow_truncate", "allow_symlink", "allow_rewrite", |
283 | * "allow_chmod", "allow_chown", "allow_chgrp", "allow_chroot", "allow_mount" | ||
284 | * and "allow_unmount". | ||
188 | */ | 285 | */ |
189 | struct tomoyo_single_path_acl_record { | 286 | struct tomoyo_path_acl { |
190 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */ | 287 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */ |
288 | u8 perm_high; | ||
191 | u16 perm; | 289 | u16 perm; |
192 | /* Pointer to single pathname. */ | 290 | /* Pointer to single pathname. */ |
193 | const struct tomoyo_path_info *filename; | 291 | const struct tomoyo_path_info *filename; |
194 | }; | 292 | }; |
195 | 293 | ||
196 | /* | 294 | /* |
197 | * tomoyo_double_path_acl_record is a structure which is used for holding an | 295 | * tomoyo_path2_acl is a structure which is used for holding an |
198 | * entry with two pathnames operation (i.e. link() and rename()). | 296 | * entry with two pathnames operation (i.e. link(), rename() and pivot_root()). |
199 | * It has following fields. | 297 | * It has following fields. |
200 | * | 298 | * |
201 | * (1) "head" which is a "struct tomoyo_acl_info". | 299 | * (1) "head" which is a "struct tomoyo_acl_info". |
@@ -203,10 +301,11 @@ struct tomoyo_single_path_acl_record { | |||
203 | * (3) "filename1" is the source/old pathname. | 301 | * (3) "filename1" is the source/old pathname. |
204 | * (4) "filename2" is the destination/new pathname. | 302 | * (4) "filename2" is the destination/new pathname. |
205 | * | 303 | * |
206 | * Directives held by this structure are "allow_rename" and "allow_link". | 304 | * Directives held by this structure are "allow_rename", "allow_link" and |
305 | * "allow_pivot_root". | ||
207 | */ | 306 | */ |
208 | struct tomoyo_double_path_acl_record { | 307 | struct tomoyo_path2_acl { |
209 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */ | 308 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH2_ACL */ |
210 | u8 perm; | 309 | u8 perm; |
211 | /* Pointer to single pathname. */ | 310 | /* Pointer to single pathname. */ |
212 | const struct tomoyo_path_info *filename1; | 311 | const struct tomoyo_path_info *filename1; |
@@ -214,29 +313,6 @@ struct tomoyo_double_path_acl_record { | |||
214 | const struct tomoyo_path_info *filename2; | 313 | const struct tomoyo_path_info *filename2; |
215 | }; | 314 | }; |
216 | 315 | ||
217 | /* Keywords for ACLs. */ | ||
218 | #define TOMOYO_KEYWORD_ALIAS "alias " | ||
219 | #define TOMOYO_KEYWORD_ALLOW_READ "allow_read " | ||
220 | #define TOMOYO_KEYWORD_DELETE "delete " | ||
221 | #define TOMOYO_KEYWORD_DENY_REWRITE "deny_rewrite " | ||
222 | #define TOMOYO_KEYWORD_FILE_PATTERN "file_pattern " | ||
223 | #define TOMOYO_KEYWORD_INITIALIZE_DOMAIN "initialize_domain " | ||
224 | #define TOMOYO_KEYWORD_KEEP_DOMAIN "keep_domain " | ||
225 | #define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_domain " | ||
226 | #define TOMOYO_KEYWORD_NO_KEEP_DOMAIN "no_keep_domain " | ||
227 | #define TOMOYO_KEYWORD_SELECT "select " | ||
228 | #define TOMOYO_KEYWORD_USE_PROFILE "use_profile " | ||
229 | #define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read" | ||
230 | /* A domain definition starts with <kernel>. */ | ||
231 | #define TOMOYO_ROOT_NAME "<kernel>" | ||
232 | #define TOMOYO_ROOT_NAME_LEN (sizeof(TOMOYO_ROOT_NAME) - 1) | ||
233 | |||
234 | /* Index numbers for Access Controls. */ | ||
235 | #define TOMOYO_MAC_FOR_FILE 0 /* domain_policy.conf */ | ||
236 | #define TOMOYO_MAX_ACCEPT_ENTRY 1 | ||
237 | #define TOMOYO_VERBOSE 2 | ||
238 | #define TOMOYO_MAX_CONTROL_INDEX 3 | ||
239 | |||
240 | /* | 316 | /* |
241 | * tomoyo_io_buffer is a structure which is used for reading and modifying | 317 | * tomoyo_io_buffer is a structure which is used for reading and modifying |
242 | * configuration via /sys/kernel/security/tomoyo/ interface. | 318 | * configuration via /sys/kernel/security/tomoyo/ interface. |
@@ -265,6 +341,8 @@ struct tomoyo_io_buffer { | |||
265 | int (*write) (struct tomoyo_io_buffer *); | 341 | int (*write) (struct tomoyo_io_buffer *); |
266 | /* Exclusive lock for this structure. */ | 342 | /* Exclusive lock for this structure. */ |
267 | struct mutex io_sem; | 343 | struct mutex io_sem; |
344 | /* Index returned by tomoyo_read_lock(). */ | ||
345 | int reader_idx; | ||
268 | /* The position currently reading from. */ | 346 | /* The position currently reading from. */ |
269 | struct list_head *read_var1; | 347 | struct list_head *read_var1; |
270 | /* Extra variables for reading. */ | 348 | /* Extra variables for reading. */ |
@@ -293,18 +371,159 @@ struct tomoyo_io_buffer { | |||
293 | int writebuf_size; | 371 | int writebuf_size; |
294 | }; | 372 | }; |
295 | 373 | ||
374 | /* | ||
375 | * tomoyo_globally_readable_file_entry is a structure which is used for holding | ||
376 | * "allow_read" entries. | ||
377 | * It has following fields. | ||
378 | * | ||
379 | * (1) "list" which is linked to tomoyo_globally_readable_list . | ||
380 | * (2) "filename" is a pathname which is allowed to open(O_RDONLY). | ||
381 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
382 | * otherwise. | ||
383 | */ | ||
384 | struct tomoyo_globally_readable_file_entry { | ||
385 | struct list_head list; | ||
386 | const struct tomoyo_path_info *filename; | ||
387 | bool is_deleted; | ||
388 | }; | ||
389 | |||
390 | /* | ||
391 | * tomoyo_pattern_entry is a structure which is used for holding | ||
392 | * "tomoyo_pattern_list" entries. | ||
393 | * It has following fields. | ||
394 | * | ||
395 | * (1) "list" which is linked to tomoyo_pattern_list . | ||
396 | * (2) "pattern" is a pathname pattern which is used for converting pathnames | ||
397 | * to pathname patterns during learning mode. | ||
398 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
399 | * otherwise. | ||
400 | */ | ||
401 | struct tomoyo_pattern_entry { | ||
402 | struct list_head list; | ||
403 | const struct tomoyo_path_info *pattern; | ||
404 | bool is_deleted; | ||
405 | }; | ||
406 | |||
407 | /* | ||
408 | * tomoyo_no_rewrite_entry is a structure which is used for holding | ||
409 | * "deny_rewrite" entries. | ||
410 | * It has following fields. | ||
411 | * | ||
412 | * (1) "list" which is linked to tomoyo_no_rewrite_list . | ||
413 | * (2) "pattern" is a pathname which is by default not permitted to modify | ||
414 | * already existing content. | ||
415 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
416 | * otherwise. | ||
417 | */ | ||
418 | struct tomoyo_no_rewrite_entry { | ||
419 | struct list_head list; | ||
420 | const struct tomoyo_path_info *pattern; | ||
421 | bool is_deleted; | ||
422 | }; | ||
423 | |||
424 | /* | ||
425 | * tomoyo_domain_initializer_entry is a structure which is used for holding | ||
426 | * "initialize_domain" and "no_initialize_domain" entries. | ||
427 | * It has following fields. | ||
428 | * | ||
429 | * (1) "list" which is linked to tomoyo_domain_initializer_list . | ||
430 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
431 | * domainname". This field is NULL if "from" clause is not specified. | ||
432 | * (3) "program" which is a program's pathname. | ||
433 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
434 | * otherwise. | ||
435 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
436 | * otherwise. | ||
437 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
438 | * component of a domainname", false otherwise. | ||
439 | */ | ||
440 | struct tomoyo_domain_initializer_entry { | ||
441 | struct list_head list; | ||
442 | const struct tomoyo_path_info *domainname; /* This may be NULL */ | ||
443 | const struct tomoyo_path_info *program; | ||
444 | bool is_deleted; | ||
445 | bool is_not; /* True if this entry is "no_initialize_domain". */ | ||
446 | /* True if the domainname is tomoyo_get_last_name(). */ | ||
447 | bool is_last_name; | ||
448 | }; | ||
449 | |||
450 | /* | ||
451 | * tomoyo_domain_keeper_entry is a structure which is used for holding | ||
452 | * "keep_domain" and "no_keep_domain" entries. | ||
453 | * It has following fields. | ||
454 | * | ||
455 | * (1) "list" which is linked to tomoyo_domain_keeper_list . | ||
456 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
457 | * domainname". | ||
458 | * (3) "program" which is a program's pathname. | ||
459 | * This field is NULL if "from" clause is not specified. | ||
460 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
461 | * otherwise. | ||
462 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
463 | * otherwise. | ||
464 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
465 | * component of a domainname", false otherwise. | ||
466 | */ | ||
467 | struct tomoyo_domain_keeper_entry { | ||
468 | struct list_head list; | ||
469 | const struct tomoyo_path_info *domainname; | ||
470 | const struct tomoyo_path_info *program; /* This may be NULL */ | ||
471 | bool is_deleted; | ||
472 | bool is_not; /* True if this entry is "no_keep_domain". */ | ||
473 | /* True if the domainname is tomoyo_get_last_name(). */ | ||
474 | bool is_last_name; | ||
475 | }; | ||
476 | |||
477 | /* | ||
478 | * tomoyo_alias_entry is a structure which is used for holding "alias" entries. | ||
479 | * It has following fields. | ||
480 | * | ||
481 | * (1) "list" which is linked to tomoyo_alias_list . | ||
482 | * (2) "original_name" which is a dereferenced pathname. | ||
483 | * (3) "aliased_name" which is a symlink's pathname. | ||
484 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
485 | * otherwise. | ||
486 | */ | ||
487 | struct tomoyo_alias_entry { | ||
488 | struct list_head list; | ||
489 | const struct tomoyo_path_info *original_name; | ||
490 | const struct tomoyo_path_info *aliased_name; | ||
491 | bool is_deleted; | ||
492 | }; | ||
493 | |||
494 | /* | ||
495 | * tomoyo_policy_manager_entry is a structure which is used for holding list of | ||
496 | * domainnames or programs which are permitted to modify configuration via | ||
497 | * /sys/kernel/security/tomoyo/ interface. | ||
498 | * It has following fields. | ||
499 | * | ||
500 | * (1) "list" which is linked to tomoyo_policy_manager_list . | ||
501 | * (2) "manager" is a domainname or a program's pathname. | ||
502 | * (3) "is_domain" is a bool which is true if "manager" is a domainname, false | ||
503 | * otherwise. | ||
504 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
505 | * otherwise. | ||
506 | */ | ||
507 | struct tomoyo_policy_manager_entry { | ||
508 | struct list_head list; | ||
509 | /* A path to program or a domainname. */ | ||
510 | const struct tomoyo_path_info *manager; | ||
511 | bool is_domain; /* True if manager is a domainname. */ | ||
512 | bool is_deleted; /* True if this entry is deleted. */ | ||
513 | }; | ||
514 | |||
515 | /********** Function prototypes. **********/ | ||
516 | |||
296 | /* Check whether the domain has too many ACL entries to hold. */ | 517 | /* Check whether the domain has too many ACL entries to hold. */ |
297 | bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain); | 518 | bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain); |
298 | /* Transactional sprintf() for policy dump. */ | 519 | /* Transactional sprintf() for policy dump. */ |
299 | bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | 520 | bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) |
300 | __attribute__ ((format(printf, 2, 3))); | 521 | __attribute__ ((format(printf, 2, 3))); |
301 | /* Check whether the domainname is correct. */ | 522 | /* Check whether the domainname is correct. */ |
302 | bool tomoyo_is_correct_domain(const unsigned char *domainname, | 523 | bool tomoyo_is_correct_domain(const unsigned char *domainname); |
303 | const char *function); | ||
304 | /* Check whether the token is correct. */ | 524 | /* Check whether the token is correct. */ |
305 | bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | 525 | bool tomoyo_is_correct_path(const char *filename, const s8 start_type, |
306 | const s8 pattern_type, const s8 end_type, | 526 | const s8 pattern_type, const s8 end_type); |
307 | const char *function); | ||
308 | /* Check whether the token can be a domainname. */ | 527 | /* Check whether the token can be a domainname. */ |
309 | bool tomoyo_is_domain_def(const unsigned char *buffer); | 528 | bool tomoyo_is_domain_def(const unsigned char *buffer); |
310 | /* Check whether the given filename matches the given pattern. */ | 529 | /* Check whether the given filename matches the given pattern. */ |
@@ -328,13 +547,13 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head); | |||
328 | /* Write domain policy violation warning message to console? */ | 547 | /* Write domain policy violation warning message to console? */ |
329 | bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain); | 548 | bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain); |
330 | /* Convert double path operation to operation name. */ | 549 | /* Convert double path operation to operation name. */ |
331 | const char *tomoyo_dp2keyword(const u8 operation); | 550 | const char *tomoyo_path22keyword(const u8 operation); |
332 | /* Get the last component of the given domainname. */ | 551 | /* Get the last component of the given domainname. */ |
333 | const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain); | 552 | const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain); |
334 | /* Get warning message. */ | 553 | /* Get warning message. */ |
335 | const char *tomoyo_get_msg(const bool is_enforce); | 554 | const char *tomoyo_get_msg(const bool is_enforce); |
336 | /* Convert single path operation to operation name. */ | 555 | /* Convert single path operation to operation name. */ |
337 | const char *tomoyo_sp2keyword(const u8 operation); | 556 | const char *tomoyo_path2keyword(const u8 operation); |
338 | /* Create "alias" entry in exception policy. */ | 557 | /* Create "alias" entry in exception policy. */ |
339 | int tomoyo_write_alias_policy(char *data, const bool is_delete); | 558 | int tomoyo_write_alias_policy(char *data, const bool is_delete); |
340 | /* | 559 | /* |
@@ -370,33 +589,107 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
370 | /* Check mode for specified functionality. */ | 589 | /* Check mode for specified functionality. */ |
371 | unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, | 590 | unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, |
372 | const u8 index); | 591 | const u8 index); |
373 | /* Allocate memory for structures. */ | ||
374 | void *tomoyo_alloc_acl_element(const u8 acl_type); | ||
375 | /* Fill in "struct tomoyo_path_info" members. */ | 592 | /* Fill in "struct tomoyo_path_info" members. */ |
376 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); | 593 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); |
377 | /* Run policy loader when /sbin/init starts. */ | 594 | /* Run policy loader when /sbin/init starts. */ |
378 | void tomoyo_load_policy(const char *filename); | 595 | void tomoyo_load_policy(const char *filename); |
379 | /* Change "struct tomoyo_domain_info"->flags. */ | ||
380 | void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain, | ||
381 | const bool is_delete, const u8 flags); | ||
382 | 596 | ||
383 | /* strcmp() for "struct tomoyo_path_info" structure. */ | 597 | /* Convert binary string to ascii string. */ |
384 | static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a, | 598 | int tomoyo_encode(char *buffer, int buflen, const char *str); |
385 | const struct tomoyo_path_info *b) | 599 | |
600 | /* Returns realpath(3) of the given pathname but ignores chroot'ed root. */ | ||
601 | int tomoyo_realpath_from_path2(struct path *path, char *newname, | ||
602 | int newname_len); | ||
603 | |||
604 | /* | ||
605 | * Returns realpath(3) of the given pathname but ignores chroot'ed root. | ||
606 | * These functions use kzalloc(), so the caller must call kfree() | ||
607 | * if these functions didn't return NULL. | ||
608 | */ | ||
609 | char *tomoyo_realpath(const char *pathname); | ||
610 | /* | ||
611 | * Same with tomoyo_realpath() except that it doesn't follow the final symlink. | ||
612 | */ | ||
613 | char *tomoyo_realpath_nofollow(const char *pathname); | ||
614 | /* Same with tomoyo_realpath() except that the pathname is already solved. */ | ||
615 | char *tomoyo_realpath_from_path(struct path *path); | ||
616 | |||
617 | /* Check memory quota. */ | ||
618 | bool tomoyo_memory_ok(void *ptr); | ||
619 | |||
620 | /* | ||
621 | * Keep the given name on the RAM. | ||
622 | * The RAM is shared, so NEVER try to modify or kfree() the returned name. | ||
623 | */ | ||
624 | const struct tomoyo_path_info *tomoyo_get_name(const char *name); | ||
625 | |||
626 | /* Check for memory usage. */ | ||
627 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head); | ||
628 | |||
629 | /* Set memory quota. */ | ||
630 | int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head); | ||
631 | |||
632 | /* Initialize realpath related code. */ | ||
633 | void __init tomoyo_realpath_init(void); | ||
634 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, | ||
635 | const struct tomoyo_path_info *filename); | ||
636 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | ||
637 | struct path *path, const int flag); | ||
638 | int tomoyo_path_perm(const u8 operation, struct path *path); | ||
639 | int tomoyo_path2_perm(const u8 operation, struct path *path1, | ||
640 | struct path *path2); | ||
641 | int tomoyo_check_rewrite_permission(struct file *filp); | ||
642 | int tomoyo_find_next_domain(struct linux_binprm *bprm); | ||
643 | |||
644 | /* Run garbage collector. */ | ||
645 | void tomoyo_run_gc(void); | ||
646 | |||
647 | void tomoyo_memory_free(void *ptr); | ||
648 | |||
649 | /********** External variable definitions. **********/ | ||
650 | |||
651 | /* Lock for GC. */ | ||
652 | extern struct srcu_struct tomoyo_ss; | ||
653 | |||
654 | /* The list for "struct tomoyo_domain_info". */ | ||
655 | extern struct list_head tomoyo_domain_list; | ||
656 | |||
657 | extern struct list_head tomoyo_domain_initializer_list; | ||
658 | extern struct list_head tomoyo_domain_keeper_list; | ||
659 | extern struct list_head tomoyo_alias_list; | ||
660 | extern struct list_head tomoyo_globally_readable_list; | ||
661 | extern struct list_head tomoyo_pattern_list; | ||
662 | extern struct list_head tomoyo_no_rewrite_list; | ||
663 | extern struct list_head tomoyo_policy_manager_list; | ||
664 | extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | ||
665 | extern struct mutex tomoyo_name_list_lock; | ||
666 | |||
667 | /* Lock for protecting policy. */ | ||
668 | extern struct mutex tomoyo_policy_lock; | ||
669 | |||
670 | /* Has /sbin/init started? */ | ||
671 | extern bool tomoyo_policy_loaded; | ||
672 | |||
673 | /* The kernel's domain. */ | ||
674 | extern struct tomoyo_domain_info tomoyo_kernel_domain; | ||
675 | |||
676 | /********** Inlined functions. **********/ | ||
677 | |||
678 | static inline int tomoyo_read_lock(void) | ||
386 | { | 679 | { |
387 | return a->hash != b->hash || strcmp(a->name, b->name); | 680 | return srcu_read_lock(&tomoyo_ss); |
388 | } | 681 | } |
389 | 682 | ||
390 | /* Get type of an ACL entry. */ | 683 | static inline void tomoyo_read_unlock(int idx) |
391 | static inline u8 tomoyo_acl_type1(struct tomoyo_acl_info *ptr) | ||
392 | { | 684 | { |
393 | return ptr->type & ~TOMOYO_ACL_DELETED; | 685 | srcu_read_unlock(&tomoyo_ss, idx); |
394 | } | 686 | } |
395 | 687 | ||
396 | /* Get type of an ACL entry. */ | 688 | /* strcmp() for "struct tomoyo_path_info" structure. */ |
397 | static inline u8 tomoyo_acl_type2(struct tomoyo_acl_info *ptr) | 689 | static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a, |
690 | const struct tomoyo_path_info *b) | ||
398 | { | 691 | { |
399 | return ptr->type; | 692 | return a->hash != b->hash || strcmp(a->name, b->name); |
400 | } | 693 | } |
401 | 694 | ||
402 | /** | 695 | /** |
@@ -423,18 +716,25 @@ static inline bool tomoyo_is_invalid(const unsigned char c) | |||
423 | return c && (c <= ' ' || c >= 127); | 716 | return c && (c <= ' ' || c >= 127); |
424 | } | 717 | } |
425 | 718 | ||
426 | /* The list for "struct tomoyo_domain_info". */ | 719 | static inline void tomoyo_put_name(const struct tomoyo_path_info *name) |
427 | extern struct list_head tomoyo_domain_list; | 720 | { |
428 | extern struct rw_semaphore tomoyo_domain_list_lock; | 721 | if (name) { |
429 | 722 | struct tomoyo_name_entry *ptr = | |
430 | /* Lock for domain->acl_info_list. */ | 723 | container_of(name, struct tomoyo_name_entry, entry); |
431 | extern struct rw_semaphore tomoyo_domain_acl_info_list_lock; | 724 | atomic_dec(&ptr->users); |
725 | } | ||
726 | } | ||
432 | 727 | ||
433 | /* Has /sbin/init started? */ | 728 | static inline struct tomoyo_domain_info *tomoyo_domain(void) |
434 | extern bool tomoyo_policy_loaded; | 729 | { |
730 | return current_cred()->security; | ||
731 | } | ||
435 | 732 | ||
436 | /* The kernel's domain. */ | 733 | static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct |
437 | extern struct tomoyo_domain_info tomoyo_kernel_domain; | 734 | *task) |
735 | { | ||
736 | return task_cred_xxx(task, security); | ||
737 | } | ||
438 | 738 | ||
439 | /** | 739 | /** |
440 | * list_for_each_cookie - iterate over a list with cookie. | 740 | * list_for_each_cookie - iterate over a list with cookie. |
@@ -442,16 +742,16 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain; | |||
442 | * @cookie: the &struct list_head to use as a cookie. | 742 | * @cookie: the &struct list_head to use as a cookie. |
443 | * @head: the head for your list. | 743 | * @head: the head for your list. |
444 | * | 744 | * |
445 | * Same with list_for_each() except that this primitive uses @cookie | 745 | * Same with list_for_each_rcu() except that this primitive uses @cookie |
446 | * so that we can continue iteration. | 746 | * so that we can continue iteration. |
447 | * @cookie must be NULL when iteration starts, and @cookie will become | 747 | * @cookie must be NULL when iteration starts, and @cookie will become |
448 | * NULL when iteration finishes. | 748 | * NULL when iteration finishes. |
449 | */ | 749 | */ |
450 | #define list_for_each_cookie(pos, cookie, head) \ | 750 | #define list_for_each_cookie(pos, cookie, head) \ |
451 | for (({ if (!cookie) \ | 751 | for (({ if (!cookie) \ |
452 | cookie = head; }), \ | 752 | cookie = head; }), \ |
453 | pos = (cookie)->next; \ | 753 | pos = rcu_dereference((cookie)->next); \ |
454 | prefetch(pos->next), pos != (head) || ((cookie) = NULL); \ | 754 | prefetch(pos->next), pos != (head) || ((cookie) = NULL); \ |
455 | (cookie) = pos, pos = pos->next) | 755 | (cookie) = pos, pos = rcu_dereference(pos->next)) |
456 | 756 | ||
457 | #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */ | 757 | #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */ |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index fcf52accce2b..66caaa1b842a 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -10,8 +10,6 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include "common.h" | 12 | #include "common.h" |
13 | #include "tomoyo.h" | ||
14 | #include "realpath.h" | ||
15 | #include <linux/binfmts.h> | 13 | #include <linux/binfmts.h> |
16 | 14 | ||
17 | /* Variables definitions.*/ | 15 | /* Variables definitions.*/ |
@@ -58,99 +56,6 @@ struct tomoyo_domain_info tomoyo_kernel_domain; | |||
58 | * exceptions. | 56 | * exceptions. |
59 | */ | 57 | */ |
60 | LIST_HEAD(tomoyo_domain_list); | 58 | LIST_HEAD(tomoyo_domain_list); |
61 | DECLARE_RWSEM(tomoyo_domain_list_lock); | ||
62 | |||
63 | /* | ||
64 | * tomoyo_domain_initializer_entry is a structure which is used for holding | ||
65 | * "initialize_domain" and "no_initialize_domain" entries. | ||
66 | * It has following fields. | ||
67 | * | ||
68 | * (1) "list" which is linked to tomoyo_domain_initializer_list . | ||
69 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
70 | * domainname". This field is NULL if "from" clause is not specified. | ||
71 | * (3) "program" which is a program's pathname. | ||
72 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
73 | * otherwise. | ||
74 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
75 | * otherwise. | ||
76 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
77 | * component of a domainname", false otherwise. | ||
78 | */ | ||
79 | struct tomoyo_domain_initializer_entry { | ||
80 | struct list_head list; | ||
81 | const struct tomoyo_path_info *domainname; /* This may be NULL */ | ||
82 | const struct tomoyo_path_info *program; | ||
83 | bool is_deleted; | ||
84 | bool is_not; /* True if this entry is "no_initialize_domain". */ | ||
85 | /* True if the domainname is tomoyo_get_last_name(). */ | ||
86 | bool is_last_name; | ||
87 | }; | ||
88 | |||
89 | /* | ||
90 | * tomoyo_domain_keeper_entry is a structure which is used for holding | ||
91 | * "keep_domain" and "no_keep_domain" entries. | ||
92 | * It has following fields. | ||
93 | * | ||
94 | * (1) "list" which is linked to tomoyo_domain_keeper_list . | ||
95 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
96 | * domainname". | ||
97 | * (3) "program" which is a program's pathname. | ||
98 | * This field is NULL if "from" clause is not specified. | ||
99 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
100 | * otherwise. | ||
101 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
102 | * otherwise. | ||
103 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
104 | * component of a domainname", false otherwise. | ||
105 | */ | ||
106 | struct tomoyo_domain_keeper_entry { | ||
107 | struct list_head list; | ||
108 | const struct tomoyo_path_info *domainname; | ||
109 | const struct tomoyo_path_info *program; /* This may be NULL */ | ||
110 | bool is_deleted; | ||
111 | bool is_not; /* True if this entry is "no_keep_domain". */ | ||
112 | /* True if the domainname is tomoyo_get_last_name(). */ | ||
113 | bool is_last_name; | ||
114 | }; | ||
115 | |||
116 | /* | ||
117 | * tomoyo_alias_entry is a structure which is used for holding "alias" entries. | ||
118 | * It has following fields. | ||
119 | * | ||
120 | * (1) "list" which is linked to tomoyo_alias_list . | ||
121 | * (2) "original_name" which is a dereferenced pathname. | ||
122 | * (3) "aliased_name" which is a symlink's pathname. | ||
123 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
124 | * otherwise. | ||
125 | */ | ||
126 | struct tomoyo_alias_entry { | ||
127 | struct list_head list; | ||
128 | const struct tomoyo_path_info *original_name; | ||
129 | const struct tomoyo_path_info *aliased_name; | ||
130 | bool is_deleted; | ||
131 | }; | ||
132 | |||
133 | /** | ||
134 | * tomoyo_set_domain_flag - Set or clear domain's attribute flags. | ||
135 | * | ||
136 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
137 | * @is_delete: True if it is a delete request. | ||
138 | * @flags: Flags to set or clear. | ||
139 | * | ||
140 | * Returns nothing. | ||
141 | */ | ||
142 | void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain, | ||
143 | const bool is_delete, const u8 flags) | ||
144 | { | ||
145 | /* We need to serialize because this is bitfield operation. */ | ||
146 | static DEFINE_SPINLOCK(lock); | ||
147 | spin_lock(&lock); | ||
148 | if (!is_delete) | ||
149 | domain->flags |= flags; | ||
150 | else | ||
151 | domain->flags &= ~flags; | ||
152 | spin_unlock(&lock); | ||
153 | } | ||
154 | 59 | ||
155 | /** | 60 | /** |
156 | * tomoyo_get_last_name - Get last component of a domainname. | 61 | * tomoyo_get_last_name - Get last component of a domainname. |
@@ -205,8 +110,7 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) | |||
205 | * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain | 110 | * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain |
206 | * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. | 111 | * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. |
207 | */ | 112 | */ |
208 | static LIST_HEAD(tomoyo_domain_initializer_list); | 113 | LIST_HEAD(tomoyo_domain_initializer_list); |
209 | static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); | ||
210 | 114 | ||
211 | /** | 115 | /** |
212 | * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. | 116 | * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. |
@@ -217,59 +121,65 @@ static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); | |||
217 | * @is_delete: True if it is a delete request. | 121 | * @is_delete: True if it is a delete request. |
218 | * | 122 | * |
219 | * Returns 0 on success, negative value otherwise. | 123 | * Returns 0 on success, negative value otherwise. |
124 | * | ||
125 | * Caller holds tomoyo_read_lock(). | ||
220 | */ | 126 | */ |
221 | static int tomoyo_update_domain_initializer_entry(const char *domainname, | 127 | static int tomoyo_update_domain_initializer_entry(const char *domainname, |
222 | const char *program, | 128 | const char *program, |
223 | const bool is_not, | 129 | const bool is_not, |
224 | const bool is_delete) | 130 | const bool is_delete) |
225 | { | 131 | { |
226 | struct tomoyo_domain_initializer_entry *new_entry; | 132 | struct tomoyo_domain_initializer_entry *entry = NULL; |
227 | struct tomoyo_domain_initializer_entry *ptr; | 133 | struct tomoyo_domain_initializer_entry *ptr; |
228 | const struct tomoyo_path_info *saved_program; | 134 | const struct tomoyo_path_info *saved_program = NULL; |
229 | const struct tomoyo_path_info *saved_domainname = NULL; | 135 | const struct tomoyo_path_info *saved_domainname = NULL; |
230 | int error = -ENOMEM; | 136 | int error = is_delete ? -ENOENT : -ENOMEM; |
231 | bool is_last_name = false; | 137 | bool is_last_name = false; |
232 | 138 | ||
233 | if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__)) | 139 | if (!tomoyo_is_correct_path(program, 1, -1, -1)) |
234 | return -EINVAL; /* No patterns allowed. */ | 140 | return -EINVAL; /* No patterns allowed. */ |
235 | if (domainname) { | 141 | if (domainname) { |
236 | if (!tomoyo_is_domain_def(domainname) && | 142 | if (!tomoyo_is_domain_def(domainname) && |
237 | tomoyo_is_correct_path(domainname, 1, -1, -1, __func__)) | 143 | tomoyo_is_correct_path(domainname, 1, -1, -1)) |
238 | is_last_name = true; | 144 | is_last_name = true; |
239 | else if (!tomoyo_is_correct_domain(domainname, __func__)) | 145 | else if (!tomoyo_is_correct_domain(domainname)) |
240 | return -EINVAL; | 146 | return -EINVAL; |
241 | saved_domainname = tomoyo_save_name(domainname); | 147 | saved_domainname = tomoyo_get_name(domainname); |
242 | if (!saved_domainname) | 148 | if (!saved_domainname) |
243 | return -ENOMEM; | 149 | goto out; |
244 | } | 150 | } |
245 | saved_program = tomoyo_save_name(program); | 151 | saved_program = tomoyo_get_name(program); |
246 | if (!saved_program) | 152 | if (!saved_program) |
247 | return -ENOMEM; | 153 | goto out; |
248 | down_write(&tomoyo_domain_initializer_list_lock); | 154 | if (!is_delete) |
249 | list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { | 155 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
156 | mutex_lock(&tomoyo_policy_lock); | ||
157 | list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { | ||
250 | if (ptr->is_not != is_not || | 158 | if (ptr->is_not != is_not || |
251 | ptr->domainname != saved_domainname || | 159 | ptr->domainname != saved_domainname || |
252 | ptr->program != saved_program) | 160 | ptr->program != saved_program) |
253 | continue; | 161 | continue; |
254 | ptr->is_deleted = is_delete; | 162 | ptr->is_deleted = is_delete; |
255 | error = 0; | 163 | error = 0; |
256 | goto out; | 164 | break; |
257 | } | 165 | } |
258 | if (is_delete) { | 166 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
259 | error = -ENOENT; | 167 | entry->domainname = saved_domainname; |
260 | goto out; | 168 | saved_domainname = NULL; |
169 | entry->program = saved_program; | ||
170 | saved_program = NULL; | ||
171 | entry->is_not = is_not; | ||
172 | entry->is_last_name = is_last_name; | ||
173 | list_add_tail_rcu(&entry->list, | ||
174 | &tomoyo_domain_initializer_list); | ||
175 | entry = NULL; | ||
176 | error = 0; | ||
261 | } | 177 | } |
262 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 178 | mutex_unlock(&tomoyo_policy_lock); |
263 | if (!new_entry) | ||
264 | goto out; | ||
265 | new_entry->domainname = saved_domainname; | ||
266 | new_entry->program = saved_program; | ||
267 | new_entry->is_not = is_not; | ||
268 | new_entry->is_last_name = is_last_name; | ||
269 | list_add_tail(&new_entry->list, &tomoyo_domain_initializer_list); | ||
270 | error = 0; | ||
271 | out: | 179 | out: |
272 | up_write(&tomoyo_domain_initializer_list_lock); | 180 | tomoyo_put_name(saved_domainname); |
181 | tomoyo_put_name(saved_program); | ||
182 | kfree(entry); | ||
273 | return error; | 183 | return error; |
274 | } | 184 | } |
275 | 185 | ||
@@ -279,13 +189,14 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, | |||
279 | * @head: Pointer to "struct tomoyo_io_buffer". | 189 | * @head: Pointer to "struct tomoyo_io_buffer". |
280 | * | 190 | * |
281 | * Returns true on success, false otherwise. | 191 | * Returns true on success, false otherwise. |
192 | * | ||
193 | * Caller holds tomoyo_read_lock(). | ||
282 | */ | 194 | */ |
283 | bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) | 195 | bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) |
284 | { | 196 | { |
285 | struct list_head *pos; | 197 | struct list_head *pos; |
286 | bool done = true; | 198 | bool done = true; |
287 | 199 | ||
288 | down_read(&tomoyo_domain_initializer_list_lock); | ||
289 | list_for_each_cookie(pos, head->read_var2, | 200 | list_for_each_cookie(pos, head->read_var2, |
290 | &tomoyo_domain_initializer_list) { | 201 | &tomoyo_domain_initializer_list) { |
291 | const char *no; | 202 | const char *no; |
@@ -308,7 +219,6 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) | |||
308 | if (!done) | 219 | if (!done) |
309 | break; | 220 | break; |
310 | } | 221 | } |
311 | up_read(&tomoyo_domain_initializer_list_lock); | ||
312 | return done; | 222 | return done; |
313 | } | 223 | } |
314 | 224 | ||
@@ -320,6 +230,8 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) | |||
320 | * @is_delete: True if it is a delete request. | 230 | * @is_delete: True if it is a delete request. |
321 | * | 231 | * |
322 | * Returns 0 on success, negative value otherwise. | 232 | * Returns 0 on success, negative value otherwise. |
233 | * | ||
234 | * Caller holds tomoyo_read_lock(). | ||
323 | */ | 235 | */ |
324 | int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, | 236 | int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, |
325 | const bool is_delete) | 237 | const bool is_delete) |
@@ -345,6 +257,8 @@ int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, | |||
345 | * | 257 | * |
346 | * Returns true if executing @program reinitializes domain transition, | 258 | * Returns true if executing @program reinitializes domain transition, |
347 | * false otherwise. | 259 | * false otherwise. |
260 | * | ||
261 | * Caller holds tomoyo_read_lock(). | ||
348 | */ | 262 | */ |
349 | static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | 263 | static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * |
350 | domainname, | 264 | domainname, |
@@ -355,8 +269,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | |||
355 | struct tomoyo_domain_initializer_entry *ptr; | 269 | struct tomoyo_domain_initializer_entry *ptr; |
356 | bool flag = false; | 270 | bool flag = false; |
357 | 271 | ||
358 | down_read(&tomoyo_domain_initializer_list_lock); | 272 | list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { |
359 | list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { | ||
360 | if (ptr->is_deleted) | 273 | if (ptr->is_deleted) |
361 | continue; | 274 | continue; |
362 | if (ptr->domainname) { | 275 | if (ptr->domainname) { |
@@ -376,7 +289,6 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | |||
376 | } | 289 | } |
377 | flag = true; | 290 | flag = true; |
378 | } | 291 | } |
379 | up_read(&tomoyo_domain_initializer_list_lock); | ||
380 | return flag; | 292 | return flag; |
381 | } | 293 | } |
382 | 294 | ||
@@ -418,8 +330,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | |||
418 | * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless | 330 | * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless |
419 | * explicitly specified by "initialize_domain". | 331 | * explicitly specified by "initialize_domain". |
420 | */ | 332 | */ |
421 | static LIST_HEAD(tomoyo_domain_keeper_list); | 333 | LIST_HEAD(tomoyo_domain_keeper_list); |
422 | static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); | ||
423 | 334 | ||
424 | /** | 335 | /** |
425 | * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. | 336 | * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. |
@@ -430,59 +341,64 @@ static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); | |||
430 | * @is_delete: True if it is a delete request. | 341 | * @is_delete: True if it is a delete request. |
431 | * | 342 | * |
432 | * Returns 0 on success, negative value otherwise. | 343 | * Returns 0 on success, negative value otherwise. |
344 | * | ||
345 | * Caller holds tomoyo_read_lock(). | ||
433 | */ | 346 | */ |
434 | static int tomoyo_update_domain_keeper_entry(const char *domainname, | 347 | static int tomoyo_update_domain_keeper_entry(const char *domainname, |
435 | const char *program, | 348 | const char *program, |
436 | const bool is_not, | 349 | const bool is_not, |
437 | const bool is_delete) | 350 | const bool is_delete) |
438 | { | 351 | { |
439 | struct tomoyo_domain_keeper_entry *new_entry; | 352 | struct tomoyo_domain_keeper_entry *entry = NULL; |
440 | struct tomoyo_domain_keeper_entry *ptr; | 353 | struct tomoyo_domain_keeper_entry *ptr; |
441 | const struct tomoyo_path_info *saved_domainname; | 354 | const struct tomoyo_path_info *saved_domainname = NULL; |
442 | const struct tomoyo_path_info *saved_program = NULL; | 355 | const struct tomoyo_path_info *saved_program = NULL; |
443 | int error = -ENOMEM; | 356 | int error = is_delete ? -ENOENT : -ENOMEM; |
444 | bool is_last_name = false; | 357 | bool is_last_name = false; |
445 | 358 | ||
446 | if (!tomoyo_is_domain_def(domainname) && | 359 | if (!tomoyo_is_domain_def(domainname) && |
447 | tomoyo_is_correct_path(domainname, 1, -1, -1, __func__)) | 360 | tomoyo_is_correct_path(domainname, 1, -1, -1)) |
448 | is_last_name = true; | 361 | is_last_name = true; |
449 | else if (!tomoyo_is_correct_domain(domainname, __func__)) | 362 | else if (!tomoyo_is_correct_domain(domainname)) |
450 | return -EINVAL; | 363 | return -EINVAL; |
451 | if (program) { | 364 | if (program) { |
452 | if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__)) | 365 | if (!tomoyo_is_correct_path(program, 1, -1, -1)) |
453 | return -EINVAL; | 366 | return -EINVAL; |
454 | saved_program = tomoyo_save_name(program); | 367 | saved_program = tomoyo_get_name(program); |
455 | if (!saved_program) | 368 | if (!saved_program) |
456 | return -ENOMEM; | 369 | goto out; |
457 | } | 370 | } |
458 | saved_domainname = tomoyo_save_name(domainname); | 371 | saved_domainname = tomoyo_get_name(domainname); |
459 | if (!saved_domainname) | 372 | if (!saved_domainname) |
460 | return -ENOMEM; | 373 | goto out; |
461 | down_write(&tomoyo_domain_keeper_list_lock); | 374 | if (!is_delete) |
462 | list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { | 375 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
376 | mutex_lock(&tomoyo_policy_lock); | ||
377 | list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { | ||
463 | if (ptr->is_not != is_not || | 378 | if (ptr->is_not != is_not || |
464 | ptr->domainname != saved_domainname || | 379 | ptr->domainname != saved_domainname || |
465 | ptr->program != saved_program) | 380 | ptr->program != saved_program) |
466 | continue; | 381 | continue; |
467 | ptr->is_deleted = is_delete; | 382 | ptr->is_deleted = is_delete; |
468 | error = 0; | 383 | error = 0; |
469 | goto out; | 384 | break; |
470 | } | 385 | } |
471 | if (is_delete) { | 386 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
472 | error = -ENOENT; | 387 | entry->domainname = saved_domainname; |
473 | goto out; | 388 | saved_domainname = NULL; |
389 | entry->program = saved_program; | ||
390 | saved_program = NULL; | ||
391 | entry->is_not = is_not; | ||
392 | entry->is_last_name = is_last_name; | ||
393 | list_add_tail_rcu(&entry->list, &tomoyo_domain_keeper_list); | ||
394 | entry = NULL; | ||
395 | error = 0; | ||
474 | } | 396 | } |
475 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 397 | mutex_unlock(&tomoyo_policy_lock); |
476 | if (!new_entry) | ||
477 | goto out; | ||
478 | new_entry->domainname = saved_domainname; | ||
479 | new_entry->program = saved_program; | ||
480 | new_entry->is_not = is_not; | ||
481 | new_entry->is_last_name = is_last_name; | ||
482 | list_add_tail(&new_entry->list, &tomoyo_domain_keeper_list); | ||
483 | error = 0; | ||
484 | out: | 398 | out: |
485 | up_write(&tomoyo_domain_keeper_list_lock); | 399 | tomoyo_put_name(saved_domainname); |
400 | tomoyo_put_name(saved_program); | ||
401 | kfree(entry); | ||
486 | return error; | 402 | return error; |
487 | } | 403 | } |
488 | 404 | ||
@@ -493,6 +409,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, | |||
493 | * @is_not: True if it is "no_keep_domain" entry. | 409 | * @is_not: True if it is "no_keep_domain" entry. |
494 | * @is_delete: True if it is a delete request. | 410 | * @is_delete: True if it is a delete request. |
495 | * | 411 | * |
412 | * Caller holds tomoyo_read_lock(). | ||
496 | */ | 413 | */ |
497 | int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, | 414 | int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, |
498 | const bool is_delete) | 415 | const bool is_delete) |
@@ -513,13 +430,14 @@ int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, | |||
513 | * @head: Pointer to "struct tomoyo_io_buffer". | 430 | * @head: Pointer to "struct tomoyo_io_buffer". |
514 | * | 431 | * |
515 | * Returns true on success, false otherwise. | 432 | * Returns true on success, false otherwise. |
433 | * | ||
434 | * Caller holds tomoyo_read_lock(). | ||
516 | */ | 435 | */ |
517 | bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) | 436 | bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) |
518 | { | 437 | { |
519 | struct list_head *pos; | 438 | struct list_head *pos; |
520 | bool done = true; | 439 | bool done = true; |
521 | 440 | ||
522 | down_read(&tomoyo_domain_keeper_list_lock); | ||
523 | list_for_each_cookie(pos, head->read_var2, | 441 | list_for_each_cookie(pos, head->read_var2, |
524 | &tomoyo_domain_keeper_list) { | 442 | &tomoyo_domain_keeper_list) { |
525 | struct tomoyo_domain_keeper_entry *ptr; | 443 | struct tomoyo_domain_keeper_entry *ptr; |
@@ -542,7 +460,6 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) | |||
542 | if (!done) | 460 | if (!done) |
543 | break; | 461 | break; |
544 | } | 462 | } |
545 | up_read(&tomoyo_domain_keeper_list_lock); | ||
546 | return done; | 463 | return done; |
547 | } | 464 | } |
548 | 465 | ||
@@ -555,6 +472,8 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) | |||
555 | * | 472 | * |
556 | * Returns true if executing @program supresses domain transition, | 473 | * Returns true if executing @program supresses domain transition, |
557 | * false otherwise. | 474 | * false otherwise. |
475 | * | ||
476 | * Caller holds tomoyo_read_lock(). | ||
558 | */ | 477 | */ |
559 | static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | 478 | static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, |
560 | const struct tomoyo_path_info *program, | 479 | const struct tomoyo_path_info *program, |
@@ -563,8 +482,7 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | |||
563 | struct tomoyo_domain_keeper_entry *ptr; | 482 | struct tomoyo_domain_keeper_entry *ptr; |
564 | bool flag = false; | 483 | bool flag = false; |
565 | 484 | ||
566 | down_read(&tomoyo_domain_keeper_list_lock); | 485 | list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { |
567 | list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { | ||
568 | if (ptr->is_deleted) | 486 | if (ptr->is_deleted) |
569 | continue; | 487 | continue; |
570 | if (!ptr->is_last_name) { | 488 | if (!ptr->is_last_name) { |
@@ -582,7 +500,6 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | |||
582 | } | 500 | } |
583 | flag = true; | 501 | flag = true; |
584 | } | 502 | } |
585 | up_read(&tomoyo_domain_keeper_list_lock); | ||
586 | return flag; | 503 | return flag; |
587 | } | 504 | } |
588 | 505 | ||
@@ -616,8 +533,7 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | |||
616 | * /bin/busybox and domainname which the current process will belong to after | 533 | * /bin/busybox and domainname which the current process will belong to after |
617 | * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . | 534 | * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . |
618 | */ | 535 | */ |
619 | static LIST_HEAD(tomoyo_alias_list); | 536 | LIST_HEAD(tomoyo_alias_list); |
620 | static DECLARE_RWSEM(tomoyo_alias_list_lock); | ||
621 | 537 | ||
622 | /** | 538 | /** |
623 | * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. | 539 | * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. |
@@ -627,46 +543,51 @@ static DECLARE_RWSEM(tomoyo_alias_list_lock); | |||
627 | * @is_delete: True if it is a delete request. | 543 | * @is_delete: True if it is a delete request. |
628 | * | 544 | * |
629 | * Returns 0 on success, negative value otherwise. | 545 | * Returns 0 on success, negative value otherwise. |
546 | * | ||
547 | * Caller holds tomoyo_read_lock(). | ||
630 | */ | 548 | */ |
631 | static int tomoyo_update_alias_entry(const char *original_name, | 549 | static int tomoyo_update_alias_entry(const char *original_name, |
632 | const char *aliased_name, | 550 | const char *aliased_name, |
633 | const bool is_delete) | 551 | const bool is_delete) |
634 | { | 552 | { |
635 | struct tomoyo_alias_entry *new_entry; | 553 | struct tomoyo_alias_entry *entry = NULL; |
636 | struct tomoyo_alias_entry *ptr; | 554 | struct tomoyo_alias_entry *ptr; |
637 | const struct tomoyo_path_info *saved_original_name; | 555 | const struct tomoyo_path_info *saved_original_name; |
638 | const struct tomoyo_path_info *saved_aliased_name; | 556 | const struct tomoyo_path_info *saved_aliased_name; |
639 | int error = -ENOMEM; | 557 | int error = is_delete ? -ENOENT : -ENOMEM; |
640 | 558 | ||
641 | if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) || | 559 | if (!tomoyo_is_correct_path(original_name, 1, -1, -1) || |
642 | !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__)) | 560 | !tomoyo_is_correct_path(aliased_name, 1, -1, -1)) |
643 | return -EINVAL; /* No patterns allowed. */ | 561 | return -EINVAL; /* No patterns allowed. */ |
644 | saved_original_name = tomoyo_save_name(original_name); | 562 | saved_original_name = tomoyo_get_name(original_name); |
645 | saved_aliased_name = tomoyo_save_name(aliased_name); | 563 | saved_aliased_name = tomoyo_get_name(aliased_name); |
646 | if (!saved_original_name || !saved_aliased_name) | 564 | if (!saved_original_name || !saved_aliased_name) |
647 | return -ENOMEM; | 565 | goto out; |
648 | down_write(&tomoyo_alias_list_lock); | 566 | if (!is_delete) |
649 | list_for_each_entry(ptr, &tomoyo_alias_list, list) { | 567 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
568 | mutex_lock(&tomoyo_policy_lock); | ||
569 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { | ||
650 | if (ptr->original_name != saved_original_name || | 570 | if (ptr->original_name != saved_original_name || |
651 | ptr->aliased_name != saved_aliased_name) | 571 | ptr->aliased_name != saved_aliased_name) |
652 | continue; | 572 | continue; |
653 | ptr->is_deleted = is_delete; | 573 | ptr->is_deleted = is_delete; |
654 | error = 0; | 574 | error = 0; |
655 | goto out; | 575 | break; |
656 | } | 576 | } |
657 | if (is_delete) { | 577 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
658 | error = -ENOENT; | 578 | entry->original_name = saved_original_name; |
659 | goto out; | 579 | saved_original_name = NULL; |
580 | entry->aliased_name = saved_aliased_name; | ||
581 | saved_aliased_name = NULL; | ||
582 | list_add_tail_rcu(&entry->list, &tomoyo_alias_list); | ||
583 | entry = NULL; | ||
584 | error = 0; | ||
660 | } | 585 | } |
661 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 586 | mutex_unlock(&tomoyo_policy_lock); |
662 | if (!new_entry) | ||
663 | goto out; | ||
664 | new_entry->original_name = saved_original_name; | ||
665 | new_entry->aliased_name = saved_aliased_name; | ||
666 | list_add_tail(&new_entry->list, &tomoyo_alias_list); | ||
667 | error = 0; | ||
668 | out: | 587 | out: |
669 | up_write(&tomoyo_alias_list_lock); | 588 | tomoyo_put_name(saved_original_name); |
589 | tomoyo_put_name(saved_aliased_name); | ||
590 | kfree(entry); | ||
670 | return error; | 591 | return error; |
671 | } | 592 | } |
672 | 593 | ||
@@ -676,13 +597,14 @@ static int tomoyo_update_alias_entry(const char *original_name, | |||
676 | * @head: Pointer to "struct tomoyo_io_buffer". | 597 | * @head: Pointer to "struct tomoyo_io_buffer". |
677 | * | 598 | * |
678 | * Returns true on success, false otherwise. | 599 | * Returns true on success, false otherwise. |
600 | * | ||
601 | * Caller holds tomoyo_read_lock(). | ||
679 | */ | 602 | */ |
680 | bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) | 603 | bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) |
681 | { | 604 | { |
682 | struct list_head *pos; | 605 | struct list_head *pos; |
683 | bool done = true; | 606 | bool done = true; |
684 | 607 | ||
685 | down_read(&tomoyo_alias_list_lock); | ||
686 | list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) { | 608 | list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) { |
687 | struct tomoyo_alias_entry *ptr; | 609 | struct tomoyo_alias_entry *ptr; |
688 | 610 | ||
@@ -695,7 +617,6 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) | |||
695 | if (!done) | 617 | if (!done) |
696 | break; | 618 | break; |
697 | } | 619 | } |
698 | up_read(&tomoyo_alias_list_lock); | ||
699 | return done; | 620 | return done; |
700 | } | 621 | } |
701 | 622 | ||
@@ -706,6 +627,8 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) | |||
706 | * @is_delete: True if it is a delete request. | 627 | * @is_delete: True if it is a delete request. |
707 | * | 628 | * |
708 | * Returns 0 on success, negative value otherwise. | 629 | * Returns 0 on success, negative value otherwise. |
630 | * | ||
631 | * Caller holds tomoyo_read_lock(). | ||
709 | */ | 632 | */ |
710 | int tomoyo_write_alias_policy(char *data, const bool is_delete) | 633 | int tomoyo_write_alias_policy(char *data, const bool is_delete) |
711 | { | 634 | { |
@@ -724,63 +647,46 @@ int tomoyo_write_alias_policy(char *data, const bool is_delete) | |||
724 | * @profile: Profile number to assign if the domain was newly created. | 647 | * @profile: Profile number to assign if the domain was newly created. |
725 | * | 648 | * |
726 | * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. | 649 | * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. |
650 | * | ||
651 | * Caller holds tomoyo_read_lock(). | ||
727 | */ | 652 | */ |
728 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | 653 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * |
729 | domainname, | 654 | domainname, |
730 | const u8 profile) | 655 | const u8 profile) |
731 | { | 656 | { |
732 | struct tomoyo_domain_info *domain = NULL; | 657 | struct tomoyo_domain_info *entry; |
658 | struct tomoyo_domain_info *domain; | ||
733 | const struct tomoyo_path_info *saved_domainname; | 659 | const struct tomoyo_path_info *saved_domainname; |
660 | bool found = false; | ||
734 | 661 | ||
735 | down_write(&tomoyo_domain_list_lock); | 662 | if (!tomoyo_is_correct_domain(domainname)) |
736 | domain = tomoyo_find_domain(domainname); | 663 | return NULL; |
737 | if (domain) | 664 | saved_domainname = tomoyo_get_name(domainname); |
738 | goto out; | ||
739 | if (!tomoyo_is_correct_domain(domainname, __func__)) | ||
740 | goto out; | ||
741 | saved_domainname = tomoyo_save_name(domainname); | ||
742 | if (!saved_domainname) | 665 | if (!saved_domainname) |
743 | goto out; | 666 | return NULL; |
744 | /* Can I reuse memory of deleted domain? */ | 667 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
745 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | 668 | mutex_lock(&tomoyo_policy_lock); |
746 | struct task_struct *p; | 669 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
747 | struct tomoyo_acl_info *ptr; | 670 | if (domain->is_deleted || |
748 | bool flag; | 671 | tomoyo_pathcmp(saved_domainname, domain->domainname)) |
749 | if (!domain->is_deleted || | ||
750 | domain->domainname != saved_domainname) | ||
751 | continue; | 672 | continue; |
752 | flag = false; | 673 | found = true; |
753 | read_lock(&tasklist_lock); | 674 | break; |
754 | for_each_process(p) { | ||
755 | if (tomoyo_real_domain(p) != domain) | ||
756 | continue; | ||
757 | flag = true; | ||
758 | break; | ||
759 | } | ||
760 | read_unlock(&tasklist_lock); | ||
761 | if (flag) | ||
762 | continue; | ||
763 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | ||
764 | ptr->type |= TOMOYO_ACL_DELETED; | ||
765 | } | ||
766 | tomoyo_set_domain_flag(domain, true, domain->flags); | ||
767 | domain->profile = profile; | ||
768 | domain->quota_warned = false; | ||
769 | mb(); /* Avoid out-of-order execution. */ | ||
770 | domain->is_deleted = false; | ||
771 | goto out; | ||
772 | } | 675 | } |
773 | /* No memory reusable. Create using new memory. */ | 676 | if (!found && tomoyo_memory_ok(entry)) { |
774 | domain = tomoyo_alloc_element(sizeof(*domain)); | 677 | INIT_LIST_HEAD(&entry->acl_info_list); |
775 | if (domain) { | 678 | entry->domainname = saved_domainname; |
776 | INIT_LIST_HEAD(&domain->acl_info_list); | 679 | saved_domainname = NULL; |
777 | domain->domainname = saved_domainname; | 680 | entry->profile = profile; |
778 | domain->profile = profile; | 681 | list_add_tail_rcu(&entry->list, &tomoyo_domain_list); |
779 | list_add_tail(&domain->list, &tomoyo_domain_list); | 682 | domain = entry; |
683 | entry = NULL; | ||
684 | found = true; | ||
780 | } | 685 | } |
781 | out: | 686 | mutex_unlock(&tomoyo_policy_lock); |
782 | up_write(&tomoyo_domain_list_lock); | 687 | tomoyo_put_name(saved_domainname); |
783 | return domain; | 688 | kfree(entry); |
689 | return found ? domain : NULL; | ||
784 | } | 690 | } |
785 | 691 | ||
786 | /** | 692 | /** |
@@ -789,6 +695,8 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
789 | * @bprm: Pointer to "struct linux_binprm". | 695 | * @bprm: Pointer to "struct linux_binprm". |
790 | * | 696 | * |
791 | * Returns 0 on success, negative value otherwise. | 697 | * Returns 0 on success, negative value otherwise. |
698 | * | ||
699 | * Caller holds tomoyo_read_lock(). | ||
792 | */ | 700 | */ |
793 | int tomoyo_find_next_domain(struct linux_binprm *bprm) | 701 | int tomoyo_find_next_domain(struct linux_binprm *bprm) |
794 | { | 702 | { |
@@ -796,7 +704,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
796 | * This function assumes that the size of buffer returned by | 704 | * This function assumes that the size of buffer returned by |
797 | * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. | 705 | * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. |
798 | */ | 706 | */ |
799 | struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp)); | 707 | struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); |
800 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); | 708 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); |
801 | struct tomoyo_domain_info *domain = NULL; | 709 | struct tomoyo_domain_info *domain = NULL; |
802 | const char *old_domain_name = old_domain->domainname->name; | 710 | const char *old_domain_name = old_domain->domainname->name; |
@@ -849,8 +757,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
849 | if (tomoyo_pathcmp(&r, &s)) { | 757 | if (tomoyo_pathcmp(&r, &s)) { |
850 | struct tomoyo_alias_entry *ptr; | 758 | struct tomoyo_alias_entry *ptr; |
851 | /* Is this program allowed to be called via symbolic links? */ | 759 | /* Is this program allowed to be called via symbolic links? */ |
852 | down_read(&tomoyo_alias_list_lock); | 760 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { |
853 | list_for_each_entry(ptr, &tomoyo_alias_list, list) { | ||
854 | if (ptr->is_deleted || | 761 | if (ptr->is_deleted || |
855 | tomoyo_pathcmp(&r, ptr->original_name) || | 762 | tomoyo_pathcmp(&r, ptr->original_name) || |
856 | tomoyo_pathcmp(&s, ptr->aliased_name)) | 763 | tomoyo_pathcmp(&s, ptr->aliased_name)) |
@@ -861,7 +768,6 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
861 | tomoyo_fill_path_info(&r); | 768 | tomoyo_fill_path_info(&r); |
862 | break; | 769 | break; |
863 | } | 770 | } |
864 | up_read(&tomoyo_alias_list_lock); | ||
865 | } | 771 | } |
866 | 772 | ||
867 | /* Check execute permission. */ | 773 | /* Check execute permission. */ |
@@ -892,9 +798,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
892 | } | 798 | } |
893 | if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN) | 799 | if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN) |
894 | goto done; | 800 | goto done; |
895 | down_read(&tomoyo_domain_list_lock); | ||
896 | domain = tomoyo_find_domain(new_domain_name); | 801 | domain = tomoyo_find_domain(new_domain_name); |
897 | up_read(&tomoyo_domain_list_lock); | ||
898 | if (domain) | 802 | if (domain) |
899 | goto done; | 803 | goto done; |
900 | if (is_enforce) | 804 | if (is_enforce) |
@@ -909,14 +813,15 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
909 | if (is_enforce) | 813 | if (is_enforce) |
910 | retval = -EPERM; | 814 | retval = -EPERM; |
911 | else | 815 | else |
912 | tomoyo_set_domain_flag(old_domain, false, | 816 | old_domain->transition_failed = true; |
913 | TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED); | ||
914 | out: | 817 | out: |
915 | if (!domain) | 818 | if (!domain) |
916 | domain = old_domain; | 819 | domain = old_domain; |
820 | /* Update reference count on "struct tomoyo_domain_info". */ | ||
821 | atomic_inc(&domain->users); | ||
917 | bprm->cred->security = domain; | 822 | bprm->cred->security = domain; |
918 | tomoyo_free(real_program_name); | 823 | kfree(real_program_name); |
919 | tomoyo_free(symlink_program_name); | 824 | kfree(symlink_program_name); |
920 | tomoyo_free(tmp); | 825 | kfree(tmp); |
921 | return retval; | 826 | return retval; |
922 | } | 827 | } |
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 9a6c58881c0a..1b24304edb7d 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -10,108 +10,64 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include "common.h" | 12 | #include "common.h" |
13 | #include "tomoyo.h" | ||
14 | #include "realpath.h" | ||
15 | |||
16 | /* | ||
17 | * tomoyo_globally_readable_file_entry is a structure which is used for holding | ||
18 | * "allow_read" entries. | ||
19 | * It has following fields. | ||
20 | * | ||
21 | * (1) "list" which is linked to tomoyo_globally_readable_list . | ||
22 | * (2) "filename" is a pathname which is allowed to open(O_RDONLY). | ||
23 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
24 | * otherwise. | ||
25 | */ | ||
26 | struct tomoyo_globally_readable_file_entry { | ||
27 | struct list_head list; | ||
28 | const struct tomoyo_path_info *filename; | ||
29 | bool is_deleted; | ||
30 | }; | ||
31 | |||
32 | /* | ||
33 | * tomoyo_pattern_entry is a structure which is used for holding | ||
34 | * "tomoyo_pattern_list" entries. | ||
35 | * It has following fields. | ||
36 | * | ||
37 | * (1) "list" which is linked to tomoyo_pattern_list . | ||
38 | * (2) "pattern" is a pathname pattern which is used for converting pathnames | ||
39 | * to pathname patterns during learning mode. | ||
40 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
41 | * otherwise. | ||
42 | */ | ||
43 | struct tomoyo_pattern_entry { | ||
44 | struct list_head list; | ||
45 | const struct tomoyo_path_info *pattern; | ||
46 | bool is_deleted; | ||
47 | }; | ||
48 | |||
49 | /* | ||
50 | * tomoyo_no_rewrite_entry is a structure which is used for holding | ||
51 | * "deny_rewrite" entries. | ||
52 | * It has following fields. | ||
53 | * | ||
54 | * (1) "list" which is linked to tomoyo_no_rewrite_list . | ||
55 | * (2) "pattern" is a pathname which is by default not permitted to modify | ||
56 | * already existing content. | ||
57 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
58 | * otherwise. | ||
59 | */ | ||
60 | struct tomoyo_no_rewrite_entry { | ||
61 | struct list_head list; | ||
62 | const struct tomoyo_path_info *pattern; | ||
63 | bool is_deleted; | ||
64 | }; | ||
65 | 13 | ||
66 | /* Keyword array for single path operations. */ | 14 | /* Keyword array for single path operations. */ |
67 | static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = { | 15 | static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { |
68 | [TOMOYO_TYPE_READ_WRITE_ACL] = "read/write", | 16 | [TOMOYO_TYPE_READ_WRITE] = "read/write", |
69 | [TOMOYO_TYPE_EXECUTE_ACL] = "execute", | 17 | [TOMOYO_TYPE_EXECUTE] = "execute", |
70 | [TOMOYO_TYPE_READ_ACL] = "read", | 18 | [TOMOYO_TYPE_READ] = "read", |
71 | [TOMOYO_TYPE_WRITE_ACL] = "write", | 19 | [TOMOYO_TYPE_WRITE] = "write", |
72 | [TOMOYO_TYPE_CREATE_ACL] = "create", | 20 | [TOMOYO_TYPE_CREATE] = "create", |
73 | [TOMOYO_TYPE_UNLINK_ACL] = "unlink", | 21 | [TOMOYO_TYPE_UNLINK] = "unlink", |
74 | [TOMOYO_TYPE_MKDIR_ACL] = "mkdir", | 22 | [TOMOYO_TYPE_MKDIR] = "mkdir", |
75 | [TOMOYO_TYPE_RMDIR_ACL] = "rmdir", | 23 | [TOMOYO_TYPE_RMDIR] = "rmdir", |
76 | [TOMOYO_TYPE_MKFIFO_ACL] = "mkfifo", | 24 | [TOMOYO_TYPE_MKFIFO] = "mkfifo", |
77 | [TOMOYO_TYPE_MKSOCK_ACL] = "mksock", | 25 | [TOMOYO_TYPE_MKSOCK] = "mksock", |
78 | [TOMOYO_TYPE_MKBLOCK_ACL] = "mkblock", | 26 | [TOMOYO_TYPE_MKBLOCK] = "mkblock", |
79 | [TOMOYO_TYPE_MKCHAR_ACL] = "mkchar", | 27 | [TOMOYO_TYPE_MKCHAR] = "mkchar", |
80 | [TOMOYO_TYPE_TRUNCATE_ACL] = "truncate", | 28 | [TOMOYO_TYPE_TRUNCATE] = "truncate", |
81 | [TOMOYO_TYPE_SYMLINK_ACL] = "symlink", | 29 | [TOMOYO_TYPE_SYMLINK] = "symlink", |
82 | [TOMOYO_TYPE_REWRITE_ACL] = "rewrite", | 30 | [TOMOYO_TYPE_REWRITE] = "rewrite", |
31 | [TOMOYO_TYPE_IOCTL] = "ioctl", | ||
32 | [TOMOYO_TYPE_CHMOD] = "chmod", | ||
33 | [TOMOYO_TYPE_CHOWN] = "chown", | ||
34 | [TOMOYO_TYPE_CHGRP] = "chgrp", | ||
35 | [TOMOYO_TYPE_CHROOT] = "chroot", | ||
36 | [TOMOYO_TYPE_MOUNT] = "mount", | ||
37 | [TOMOYO_TYPE_UMOUNT] = "unmount", | ||
83 | }; | 38 | }; |
84 | 39 | ||
85 | /* Keyword array for double path operations. */ | 40 | /* Keyword array for double path operations. */ |
86 | static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = { | 41 | static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { |
87 | [TOMOYO_TYPE_LINK_ACL] = "link", | 42 | [TOMOYO_TYPE_LINK] = "link", |
88 | [TOMOYO_TYPE_RENAME_ACL] = "rename", | 43 | [TOMOYO_TYPE_RENAME] = "rename", |
44 | [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", | ||
89 | }; | 45 | }; |
90 | 46 | ||
91 | /** | 47 | /** |
92 | * tomoyo_sp2keyword - Get the name of single path operation. | 48 | * tomoyo_path2keyword - Get the name of single path operation. |
93 | * | 49 | * |
94 | * @operation: Type of operation. | 50 | * @operation: Type of operation. |
95 | * | 51 | * |
96 | * Returns the name of single path operation. | 52 | * Returns the name of single path operation. |
97 | */ | 53 | */ |
98 | const char *tomoyo_sp2keyword(const u8 operation) | 54 | const char *tomoyo_path2keyword(const u8 operation) |
99 | { | 55 | { |
100 | return (operation < TOMOYO_MAX_SINGLE_PATH_OPERATION) | 56 | return (operation < TOMOYO_MAX_PATH_OPERATION) |
101 | ? tomoyo_sp_keyword[operation] : NULL; | 57 | ? tomoyo_path_keyword[operation] : NULL; |
102 | } | 58 | } |
103 | 59 | ||
104 | /** | 60 | /** |
105 | * tomoyo_dp2keyword - Get the name of double path operation. | 61 | * tomoyo_path22keyword - Get the name of double path operation. |
106 | * | 62 | * |
107 | * @operation: Type of operation. | 63 | * @operation: Type of operation. |
108 | * | 64 | * |
109 | * Returns the name of double path operation. | 65 | * Returns the name of double path operation. |
110 | */ | 66 | */ |
111 | const char *tomoyo_dp2keyword(const u8 operation) | 67 | const char *tomoyo_path22keyword(const u8 operation) |
112 | { | 68 | { |
113 | return (operation < TOMOYO_MAX_DOUBLE_PATH_OPERATION) | 69 | return (operation < TOMOYO_MAX_PATH2_OPERATION) |
114 | ? tomoyo_dp_keyword[operation] : NULL; | 70 | ? tomoyo_path2_keyword[operation] : NULL; |
115 | } | 71 | } |
116 | 72 | ||
117 | /** | 73 | /** |
@@ -142,7 +98,8 @@ static bool tomoyo_strendswith(const char *name, const char *tail) | |||
142 | static struct tomoyo_path_info *tomoyo_get_path(struct path *path) | 98 | static struct tomoyo_path_info *tomoyo_get_path(struct path *path) |
143 | { | 99 | { |
144 | int error; | 100 | int error; |
145 | struct tomoyo_path_info_with_data *buf = tomoyo_alloc(sizeof(*buf)); | 101 | struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf), |
102 | GFP_KERNEL); | ||
146 | 103 | ||
147 | if (!buf) | 104 | if (!buf) |
148 | return NULL; | 105 | return NULL; |
@@ -154,20 +111,17 @@ static struct tomoyo_path_info *tomoyo_get_path(struct path *path) | |||
154 | tomoyo_fill_path_info(&buf->head); | 111 | tomoyo_fill_path_info(&buf->head); |
155 | return &buf->head; | 112 | return &buf->head; |
156 | } | 113 | } |
157 | tomoyo_free(buf); | 114 | kfree(buf); |
158 | return NULL; | 115 | return NULL; |
159 | } | 116 | } |
160 | 117 | ||
161 | /* Lock for domain->acl_info_list. */ | 118 | static int tomoyo_update_path2_acl(const u8 type, const char *filename1, |
162 | DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock); | 119 | const char *filename2, |
163 | 120 | struct tomoyo_domain_info *const domain, | |
164 | static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, | 121 | const bool is_delete); |
165 | const char *filename2, | 122 | static int tomoyo_update_path_acl(const u8 type, const char *filename, |
166 | struct tomoyo_domain_info * | 123 | struct tomoyo_domain_info *const domain, |
167 | const domain, const bool is_delete); | 124 | const bool is_delete); |
168 | static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | ||
169 | struct tomoyo_domain_info * | ||
170 | const domain, const bool is_delete); | ||
171 | 125 | ||
172 | /* | 126 | /* |
173 | * tomoyo_globally_readable_list is used for holding list of pathnames which | 127 | * tomoyo_globally_readable_list is used for holding list of pathnames which |
@@ -194,8 +148,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
194 | * given "allow_read /lib/libc-2.5.so" to the domain which current process | 148 | * given "allow_read /lib/libc-2.5.so" to the domain which current process |
195 | * belongs to. | 149 | * belongs to. |
196 | */ | 150 | */ |
197 | static LIST_HEAD(tomoyo_globally_readable_list); | 151 | LIST_HEAD(tomoyo_globally_readable_list); |
198 | static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); | ||
199 | 152 | ||
200 | /** | 153 | /** |
201 | * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. | 154 | * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. |
@@ -204,40 +157,42 @@ static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); | |||
204 | * @is_delete: True if it is a delete request. | 157 | * @is_delete: True if it is a delete request. |
205 | * | 158 | * |
206 | * Returns 0 on success, negative value otherwise. | 159 | * Returns 0 on success, negative value otherwise. |
160 | * | ||
161 | * Caller holds tomoyo_read_lock(). | ||
207 | */ | 162 | */ |
208 | static int tomoyo_update_globally_readable_entry(const char *filename, | 163 | static int tomoyo_update_globally_readable_entry(const char *filename, |
209 | const bool is_delete) | 164 | const bool is_delete) |
210 | { | 165 | { |
211 | struct tomoyo_globally_readable_file_entry *new_entry; | 166 | struct tomoyo_globally_readable_file_entry *entry = NULL; |
212 | struct tomoyo_globally_readable_file_entry *ptr; | 167 | struct tomoyo_globally_readable_file_entry *ptr; |
213 | const struct tomoyo_path_info *saved_filename; | 168 | const struct tomoyo_path_info *saved_filename; |
214 | int error = -ENOMEM; | 169 | int error = is_delete ? -ENOENT : -ENOMEM; |
215 | 170 | ||
216 | if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__)) | 171 | if (!tomoyo_is_correct_path(filename, 1, 0, -1)) |
217 | return -EINVAL; | 172 | return -EINVAL; |
218 | saved_filename = tomoyo_save_name(filename); | 173 | saved_filename = tomoyo_get_name(filename); |
219 | if (!saved_filename) | 174 | if (!saved_filename) |
220 | return -ENOMEM; | 175 | return -ENOMEM; |
221 | down_write(&tomoyo_globally_readable_list_lock); | 176 | if (!is_delete) |
222 | list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { | 177 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
178 | mutex_lock(&tomoyo_policy_lock); | ||
179 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { | ||
223 | if (ptr->filename != saved_filename) | 180 | if (ptr->filename != saved_filename) |
224 | continue; | 181 | continue; |
225 | ptr->is_deleted = is_delete; | 182 | ptr->is_deleted = is_delete; |
226 | error = 0; | 183 | error = 0; |
227 | goto out; | 184 | break; |
228 | } | 185 | } |
229 | if (is_delete) { | 186 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
230 | error = -ENOENT; | 187 | entry->filename = saved_filename; |
231 | goto out; | 188 | saved_filename = NULL; |
189 | list_add_tail_rcu(&entry->list, &tomoyo_globally_readable_list); | ||
190 | entry = NULL; | ||
191 | error = 0; | ||
232 | } | 192 | } |
233 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 193 | mutex_unlock(&tomoyo_policy_lock); |
234 | if (!new_entry) | 194 | tomoyo_put_name(saved_filename); |
235 | goto out; | 195 | kfree(entry); |
236 | new_entry->filename = saved_filename; | ||
237 | list_add_tail(&new_entry->list, &tomoyo_globally_readable_list); | ||
238 | error = 0; | ||
239 | out: | ||
240 | up_write(&tomoyo_globally_readable_list_lock); | ||
241 | return error; | 196 | return error; |
242 | } | 197 | } |
243 | 198 | ||
@@ -247,21 +202,22 @@ static int tomoyo_update_globally_readable_entry(const char *filename, | |||
247 | * @filename: The filename to check. | 202 | * @filename: The filename to check. |
248 | * | 203 | * |
249 | * Returns true if any domain can open @filename for reading, false otherwise. | 204 | * Returns true if any domain can open @filename for reading, false otherwise. |
205 | * | ||
206 | * Caller holds tomoyo_read_lock(). | ||
250 | */ | 207 | */ |
251 | static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * | 208 | static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * |
252 | filename) | 209 | filename) |
253 | { | 210 | { |
254 | struct tomoyo_globally_readable_file_entry *ptr; | 211 | struct tomoyo_globally_readable_file_entry *ptr; |
255 | bool found = false; | 212 | bool found = false; |
256 | down_read(&tomoyo_globally_readable_list_lock); | 213 | |
257 | list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { | 214 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { |
258 | if (!ptr->is_deleted && | 215 | if (!ptr->is_deleted && |
259 | tomoyo_path_matches_pattern(filename, ptr->filename)) { | 216 | tomoyo_path_matches_pattern(filename, ptr->filename)) { |
260 | found = true; | 217 | found = true; |
261 | break; | 218 | break; |
262 | } | 219 | } |
263 | } | 220 | } |
264 | up_read(&tomoyo_globally_readable_list_lock); | ||
265 | return found; | 221 | return found; |
266 | } | 222 | } |
267 | 223 | ||
@@ -272,6 +228,8 @@ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * | |||
272 | * @is_delete: True if it is a delete request. | 228 | * @is_delete: True if it is a delete request. |
273 | * | 229 | * |
274 | * Returns 0 on success, negative value otherwise. | 230 | * Returns 0 on success, negative value otherwise. |
231 | * | ||
232 | * Caller holds tomoyo_read_lock(). | ||
275 | */ | 233 | */ |
276 | int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) | 234 | int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) |
277 | { | 235 | { |
@@ -284,13 +242,14 @@ int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) | |||
284 | * @head: Pointer to "struct tomoyo_io_buffer". | 242 | * @head: Pointer to "struct tomoyo_io_buffer". |
285 | * | 243 | * |
286 | * Returns true on success, false otherwise. | 244 | * Returns true on success, false otherwise. |
245 | * | ||
246 | * Caller holds tomoyo_read_lock(). | ||
287 | */ | 247 | */ |
288 | bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) | 248 | bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) |
289 | { | 249 | { |
290 | struct list_head *pos; | 250 | struct list_head *pos; |
291 | bool done = true; | 251 | bool done = true; |
292 | 252 | ||
293 | down_read(&tomoyo_globally_readable_list_lock); | ||
294 | list_for_each_cookie(pos, head->read_var2, | 253 | list_for_each_cookie(pos, head->read_var2, |
295 | &tomoyo_globally_readable_list) { | 254 | &tomoyo_globally_readable_list) { |
296 | struct tomoyo_globally_readable_file_entry *ptr; | 255 | struct tomoyo_globally_readable_file_entry *ptr; |
@@ -304,7 +263,6 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) | |||
304 | if (!done) | 263 | if (!done) |
305 | break; | 264 | break; |
306 | } | 265 | } |
307 | up_read(&tomoyo_globally_readable_list_lock); | ||
308 | return done; | 266 | return done; |
309 | } | 267 | } |
310 | 268 | ||
@@ -337,8 +295,7 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) | |||
337 | * which pretends as if /proc/self/ is not a symlink; so that we can forbid | 295 | * which pretends as if /proc/self/ is not a symlink; so that we can forbid |
338 | * current process from accessing other process's information. | 296 | * current process from accessing other process's information. |
339 | */ | 297 | */ |
340 | static LIST_HEAD(tomoyo_pattern_list); | 298 | LIST_HEAD(tomoyo_pattern_list); |
341 | static DECLARE_RWSEM(tomoyo_pattern_list_lock); | ||
342 | 299 | ||
343 | /** | 300 | /** |
344 | * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. | 301 | * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. |
@@ -347,40 +304,43 @@ static DECLARE_RWSEM(tomoyo_pattern_list_lock); | |||
347 | * @is_delete: True if it is a delete request. | 304 | * @is_delete: True if it is a delete request. |
348 | * | 305 | * |
349 | * Returns 0 on success, negative value otherwise. | 306 | * Returns 0 on success, negative value otherwise. |
307 | * | ||
308 | * Caller holds tomoyo_read_lock(). | ||
350 | */ | 309 | */ |
351 | static int tomoyo_update_file_pattern_entry(const char *pattern, | 310 | static int tomoyo_update_file_pattern_entry(const char *pattern, |
352 | const bool is_delete) | 311 | const bool is_delete) |
353 | { | 312 | { |
354 | struct tomoyo_pattern_entry *new_entry; | 313 | struct tomoyo_pattern_entry *entry = NULL; |
355 | struct tomoyo_pattern_entry *ptr; | 314 | struct tomoyo_pattern_entry *ptr; |
356 | const struct tomoyo_path_info *saved_pattern; | 315 | const struct tomoyo_path_info *saved_pattern; |
357 | int error = -ENOMEM; | 316 | int error = is_delete ? -ENOENT : -ENOMEM; |
358 | 317 | ||
359 | if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__)) | 318 | saved_pattern = tomoyo_get_name(pattern); |
360 | return -EINVAL; | ||
361 | saved_pattern = tomoyo_save_name(pattern); | ||
362 | if (!saved_pattern) | 319 | if (!saved_pattern) |
363 | return -ENOMEM; | 320 | return error; |
364 | down_write(&tomoyo_pattern_list_lock); | 321 | if (!saved_pattern->is_patterned) |
365 | list_for_each_entry(ptr, &tomoyo_pattern_list, list) { | 322 | goto out; |
323 | if (!is_delete) | ||
324 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
325 | mutex_lock(&tomoyo_policy_lock); | ||
326 | list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { | ||
366 | if (saved_pattern != ptr->pattern) | 327 | if (saved_pattern != ptr->pattern) |
367 | continue; | 328 | continue; |
368 | ptr->is_deleted = is_delete; | 329 | ptr->is_deleted = is_delete; |
369 | error = 0; | 330 | error = 0; |
370 | goto out; | 331 | break; |
371 | } | 332 | } |
372 | if (is_delete) { | 333 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
373 | error = -ENOENT; | 334 | entry->pattern = saved_pattern; |
374 | goto out; | 335 | saved_pattern = NULL; |
336 | list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); | ||
337 | entry = NULL; | ||
338 | error = 0; | ||
375 | } | 339 | } |
376 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 340 | mutex_unlock(&tomoyo_policy_lock); |
377 | if (!new_entry) | ||
378 | goto out; | ||
379 | new_entry->pattern = saved_pattern; | ||
380 | list_add_tail(&new_entry->list, &tomoyo_pattern_list); | ||
381 | error = 0; | ||
382 | out: | 341 | out: |
383 | up_write(&tomoyo_pattern_list_lock); | 342 | kfree(entry); |
343 | tomoyo_put_name(saved_pattern); | ||
384 | return error; | 344 | return error; |
385 | } | 345 | } |
386 | 346 | ||
@@ -390,6 +350,8 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, | |||
390 | * @filename: The filename to find patterned pathname. | 350 | * @filename: The filename to find patterned pathname. |
391 | * | 351 | * |
392 | * Returns pointer to pathname pattern if matched, @filename otherwise. | 352 | * Returns pointer to pathname pattern if matched, @filename otherwise. |
353 | * | ||
354 | * Caller holds tomoyo_read_lock(). | ||
393 | */ | 355 | */ |
394 | static const struct tomoyo_path_info * | 356 | static const struct tomoyo_path_info * |
395 | tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | 357 | tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) |
@@ -397,8 +359,7 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | |||
397 | struct tomoyo_pattern_entry *ptr; | 359 | struct tomoyo_pattern_entry *ptr; |
398 | const struct tomoyo_path_info *pattern = NULL; | 360 | const struct tomoyo_path_info *pattern = NULL; |
399 | 361 | ||
400 | down_read(&tomoyo_pattern_list_lock); | 362 | list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { |
401 | list_for_each_entry(ptr, &tomoyo_pattern_list, list) { | ||
402 | if (ptr->is_deleted) | 363 | if (ptr->is_deleted) |
403 | continue; | 364 | continue; |
404 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) | 365 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) |
@@ -411,7 +372,6 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | |||
411 | break; | 372 | break; |
412 | } | 373 | } |
413 | } | 374 | } |
414 | up_read(&tomoyo_pattern_list_lock); | ||
415 | if (pattern) | 375 | if (pattern) |
416 | filename = pattern; | 376 | filename = pattern; |
417 | return filename; | 377 | return filename; |
@@ -424,6 +384,8 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | |||
424 | * @is_delete: True if it is a delete request. | 384 | * @is_delete: True if it is a delete request. |
425 | * | 385 | * |
426 | * Returns 0 on success, negative value otherwise. | 386 | * Returns 0 on success, negative value otherwise. |
387 | * | ||
388 | * Caller holds tomoyo_read_lock(). | ||
427 | */ | 389 | */ |
428 | int tomoyo_write_pattern_policy(char *data, const bool is_delete) | 390 | int tomoyo_write_pattern_policy(char *data, const bool is_delete) |
429 | { | 391 | { |
@@ -436,13 +398,14 @@ int tomoyo_write_pattern_policy(char *data, const bool is_delete) | |||
436 | * @head: Pointer to "struct tomoyo_io_buffer". | 398 | * @head: Pointer to "struct tomoyo_io_buffer". |
437 | * | 399 | * |
438 | * Returns true on success, false otherwise. | 400 | * Returns true on success, false otherwise. |
401 | * | ||
402 | * Caller holds tomoyo_read_lock(). | ||
439 | */ | 403 | */ |
440 | bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) | 404 | bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) |
441 | { | 405 | { |
442 | struct list_head *pos; | 406 | struct list_head *pos; |
443 | bool done = true; | 407 | bool done = true; |
444 | 408 | ||
445 | down_read(&tomoyo_pattern_list_lock); | ||
446 | list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { | 409 | list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { |
447 | struct tomoyo_pattern_entry *ptr; | 410 | struct tomoyo_pattern_entry *ptr; |
448 | ptr = list_entry(pos, struct tomoyo_pattern_entry, list); | 411 | ptr = list_entry(pos, struct tomoyo_pattern_entry, list); |
@@ -453,7 +416,6 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) | |||
453 | if (!done) | 416 | if (!done) |
454 | break; | 417 | break; |
455 | } | 418 | } |
456 | up_read(&tomoyo_pattern_list_lock); | ||
457 | return done; | 419 | return done; |
458 | } | 420 | } |
459 | 421 | ||
@@ -486,8 +448,7 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) | |||
486 | * " (deleted)" suffix if the file is already unlink()ed; so that we don't | 448 | * " (deleted)" suffix if the file is already unlink()ed; so that we don't |
487 | * need to worry whether the file is already unlink()ed or not. | 449 | * need to worry whether the file is already unlink()ed or not. |
488 | */ | 450 | */ |
489 | static LIST_HEAD(tomoyo_no_rewrite_list); | 451 | LIST_HEAD(tomoyo_no_rewrite_list); |
490 | static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); | ||
491 | 452 | ||
492 | /** | 453 | /** |
493 | * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. | 454 | * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. |
@@ -496,39 +457,42 @@ static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); | |||
496 | * @is_delete: True if it is a delete request. | 457 | * @is_delete: True if it is a delete request. |
497 | * | 458 | * |
498 | * Returns 0 on success, negative value otherwise. | 459 | * Returns 0 on success, negative value otherwise. |
460 | * | ||
461 | * Caller holds tomoyo_read_lock(). | ||
499 | */ | 462 | */ |
500 | static int tomoyo_update_no_rewrite_entry(const char *pattern, | 463 | static int tomoyo_update_no_rewrite_entry(const char *pattern, |
501 | const bool is_delete) | 464 | const bool is_delete) |
502 | { | 465 | { |
503 | struct tomoyo_no_rewrite_entry *new_entry, *ptr; | 466 | struct tomoyo_no_rewrite_entry *entry = NULL; |
467 | struct tomoyo_no_rewrite_entry *ptr; | ||
504 | const struct tomoyo_path_info *saved_pattern; | 468 | const struct tomoyo_path_info *saved_pattern; |
505 | int error = -ENOMEM; | 469 | int error = is_delete ? -ENOENT : -ENOMEM; |
506 | 470 | ||
507 | if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__)) | 471 | if (!tomoyo_is_correct_path(pattern, 0, 0, 0)) |
508 | return -EINVAL; | 472 | return -EINVAL; |
509 | saved_pattern = tomoyo_save_name(pattern); | 473 | saved_pattern = tomoyo_get_name(pattern); |
510 | if (!saved_pattern) | 474 | if (!saved_pattern) |
511 | return -ENOMEM; | 475 | return error; |
512 | down_write(&tomoyo_no_rewrite_list_lock); | 476 | if (!is_delete) |
513 | list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { | 477 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
478 | mutex_lock(&tomoyo_policy_lock); | ||
479 | list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { | ||
514 | if (ptr->pattern != saved_pattern) | 480 | if (ptr->pattern != saved_pattern) |
515 | continue; | 481 | continue; |
516 | ptr->is_deleted = is_delete; | 482 | ptr->is_deleted = is_delete; |
517 | error = 0; | 483 | error = 0; |
518 | goto out; | 484 | break; |
519 | } | 485 | } |
520 | if (is_delete) { | 486 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
521 | error = -ENOENT; | 487 | entry->pattern = saved_pattern; |
522 | goto out; | 488 | saved_pattern = NULL; |
489 | list_add_tail_rcu(&entry->list, &tomoyo_no_rewrite_list); | ||
490 | entry = NULL; | ||
491 | error = 0; | ||
523 | } | 492 | } |
524 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 493 | mutex_unlock(&tomoyo_policy_lock); |
525 | if (!new_entry) | 494 | tomoyo_put_name(saved_pattern); |
526 | goto out; | 495 | kfree(entry); |
527 | new_entry->pattern = saved_pattern; | ||
528 | list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list); | ||
529 | error = 0; | ||
530 | out: | ||
531 | up_write(&tomoyo_no_rewrite_list_lock); | ||
532 | return error; | 496 | return error; |
533 | } | 497 | } |
534 | 498 | ||
@@ -539,14 +503,15 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, | |||
539 | * | 503 | * |
540 | * Returns true if @filename is specified by "deny_rewrite" directive, | 504 | * Returns true if @filename is specified by "deny_rewrite" directive, |
541 | * false otherwise. | 505 | * false otherwise. |
506 | * | ||
507 | * Caller holds tomoyo_read_lock(). | ||
542 | */ | 508 | */ |
543 | static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) | 509 | static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) |
544 | { | 510 | { |
545 | struct tomoyo_no_rewrite_entry *ptr; | 511 | struct tomoyo_no_rewrite_entry *ptr; |
546 | bool found = false; | 512 | bool found = false; |
547 | 513 | ||
548 | down_read(&tomoyo_no_rewrite_list_lock); | 514 | list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { |
549 | list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { | ||
550 | if (ptr->is_deleted) | 515 | if (ptr->is_deleted) |
551 | continue; | 516 | continue; |
552 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) | 517 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) |
@@ -554,7 +519,6 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) | |||
554 | found = true; | 519 | found = true; |
555 | break; | 520 | break; |
556 | } | 521 | } |
557 | up_read(&tomoyo_no_rewrite_list_lock); | ||
558 | return found; | 522 | return found; |
559 | } | 523 | } |
560 | 524 | ||
@@ -565,6 +529,8 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) | |||
565 | * @is_delete: True if it is a delete request. | 529 | * @is_delete: True if it is a delete request. |
566 | * | 530 | * |
567 | * Returns 0 on success, negative value otherwise. | 531 | * Returns 0 on success, negative value otherwise. |
532 | * | ||
533 | * Caller holds tomoyo_read_lock(). | ||
568 | */ | 534 | */ |
569 | int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) | 535 | int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) |
570 | { | 536 | { |
@@ -577,13 +543,14 @@ int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) | |||
577 | * @head: Pointer to "struct tomoyo_io_buffer". | 543 | * @head: Pointer to "struct tomoyo_io_buffer". |
578 | * | 544 | * |
579 | * Returns true on success, false otherwise. | 545 | * Returns true on success, false otherwise. |
546 | * | ||
547 | * Caller holds tomoyo_read_lock(). | ||
580 | */ | 548 | */ |
581 | bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) | 549 | bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) |
582 | { | 550 | { |
583 | struct list_head *pos; | 551 | struct list_head *pos; |
584 | bool done = true; | 552 | bool done = true; |
585 | 553 | ||
586 | down_read(&tomoyo_no_rewrite_list_lock); | ||
587 | list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { | 554 | list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { |
588 | struct tomoyo_no_rewrite_entry *ptr; | 555 | struct tomoyo_no_rewrite_entry *ptr; |
589 | ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); | 556 | ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); |
@@ -594,7 +561,6 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) | |||
594 | if (!done) | 561 | if (!done) |
595 | break; | 562 | break; |
596 | } | 563 | } |
597 | up_read(&tomoyo_no_rewrite_list_lock); | ||
598 | return done; | 564 | return done; |
599 | } | 565 | } |
600 | 566 | ||
@@ -612,6 +578,8 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) | |||
612 | * Current policy syntax uses "allow_read/write" instead of "6", | 578 | * Current policy syntax uses "allow_read/write" instead of "6", |
613 | * "allow_read" instead of "4", "allow_write" instead of "2", | 579 | * "allow_read" instead of "4", "allow_write" instead of "2", |
614 | * "allow_execute" instead of "1". | 580 | * "allow_execute" instead of "1". |
581 | * | ||
582 | * Caller holds tomoyo_read_lock(). | ||
615 | */ | 583 | */ |
616 | static int tomoyo_update_file_acl(const char *filename, u8 perm, | 584 | static int tomoyo_update_file_acl(const char *filename, u8 perm, |
617 | struct tomoyo_domain_info * const domain, | 585 | struct tomoyo_domain_info * const domain, |
@@ -629,19 +597,19 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm, | |||
629 | */ | 597 | */ |
630 | return 0; | 598 | return 0; |
631 | if (perm & 4) | 599 | if (perm & 4) |
632 | tomoyo_update_single_path_acl(TOMOYO_TYPE_READ_ACL, filename, | 600 | tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain, |
633 | domain, is_delete); | 601 | is_delete); |
634 | if (perm & 2) | 602 | if (perm & 2) |
635 | tomoyo_update_single_path_acl(TOMOYO_TYPE_WRITE_ACL, filename, | 603 | tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain, |
636 | domain, is_delete); | 604 | is_delete); |
637 | if (perm & 1) | 605 | if (perm & 1) |
638 | tomoyo_update_single_path_acl(TOMOYO_TYPE_EXECUTE_ACL, | 606 | tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain, |
639 | filename, domain, is_delete); | 607 | is_delete); |
640 | return 0; | 608 | return 0; |
641 | } | 609 | } |
642 | 610 | ||
643 | /** | 611 | /** |
644 | * tomoyo_check_single_path_acl2 - Check permission for single path operation. | 612 | * tomoyo_path_acl2 - Check permission for single path operation. |
645 | * | 613 | * |
646 | * @domain: Pointer to "struct tomoyo_domain_info". | 614 | * @domain: Pointer to "struct tomoyo_domain_info". |
647 | * @filename: Filename to check. | 615 | * @filename: Filename to check. |
@@ -649,26 +617,28 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm, | |||
649 | * @may_use_pattern: True if patterned ACL is permitted. | 617 | * @may_use_pattern: True if patterned ACL is permitted. |
650 | * | 618 | * |
651 | * Returns 0 on success, -EPERM otherwise. | 619 | * Returns 0 on success, -EPERM otherwise. |
620 | * | ||
621 | * Caller holds tomoyo_read_lock(). | ||
652 | */ | 622 | */ |
653 | static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * | 623 | static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain, |
654 | domain, | 624 | const struct tomoyo_path_info *filename, |
655 | const struct tomoyo_path_info * | 625 | const u32 perm, const bool may_use_pattern) |
656 | filename, | ||
657 | const u16 perm, | ||
658 | const bool may_use_pattern) | ||
659 | { | 626 | { |
660 | struct tomoyo_acl_info *ptr; | 627 | struct tomoyo_acl_info *ptr; |
661 | int error = -EPERM; | 628 | int error = -EPERM; |
662 | 629 | ||
663 | down_read(&tomoyo_domain_acl_info_list_lock); | 630 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
664 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 631 | struct tomoyo_path_acl *acl; |
665 | struct tomoyo_single_path_acl_record *acl; | 632 | if (ptr->type != TOMOYO_TYPE_PATH_ACL) |
666 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) | ||
667 | continue; | ||
668 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, | ||
669 | head); | ||
670 | if (!(acl->perm & perm)) | ||
671 | continue; | 633 | continue; |
634 | acl = container_of(ptr, struct tomoyo_path_acl, head); | ||
635 | if (perm <= 0xFFFF) { | ||
636 | if (!(acl->perm & perm)) | ||
637 | continue; | ||
638 | } else { | ||
639 | if (!(acl->perm_high & (perm >> 16))) | ||
640 | continue; | ||
641 | } | ||
672 | if (may_use_pattern || !acl->filename->is_patterned) { | 642 | if (may_use_pattern || !acl->filename->is_patterned) { |
673 | if (!tomoyo_path_matches_pattern(filename, | 643 | if (!tomoyo_path_matches_pattern(filename, |
674 | acl->filename)) | 644 | acl->filename)) |
@@ -679,7 +649,6 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * | |||
679 | error = 0; | 649 | error = 0; |
680 | break; | 650 | break; |
681 | } | 651 | } |
682 | up_read(&tomoyo_domain_acl_info_list_lock); | ||
683 | return error; | 652 | return error; |
684 | } | 653 | } |
685 | 654 | ||
@@ -691,27 +660,28 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * | |||
691 | * @operation: Mode ("read" or "write" or "read/write" or "execute"). | 660 | * @operation: Mode ("read" or "write" or "read/write" or "execute"). |
692 | * | 661 | * |
693 | * Returns 0 on success, -EPERM otherwise. | 662 | * Returns 0 on success, -EPERM otherwise. |
663 | * | ||
664 | * Caller holds tomoyo_read_lock(). | ||
694 | */ | 665 | */ |
695 | static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, | 666 | static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, |
696 | const struct tomoyo_path_info *filename, | 667 | const struct tomoyo_path_info *filename, |
697 | const u8 operation) | 668 | const u8 operation) |
698 | { | 669 | { |
699 | u16 perm = 0; | 670 | u32 perm = 0; |
700 | 671 | ||
701 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) | 672 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) |
702 | return 0; | 673 | return 0; |
703 | if (operation == 6) | 674 | if (operation == 6) |
704 | perm = 1 << TOMOYO_TYPE_READ_WRITE_ACL; | 675 | perm = 1 << TOMOYO_TYPE_READ_WRITE; |
705 | else if (operation == 4) | 676 | else if (operation == 4) |
706 | perm = 1 << TOMOYO_TYPE_READ_ACL; | 677 | perm = 1 << TOMOYO_TYPE_READ; |
707 | else if (operation == 2) | 678 | else if (operation == 2) |
708 | perm = 1 << TOMOYO_TYPE_WRITE_ACL; | 679 | perm = 1 << TOMOYO_TYPE_WRITE; |
709 | else if (operation == 1) | 680 | else if (operation == 1) |
710 | perm = 1 << TOMOYO_TYPE_EXECUTE_ACL; | 681 | perm = 1 << TOMOYO_TYPE_EXECUTE; |
711 | else | 682 | else |
712 | BUG(); | 683 | BUG(); |
713 | return tomoyo_check_single_path_acl2(domain, filename, perm, | 684 | return tomoyo_path_acl2(domain, filename, perm, operation != 1); |
714 | operation != 1); | ||
715 | } | 685 | } |
716 | 686 | ||
717 | /** | 687 | /** |
@@ -724,6 +694,8 @@ static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, | |||
724 | * @mode: Access control mode. | 694 | * @mode: Access control mode. |
725 | * | 695 | * |
726 | * Returns 0 on success, negative value otherwise. | 696 | * Returns 0 on success, negative value otherwise. |
697 | * | ||
698 | * Caller holds tomoyo_read_lock(). | ||
727 | */ | 699 | */ |
728 | static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, | 700 | static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, |
729 | const struct tomoyo_path_info *filename, | 701 | const struct tomoyo_path_info *filename, |
@@ -737,18 +709,17 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, | |||
737 | if (!filename) | 709 | if (!filename) |
738 | return 0; | 710 | return 0; |
739 | error = tomoyo_check_file_acl(domain, filename, perm); | 711 | error = tomoyo_check_file_acl(domain, filename, perm); |
740 | if (error && perm == 4 && | 712 | if (error && perm == 4 && !domain->ignore_global_allow_read |
741 | (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0 | ||
742 | && tomoyo_is_globally_readable_file(filename)) | 713 | && tomoyo_is_globally_readable_file(filename)) |
743 | error = 0; | 714 | error = 0; |
744 | if (perm == 6) | 715 | if (perm == 6) |
745 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_WRITE_ACL); | 716 | msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE); |
746 | else if (perm == 4) | 717 | else if (perm == 4) |
747 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_ACL); | 718 | msg = tomoyo_path2keyword(TOMOYO_TYPE_READ); |
748 | else if (perm == 2) | 719 | else if (perm == 2) |
749 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_WRITE_ACL); | 720 | msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE); |
750 | else if (perm == 1) | 721 | else if (perm == 1) |
751 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_EXECUTE_ACL); | 722 | msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE); |
752 | else | 723 | else |
753 | BUG(); | 724 | BUG(); |
754 | if (!error) | 725 | if (!error) |
@@ -777,6 +748,8 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, | |||
777 | * @is_delete: True if it is a delete request. | 748 | * @is_delete: True if it is a delete request. |
778 | * | 749 | * |
779 | * Returns 0 on success, negative value otherwise. | 750 | * Returns 0 on success, negative value otherwise. |
751 | * | ||
752 | * Caller holds tomoyo_read_lock(). | ||
780 | */ | 753 | */ |
781 | int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, | 754 | int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, |
782 | const bool is_delete) | 755 | const bool is_delete) |
@@ -795,28 +768,28 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, | |||
795 | if (strncmp(data, "allow_", 6)) | 768 | if (strncmp(data, "allow_", 6)) |
796 | goto out; | 769 | goto out; |
797 | data += 6; | 770 | data += 6; |
798 | for (type = 0; type < TOMOYO_MAX_SINGLE_PATH_OPERATION; type++) { | 771 | for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { |
799 | if (strcmp(data, tomoyo_sp_keyword[type])) | 772 | if (strcmp(data, tomoyo_path_keyword[type])) |
800 | continue; | 773 | continue; |
801 | return tomoyo_update_single_path_acl(type, filename, | 774 | return tomoyo_update_path_acl(type, filename, domain, |
802 | domain, is_delete); | 775 | is_delete); |
803 | } | 776 | } |
804 | filename2 = strchr(filename, ' '); | 777 | filename2 = strchr(filename, ' '); |
805 | if (!filename2) | 778 | if (!filename2) |
806 | goto out; | 779 | goto out; |
807 | *filename2++ = '\0'; | 780 | *filename2++ = '\0'; |
808 | for (type = 0; type < TOMOYO_MAX_DOUBLE_PATH_OPERATION; type++) { | 781 | for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { |
809 | if (strcmp(data, tomoyo_dp_keyword[type])) | 782 | if (strcmp(data, tomoyo_path2_keyword[type])) |
810 | continue; | 783 | continue; |
811 | return tomoyo_update_double_path_acl(type, filename, filename2, | 784 | return tomoyo_update_path2_acl(type, filename, filename2, |
812 | domain, is_delete); | 785 | domain, is_delete); |
813 | } | 786 | } |
814 | out: | 787 | out: |
815 | return -EINVAL; | 788 | return -EINVAL; |
816 | } | 789 | } |
817 | 790 | ||
818 | /** | 791 | /** |
819 | * tomoyo_update_single_path_acl - Update "struct tomoyo_single_path_acl_record" list. | 792 | * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. |
820 | * | 793 | * |
821 | * @type: Type of operation. | 794 | * @type: Type of operation. |
822 | * @filename: Filename. | 795 | * @filename: Filename. |
@@ -824,85 +797,82 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, | |||
824 | * @is_delete: True if it is a delete request. | 797 | * @is_delete: True if it is a delete request. |
825 | * | 798 | * |
826 | * Returns 0 on success, negative value otherwise. | 799 | * Returns 0 on success, negative value otherwise. |
800 | * | ||
801 | * Caller holds tomoyo_read_lock(). | ||
827 | */ | 802 | */ |
828 | static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | 803 | static int tomoyo_update_path_acl(const u8 type, const char *filename, |
829 | struct tomoyo_domain_info * | 804 | struct tomoyo_domain_info *const domain, |
830 | const domain, const bool is_delete) | 805 | const bool is_delete) |
831 | { | 806 | { |
832 | static const u16 rw_mask = | 807 | static const u32 rw_mask = |
833 | (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL); | 808 | (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); |
834 | const struct tomoyo_path_info *saved_filename; | 809 | const struct tomoyo_path_info *saved_filename; |
835 | struct tomoyo_acl_info *ptr; | 810 | struct tomoyo_acl_info *ptr; |
836 | struct tomoyo_single_path_acl_record *acl; | 811 | struct tomoyo_path_acl *entry = NULL; |
837 | int error = -ENOMEM; | 812 | int error = is_delete ? -ENOENT : -ENOMEM; |
838 | const u16 perm = 1 << type; | 813 | const u32 perm = 1 << type; |
839 | 814 | ||
840 | if (!domain) | 815 | if (!domain) |
841 | return -EINVAL; | 816 | return -EINVAL; |
842 | if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__)) | 817 | if (!tomoyo_is_correct_path(filename, 0, 0, 0)) |
843 | return -EINVAL; | 818 | return -EINVAL; |
844 | saved_filename = tomoyo_save_name(filename); | 819 | saved_filename = tomoyo_get_name(filename); |
845 | if (!saved_filename) | 820 | if (!saved_filename) |
846 | return -ENOMEM; | 821 | return -ENOMEM; |
847 | down_write(&tomoyo_domain_acl_info_list_lock); | 822 | if (!is_delete) |
848 | if (is_delete) | 823 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
849 | goto delete; | 824 | mutex_lock(&tomoyo_policy_lock); |
850 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 825 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
851 | if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) | 826 | struct tomoyo_path_acl *acl = |
827 | container_of(ptr, struct tomoyo_path_acl, head); | ||
828 | if (ptr->type != TOMOYO_TYPE_PATH_ACL) | ||
852 | continue; | 829 | continue; |
853 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, | ||
854 | head); | ||
855 | if (acl->filename != saved_filename) | 830 | if (acl->filename != saved_filename) |
856 | continue; | 831 | continue; |
857 | /* Special case. Clear all bits if marked as deleted. */ | 832 | if (is_delete) { |
858 | if (ptr->type & TOMOYO_ACL_DELETED) | 833 | if (perm <= 0xFFFF) |
859 | acl->perm = 0; | 834 | acl->perm &= ~perm; |
860 | acl->perm |= perm; | 835 | else |
861 | if ((acl->perm & rw_mask) == rw_mask) | 836 | acl->perm_high &= ~(perm >> 16); |
862 | acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; | 837 | if ((acl->perm & rw_mask) != rw_mask) |
863 | else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) | 838 | acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); |
864 | acl->perm |= rw_mask; | 839 | else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))) |
865 | ptr->type &= ~TOMOYO_ACL_DELETED; | 840 | acl->perm &= ~rw_mask; |
841 | } else { | ||
842 | if (perm <= 0xFFFF) | ||
843 | acl->perm |= perm; | ||
844 | else | ||
845 | acl->perm_high |= (perm >> 16); | ||
846 | if ((acl->perm & rw_mask) == rw_mask) | ||
847 | acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE; | ||
848 | else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)) | ||
849 | acl->perm |= rw_mask; | ||
850 | } | ||
866 | error = 0; | 851 | error = 0; |
867 | goto out; | 852 | break; |
868 | } | 853 | } |
869 | /* Not found. Append it to the tail. */ | 854 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
870 | acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL); | 855 | entry->head.type = TOMOYO_TYPE_PATH_ACL; |
871 | if (!acl) | 856 | if (perm <= 0xFFFF) |
872 | goto out; | 857 | entry->perm = perm; |
873 | acl->perm = perm; | 858 | else |
874 | if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) | 859 | entry->perm_high = (perm >> 16); |
875 | acl->perm |= rw_mask; | 860 | if (perm == (1 << TOMOYO_TYPE_READ_WRITE)) |
876 | acl->filename = saved_filename; | 861 | entry->perm |= rw_mask; |
877 | list_add_tail(&acl->head.list, &domain->acl_info_list); | 862 | entry->filename = saved_filename; |
878 | error = 0; | 863 | saved_filename = NULL; |
879 | goto out; | 864 | list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); |
880 | delete: | 865 | entry = NULL; |
881 | error = -ENOENT; | ||
882 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | ||
883 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) | ||
884 | continue; | ||
885 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, | ||
886 | head); | ||
887 | if (acl->filename != saved_filename) | ||
888 | continue; | ||
889 | acl->perm &= ~perm; | ||
890 | if ((acl->perm & rw_mask) != rw_mask) | ||
891 | acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); | ||
892 | else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) | ||
893 | acl->perm &= ~rw_mask; | ||
894 | if (!acl->perm) | ||
895 | ptr->type |= TOMOYO_ACL_DELETED; | ||
896 | error = 0; | 866 | error = 0; |
897 | break; | ||
898 | } | 867 | } |
899 | out: | 868 | mutex_unlock(&tomoyo_policy_lock); |
900 | up_write(&tomoyo_domain_acl_info_list_lock); | 869 | kfree(entry); |
870 | tomoyo_put_name(saved_filename); | ||
901 | return error; | 871 | return error; |
902 | } | 872 | } |
903 | 873 | ||
904 | /** | 874 | /** |
905 | * tomoyo_update_double_path_acl - Update "struct tomoyo_double_path_acl_record" list. | 875 | * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. |
906 | * | 876 | * |
907 | * @type: Type of operation. | 877 | * @type: Type of operation. |
908 | * @filename1: First filename. | 878 | * @filename1: First filename. |
@@ -911,98 +881,88 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
911 | * @is_delete: True if it is a delete request. | 881 | * @is_delete: True if it is a delete request. |
912 | * | 882 | * |
913 | * Returns 0 on success, negative value otherwise. | 883 | * Returns 0 on success, negative value otherwise. |
884 | * | ||
885 | * Caller holds tomoyo_read_lock(). | ||
914 | */ | 886 | */ |
915 | static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, | 887 | static int tomoyo_update_path2_acl(const u8 type, const char *filename1, |
916 | const char *filename2, | 888 | const char *filename2, |
917 | struct tomoyo_domain_info * | 889 | struct tomoyo_domain_info *const domain, |
918 | const domain, const bool is_delete) | 890 | const bool is_delete) |
919 | { | 891 | { |
920 | const struct tomoyo_path_info *saved_filename1; | 892 | const struct tomoyo_path_info *saved_filename1; |
921 | const struct tomoyo_path_info *saved_filename2; | 893 | const struct tomoyo_path_info *saved_filename2; |
922 | struct tomoyo_acl_info *ptr; | 894 | struct tomoyo_acl_info *ptr; |
923 | struct tomoyo_double_path_acl_record *acl; | 895 | struct tomoyo_path2_acl *entry = NULL; |
924 | int error = -ENOMEM; | 896 | int error = is_delete ? -ENOENT : -ENOMEM; |
925 | const u8 perm = 1 << type; | 897 | const u8 perm = 1 << type; |
926 | 898 | ||
927 | if (!domain) | 899 | if (!domain) |
928 | return -EINVAL; | 900 | return -EINVAL; |
929 | if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) || | 901 | if (!tomoyo_is_correct_path(filename1, 0, 0, 0) || |
930 | !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__)) | 902 | !tomoyo_is_correct_path(filename2, 0, 0, 0)) |
931 | return -EINVAL; | 903 | return -EINVAL; |
932 | saved_filename1 = tomoyo_save_name(filename1); | 904 | saved_filename1 = tomoyo_get_name(filename1); |
933 | saved_filename2 = tomoyo_save_name(filename2); | 905 | saved_filename2 = tomoyo_get_name(filename2); |
934 | if (!saved_filename1 || !saved_filename2) | 906 | if (!saved_filename1 || !saved_filename2) |
935 | return -ENOMEM; | ||
936 | down_write(&tomoyo_domain_acl_info_list_lock); | ||
937 | if (is_delete) | ||
938 | goto delete; | ||
939 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | ||
940 | if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) | ||
941 | continue; | ||
942 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, | ||
943 | head); | ||
944 | if (acl->filename1 != saved_filename1 || | ||
945 | acl->filename2 != saved_filename2) | ||
946 | continue; | ||
947 | /* Special case. Clear all bits if marked as deleted. */ | ||
948 | if (ptr->type & TOMOYO_ACL_DELETED) | ||
949 | acl->perm = 0; | ||
950 | acl->perm |= perm; | ||
951 | ptr->type &= ~TOMOYO_ACL_DELETED; | ||
952 | error = 0; | ||
953 | goto out; | 907 | goto out; |
954 | } | 908 | if (!is_delete) |
955 | /* Not found. Append it to the tail. */ | 909 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
956 | acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL); | 910 | mutex_lock(&tomoyo_policy_lock); |
957 | if (!acl) | 911 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
958 | goto out; | 912 | struct tomoyo_path2_acl *acl = |
959 | acl->perm = perm; | 913 | container_of(ptr, struct tomoyo_path2_acl, head); |
960 | acl->filename1 = saved_filename1; | 914 | if (ptr->type != TOMOYO_TYPE_PATH2_ACL) |
961 | acl->filename2 = saved_filename2; | ||
962 | list_add_tail(&acl->head.list, &domain->acl_info_list); | ||
963 | error = 0; | ||
964 | goto out; | ||
965 | delete: | ||
966 | error = -ENOENT; | ||
967 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | ||
968 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) | ||
969 | continue; | 915 | continue; |
970 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, | ||
971 | head); | ||
972 | if (acl->filename1 != saved_filename1 || | 916 | if (acl->filename1 != saved_filename1 || |
973 | acl->filename2 != saved_filename2) | 917 | acl->filename2 != saved_filename2) |
974 | continue; | 918 | continue; |
975 | acl->perm &= ~perm; | 919 | if (is_delete) |
976 | if (!acl->perm) | 920 | acl->perm &= ~perm; |
977 | ptr->type |= TOMOYO_ACL_DELETED; | 921 | else |
922 | acl->perm |= perm; | ||
978 | error = 0; | 923 | error = 0; |
979 | break; | 924 | break; |
980 | } | 925 | } |
926 | if (!is_delete && error && tomoyo_memory_ok(entry)) { | ||
927 | entry->head.type = TOMOYO_TYPE_PATH2_ACL; | ||
928 | entry->perm = perm; | ||
929 | entry->filename1 = saved_filename1; | ||
930 | saved_filename1 = NULL; | ||
931 | entry->filename2 = saved_filename2; | ||
932 | saved_filename2 = NULL; | ||
933 | list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); | ||
934 | entry = NULL; | ||
935 | error = 0; | ||
936 | } | ||
937 | mutex_unlock(&tomoyo_policy_lock); | ||
981 | out: | 938 | out: |
982 | up_write(&tomoyo_domain_acl_info_list_lock); | 939 | tomoyo_put_name(saved_filename1); |
940 | tomoyo_put_name(saved_filename2); | ||
941 | kfree(entry); | ||
983 | return error; | 942 | return error; |
984 | } | 943 | } |
985 | 944 | ||
986 | /** | 945 | /** |
987 | * tomoyo_check_single_path_acl - Check permission for single path operation. | 946 | * tomoyo_path_acl - Check permission for single path operation. |
988 | * | 947 | * |
989 | * @domain: Pointer to "struct tomoyo_domain_info". | 948 | * @domain: Pointer to "struct tomoyo_domain_info". |
990 | * @type: Type of operation. | 949 | * @type: Type of operation. |
991 | * @filename: Filename to check. | 950 | * @filename: Filename to check. |
992 | * | 951 | * |
993 | * Returns 0 on success, negative value otherwise. | 952 | * Returns 0 on success, negative value otherwise. |
953 | * | ||
954 | * Caller holds tomoyo_read_lock(). | ||
994 | */ | 955 | */ |
995 | static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, | 956 | static int tomoyo_path_acl(struct tomoyo_domain_info *domain, const u8 type, |
996 | const u8 type, | 957 | const struct tomoyo_path_info *filename) |
997 | const struct tomoyo_path_info *filename) | ||
998 | { | 958 | { |
999 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) | 959 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) |
1000 | return 0; | 960 | return 0; |
1001 | return tomoyo_check_single_path_acl2(domain, filename, 1 << type, 1); | 961 | return tomoyo_path_acl2(domain, filename, 1 << type, 1); |
1002 | } | 962 | } |
1003 | 963 | ||
1004 | /** | 964 | /** |
1005 | * tomoyo_check_double_path_acl - Check permission for double path operation. | 965 | * tomoyo_path2_acl - Check permission for double path operation. |
1006 | * | 966 | * |
1007 | * @domain: Pointer to "struct tomoyo_domain_info". | 967 | * @domain: Pointer to "struct tomoyo_domain_info". |
1008 | * @type: Type of operation. | 968 | * @type: Type of operation. |
@@ -1010,13 +970,13 @@ static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, | |||
1010 | * @filename2: Second filename to check. | 970 | * @filename2: Second filename to check. |
1011 | * | 971 | * |
1012 | * Returns 0 on success, -EPERM otherwise. | 972 | * Returns 0 on success, -EPERM otherwise. |
973 | * | ||
974 | * Caller holds tomoyo_read_lock(). | ||
1013 | */ | 975 | */ |
1014 | static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, | 976 | static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain, |
1015 | const u8 type, | 977 | const u8 type, |
1016 | const struct tomoyo_path_info * | 978 | const struct tomoyo_path_info *filename1, |
1017 | filename1, | 979 | const struct tomoyo_path_info *filename2) |
1018 | const struct tomoyo_path_info * | ||
1019 | filename2) | ||
1020 | { | 980 | { |
1021 | struct tomoyo_acl_info *ptr; | 981 | struct tomoyo_acl_info *ptr; |
1022 | const u8 perm = 1 << type; | 982 | const u8 perm = 1 << type; |
@@ -1024,13 +984,11 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, | |||
1024 | 984 | ||
1025 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) | 985 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) |
1026 | return 0; | 986 | return 0; |
1027 | down_read(&tomoyo_domain_acl_info_list_lock); | 987 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
1028 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 988 | struct tomoyo_path2_acl *acl; |
1029 | struct tomoyo_double_path_acl_record *acl; | 989 | if (ptr->type != TOMOYO_TYPE_PATH2_ACL) |
1030 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) | ||
1031 | continue; | 990 | continue; |
1032 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, | 991 | acl = container_of(ptr, struct tomoyo_path2_acl, head); |
1033 | head); | ||
1034 | if (!(acl->perm & perm)) | 992 | if (!(acl->perm & perm)) |
1035 | continue; | 993 | continue; |
1036 | if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) | 994 | if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) |
@@ -1040,12 +998,11 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, | |||
1040 | error = 0; | 998 | error = 0; |
1041 | break; | 999 | break; |
1042 | } | 1000 | } |
1043 | up_read(&tomoyo_domain_acl_info_list_lock); | ||
1044 | return error; | 1001 | return error; |
1045 | } | 1002 | } |
1046 | 1003 | ||
1047 | /** | 1004 | /** |
1048 | * tomoyo_check_single_path_permission2 - Check permission for single path operation. | 1005 | * tomoyo_path_permission2 - Check permission for single path operation. |
1049 | * | 1006 | * |
1050 | * @domain: Pointer to "struct tomoyo_domain_info". | 1007 | * @domain: Pointer to "struct tomoyo_domain_info". |
1051 | * @operation: Type of operation. | 1008 | * @operation: Type of operation. |
@@ -1053,11 +1010,13 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, | |||
1053 | * @mode: Access control mode. | 1010 | * @mode: Access control mode. |
1054 | * | 1011 | * |
1055 | * Returns 0 on success, negative value otherwise. | 1012 | * Returns 0 on success, negative value otherwise. |
1013 | * | ||
1014 | * Caller holds tomoyo_read_lock(). | ||
1056 | */ | 1015 | */ |
1057 | static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | 1016 | static int tomoyo_path_permission2(struct tomoyo_domain_info *const domain, |
1058 | const domain, u8 operation, | 1017 | u8 operation, |
1059 | const struct tomoyo_path_info * | 1018 | const struct tomoyo_path_info *filename, |
1060 | filename, const u8 mode) | 1019 | const u8 mode) |
1061 | { | 1020 | { |
1062 | const char *msg; | 1021 | const char *msg; |
1063 | int error; | 1022 | int error; |
@@ -1066,8 +1025,8 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | |||
1066 | if (!mode) | 1025 | if (!mode) |
1067 | return 0; | 1026 | return 0; |
1068 | next: | 1027 | next: |
1069 | error = tomoyo_check_single_path_acl(domain, operation, filename); | 1028 | error = tomoyo_path_acl(domain, operation, filename); |
1070 | msg = tomoyo_sp2keyword(operation); | 1029 | msg = tomoyo_path2keyword(operation); |
1071 | if (!error) | 1030 | if (!error) |
1072 | goto ok; | 1031 | goto ok; |
1073 | if (tomoyo_verbose_mode(domain)) | 1032 | if (tomoyo_verbose_mode(domain)) |
@@ -1076,7 +1035,7 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | |||
1076 | tomoyo_get_last_name(domain)); | 1035 | tomoyo_get_last_name(domain)); |
1077 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { | 1036 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { |
1078 | const char *name = tomoyo_get_file_pattern(filename)->name; | 1037 | const char *name = tomoyo_get_file_pattern(filename)->name; |
1079 | tomoyo_update_single_path_acl(operation, name, domain, false); | 1038 | tomoyo_update_path_acl(operation, name, domain, false); |
1080 | } | 1039 | } |
1081 | if (!is_enforce) | 1040 | if (!is_enforce) |
1082 | error = 0; | 1041 | error = 0; |
@@ -1086,9 +1045,9 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | |||
1086 | * we need to check "allow_rewrite" permission if the filename is | 1045 | * we need to check "allow_rewrite" permission if the filename is |
1087 | * specified by "deny_rewrite" keyword. | 1046 | * specified by "deny_rewrite" keyword. |
1088 | */ | 1047 | */ |
1089 | if (!error && operation == TOMOYO_TYPE_TRUNCATE_ACL && | 1048 | if (!error && operation == TOMOYO_TYPE_TRUNCATE && |
1090 | tomoyo_is_no_rewrite_file(filename)) { | 1049 | tomoyo_is_no_rewrite_file(filename)) { |
1091 | operation = TOMOYO_TYPE_REWRITE_ACL; | 1050 | operation = TOMOYO_TYPE_REWRITE; |
1092 | goto next; | 1051 | goto next; |
1093 | } | 1052 | } |
1094 | return error; | 1053 | return error; |
@@ -1101,6 +1060,8 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | |||
1101 | * @filename: Check permission for "execute". | 1060 | * @filename: Check permission for "execute". |
1102 | * | 1061 | * |
1103 | * Returns 0 on success, negativevalue otherwise. | 1062 | * Returns 0 on success, negativevalue otherwise. |
1063 | * | ||
1064 | * Caller holds tomoyo_read_lock(). | ||
1104 | */ | 1065 | */ |
1105 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, | 1066 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, |
1106 | const struct tomoyo_path_info *filename) | 1067 | const struct tomoyo_path_info *filename) |
@@ -1129,6 +1090,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
1129 | struct tomoyo_path_info *buf; | 1090 | struct tomoyo_path_info *buf; |
1130 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1091 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1131 | const bool is_enforce = (mode == 3); | 1092 | const bool is_enforce = (mode == 3); |
1093 | int idx; | ||
1132 | 1094 | ||
1133 | if (!mode || !path->mnt) | 1095 | if (!mode || !path->mnt) |
1134 | return 0; | 1096 | return 0; |
@@ -1140,6 +1102,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
1140 | * don't call me. | 1102 | * don't call me. |
1141 | */ | 1103 | */ |
1142 | return 0; | 1104 | return 0; |
1105 | idx = tomoyo_read_lock(); | ||
1143 | buf = tomoyo_get_path(path); | 1106 | buf = tomoyo_get_path(path); |
1144 | if (!buf) | 1107 | if (!buf) |
1145 | goto out; | 1108 | goto out; |
@@ -1152,49 +1115,50 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
1152 | if ((acc_mode & MAY_WRITE) && | 1115 | if ((acc_mode & MAY_WRITE) && |
1153 | ((flag & O_TRUNC) || !(flag & O_APPEND)) && | 1116 | ((flag & O_TRUNC) || !(flag & O_APPEND)) && |
1154 | (tomoyo_is_no_rewrite_file(buf))) { | 1117 | (tomoyo_is_no_rewrite_file(buf))) { |
1155 | error = tomoyo_check_single_path_permission2(domain, | 1118 | error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, |
1156 | TOMOYO_TYPE_REWRITE_ACL, | 1119 | buf, mode); |
1157 | buf, mode); | ||
1158 | } | 1120 | } |
1159 | if (!error) | 1121 | if (!error) |
1160 | error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", | 1122 | error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", |
1161 | mode); | 1123 | mode); |
1162 | if (!error && (flag & O_TRUNC)) | 1124 | if (!error && (flag & O_TRUNC)) |
1163 | error = tomoyo_check_single_path_permission2(domain, | 1125 | error = tomoyo_path_permission2(domain, TOMOYO_TYPE_TRUNCATE, |
1164 | TOMOYO_TYPE_TRUNCATE_ACL, | 1126 | buf, mode); |
1165 | buf, mode); | ||
1166 | out: | 1127 | out: |
1167 | tomoyo_free(buf); | 1128 | kfree(buf); |
1129 | tomoyo_read_unlock(idx); | ||
1168 | if (!is_enforce) | 1130 | if (!is_enforce) |
1169 | error = 0; | 1131 | error = 0; |
1170 | return error; | 1132 | return error; |
1171 | } | 1133 | } |
1172 | 1134 | ||
1173 | /** | 1135 | /** |
1174 | * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate" and "symlink". | 1136 | * tomoyo_path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount". |
1175 | * | 1137 | * |
1176 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1177 | * @operation: Type of operation. | 1138 | * @operation: Type of operation. |
1178 | * @path: Pointer to "struct path". | 1139 | * @path: Pointer to "struct path". |
1179 | * | 1140 | * |
1180 | * Returns 0 on success, negative value otherwise. | 1141 | * Returns 0 on success, negative value otherwise. |
1181 | */ | 1142 | */ |
1182 | int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, | 1143 | int tomoyo_path_perm(const u8 operation, struct path *path) |
1183 | const u8 operation, struct path *path) | ||
1184 | { | 1144 | { |
1185 | int error = -ENOMEM; | 1145 | int error = -ENOMEM; |
1186 | struct tomoyo_path_info *buf; | 1146 | struct tomoyo_path_info *buf; |
1147 | struct tomoyo_domain_info *domain = tomoyo_domain(); | ||
1187 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1148 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1188 | const bool is_enforce = (mode == 3); | 1149 | const bool is_enforce = (mode == 3); |
1150 | int idx; | ||
1189 | 1151 | ||
1190 | if (!mode || !path->mnt) | 1152 | if (!mode || !path->mnt) |
1191 | return 0; | 1153 | return 0; |
1154 | idx = tomoyo_read_lock(); | ||
1192 | buf = tomoyo_get_path(path); | 1155 | buf = tomoyo_get_path(path); |
1193 | if (!buf) | 1156 | if (!buf) |
1194 | goto out; | 1157 | goto out; |
1195 | switch (operation) { | 1158 | switch (operation) { |
1196 | case TOMOYO_TYPE_MKDIR_ACL: | 1159 | case TOMOYO_TYPE_MKDIR: |
1197 | case TOMOYO_TYPE_RMDIR_ACL: | 1160 | case TOMOYO_TYPE_RMDIR: |
1161 | case TOMOYO_TYPE_CHROOT: | ||
1198 | if (!buf->is_dir) { | 1162 | if (!buf->is_dir) { |
1199 | /* | 1163 | /* |
1200 | * tomoyo_get_path() reserves space for appending "/." | 1164 | * tomoyo_get_path() reserves space for appending "/." |
@@ -1203,10 +1167,10 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, | |||
1203 | tomoyo_fill_path_info(buf); | 1167 | tomoyo_fill_path_info(buf); |
1204 | } | 1168 | } |
1205 | } | 1169 | } |
1206 | error = tomoyo_check_single_path_permission2(domain, operation, buf, | 1170 | error = tomoyo_path_permission2(domain, operation, buf, mode); |
1207 | mode); | ||
1208 | out: | 1171 | out: |
1209 | tomoyo_free(buf); | 1172 | kfree(buf); |
1173 | tomoyo_read_unlock(idx); | ||
1210 | if (!is_enforce) | 1174 | if (!is_enforce) |
1211 | error = 0; | 1175 | error = 0; |
1212 | return error; | 1176 | return error; |
@@ -1215,21 +1179,23 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, | |||
1215 | /** | 1179 | /** |
1216 | * tomoyo_check_rewrite_permission - Check permission for "rewrite". | 1180 | * tomoyo_check_rewrite_permission - Check permission for "rewrite". |
1217 | * | 1181 | * |
1218 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1219 | * @filp: Pointer to "struct file". | 1182 | * @filp: Pointer to "struct file". |
1220 | * | 1183 | * |
1221 | * Returns 0 on success, negative value otherwise. | 1184 | * Returns 0 on success, negative value otherwise. |
1222 | */ | 1185 | */ |
1223 | int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, | 1186 | int tomoyo_check_rewrite_permission(struct file *filp) |
1224 | struct file *filp) | ||
1225 | { | 1187 | { |
1226 | int error = -ENOMEM; | 1188 | int error = -ENOMEM; |
1189 | struct tomoyo_domain_info *domain = tomoyo_domain(); | ||
1227 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1190 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1228 | const bool is_enforce = (mode == 3); | 1191 | const bool is_enforce = (mode == 3); |
1229 | struct tomoyo_path_info *buf; | 1192 | struct tomoyo_path_info *buf; |
1193 | int idx; | ||
1230 | 1194 | ||
1231 | if (!mode || !filp->f_path.mnt) | 1195 | if (!mode || !filp->f_path.mnt) |
1232 | return 0; | 1196 | return 0; |
1197 | |||
1198 | idx = tomoyo_read_lock(); | ||
1233 | buf = tomoyo_get_path(&filp->f_path); | 1199 | buf = tomoyo_get_path(&filp->f_path); |
1234 | if (!buf) | 1200 | if (!buf) |
1235 | goto out; | 1201 | goto out; |
@@ -1237,38 +1203,38 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, | |||
1237 | error = 0; | 1203 | error = 0; |
1238 | goto out; | 1204 | goto out; |
1239 | } | 1205 | } |
1240 | error = tomoyo_check_single_path_permission2(domain, | 1206 | error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, buf, mode); |
1241 | TOMOYO_TYPE_REWRITE_ACL, | ||
1242 | buf, mode); | ||
1243 | out: | 1207 | out: |
1244 | tomoyo_free(buf); | 1208 | kfree(buf); |
1209 | tomoyo_read_unlock(idx); | ||
1245 | if (!is_enforce) | 1210 | if (!is_enforce) |
1246 | error = 0; | 1211 | error = 0; |
1247 | return error; | 1212 | return error; |
1248 | } | 1213 | } |
1249 | 1214 | ||
1250 | /** | 1215 | /** |
1251 | * tomoyo_check_2path_perm - Check permission for "rename" and "link". | 1216 | * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". |
1252 | * | 1217 | * |
1253 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1254 | * @operation: Type of operation. | 1218 | * @operation: Type of operation. |
1255 | * @path1: Pointer to "struct path". | 1219 | * @path1: Pointer to "struct path". |
1256 | * @path2: Pointer to "struct path". | 1220 | * @path2: Pointer to "struct path". |
1257 | * | 1221 | * |
1258 | * Returns 0 on success, negative value otherwise. | 1222 | * Returns 0 on success, negative value otherwise. |
1259 | */ | 1223 | */ |
1260 | int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, | 1224 | int tomoyo_path2_perm(const u8 operation, struct path *path1, |
1261 | const u8 operation, struct path *path1, | 1225 | struct path *path2) |
1262 | struct path *path2) | ||
1263 | { | 1226 | { |
1264 | int error = -ENOMEM; | 1227 | int error = -ENOMEM; |
1265 | struct tomoyo_path_info *buf1, *buf2; | 1228 | struct tomoyo_path_info *buf1, *buf2; |
1229 | struct tomoyo_domain_info *domain = tomoyo_domain(); | ||
1266 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1230 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1267 | const bool is_enforce = (mode == 3); | 1231 | const bool is_enforce = (mode == 3); |
1268 | const char *msg; | 1232 | const char *msg; |
1233 | int idx; | ||
1269 | 1234 | ||
1270 | if (!mode || !path1->mnt || !path2->mnt) | 1235 | if (!mode || !path1->mnt || !path2->mnt) |
1271 | return 0; | 1236 | return 0; |
1237 | idx = tomoyo_read_lock(); | ||
1272 | buf1 = tomoyo_get_path(path1); | 1238 | buf1 = tomoyo_get_path(path1); |
1273 | buf2 = tomoyo_get_path(path2); | 1239 | buf2 = tomoyo_get_path(path2); |
1274 | if (!buf1 || !buf2) | 1240 | if (!buf1 || !buf2) |
@@ -1289,8 +1255,8 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, | |||
1289 | } | 1255 | } |
1290 | } | 1256 | } |
1291 | } | 1257 | } |
1292 | error = tomoyo_check_double_path_acl(domain, operation, buf1, buf2); | 1258 | error = tomoyo_path2_acl(domain, operation, buf1, buf2); |
1293 | msg = tomoyo_dp2keyword(operation); | 1259 | msg = tomoyo_path22keyword(operation); |
1294 | if (!error) | 1260 | if (!error) |
1295 | goto out; | 1261 | goto out; |
1296 | if (tomoyo_verbose_mode(domain)) | 1262 | if (tomoyo_verbose_mode(domain)) |
@@ -1301,12 +1267,13 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, | |||
1301 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { | 1267 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { |
1302 | const char *name1 = tomoyo_get_file_pattern(buf1)->name; | 1268 | const char *name1 = tomoyo_get_file_pattern(buf1)->name; |
1303 | const char *name2 = tomoyo_get_file_pattern(buf2)->name; | 1269 | const char *name2 = tomoyo_get_file_pattern(buf2)->name; |
1304 | tomoyo_update_double_path_acl(operation, name1, name2, domain, | 1270 | tomoyo_update_path2_acl(operation, name1, name2, domain, |
1305 | false); | 1271 | false); |
1306 | } | 1272 | } |
1307 | out: | 1273 | out: |
1308 | tomoyo_free(buf1); | 1274 | kfree(buf1); |
1309 | tomoyo_free(buf2); | 1275 | kfree(buf2); |
1276 | tomoyo_read_unlock(idx); | ||
1310 | if (!is_enforce) | 1277 | if (!is_enforce) |
1311 | error = 0; | 1278 | error = 0; |
1312 | return error; | 1279 | return error; |
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c new file mode 100644 index 000000000000..9645525ccdd4 --- /dev/null +++ b/security/tomoyo/gc.c | |||
@@ -0,0 +1,370 @@ | |||
1 | /* | ||
2 | * security/tomoyo/gc.c | ||
3 | * | ||
4 | * Implementation of the Domain-Based Mandatory Access Control. | ||
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include "common.h" | ||
11 | #include <linux/kthread.h> | ||
12 | |||
13 | enum tomoyo_gc_id { | ||
14 | TOMOYO_ID_DOMAIN_INITIALIZER, | ||
15 | TOMOYO_ID_DOMAIN_KEEPER, | ||
16 | TOMOYO_ID_ALIAS, | ||
17 | TOMOYO_ID_GLOBALLY_READABLE, | ||
18 | TOMOYO_ID_PATTERN, | ||
19 | TOMOYO_ID_NO_REWRITE, | ||
20 | TOMOYO_ID_MANAGER, | ||
21 | TOMOYO_ID_NAME, | ||
22 | TOMOYO_ID_ACL, | ||
23 | TOMOYO_ID_DOMAIN | ||
24 | }; | ||
25 | |||
26 | struct tomoyo_gc_entry { | ||
27 | struct list_head list; | ||
28 | int type; | ||
29 | void *element; | ||
30 | }; | ||
31 | static LIST_HEAD(tomoyo_gc_queue); | ||
32 | static DEFINE_MUTEX(tomoyo_gc_mutex); | ||
33 | |||
34 | /* Caller holds tomoyo_policy_lock mutex. */ | ||
35 | static bool tomoyo_add_to_gc(const int type, void *element) | ||
36 | { | ||
37 | struct tomoyo_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | ||
38 | if (!entry) | ||
39 | return false; | ||
40 | entry->type = type; | ||
41 | entry->element = element; | ||
42 | list_add(&entry->list, &tomoyo_gc_queue); | ||
43 | return true; | ||
44 | } | ||
45 | |||
46 | static void tomoyo_del_allow_read | ||
47 | (struct tomoyo_globally_readable_file_entry *ptr) | ||
48 | { | ||
49 | tomoyo_put_name(ptr->filename); | ||
50 | } | ||
51 | |||
52 | static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr) | ||
53 | { | ||
54 | tomoyo_put_name(ptr->pattern); | ||
55 | } | ||
56 | |||
57 | static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr) | ||
58 | { | ||
59 | tomoyo_put_name(ptr->pattern); | ||
60 | } | ||
61 | |||
62 | static void tomoyo_del_domain_initializer | ||
63 | (struct tomoyo_domain_initializer_entry *ptr) | ||
64 | { | ||
65 | tomoyo_put_name(ptr->domainname); | ||
66 | tomoyo_put_name(ptr->program); | ||
67 | } | ||
68 | |||
69 | static void tomoyo_del_domain_keeper(struct tomoyo_domain_keeper_entry *ptr) | ||
70 | { | ||
71 | tomoyo_put_name(ptr->domainname); | ||
72 | tomoyo_put_name(ptr->program); | ||
73 | } | ||
74 | |||
75 | static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr) | ||
76 | { | ||
77 | tomoyo_put_name(ptr->original_name); | ||
78 | tomoyo_put_name(ptr->aliased_name); | ||
79 | } | ||
80 | |||
81 | static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr) | ||
82 | { | ||
83 | tomoyo_put_name(ptr->manager); | ||
84 | } | ||
85 | |||
86 | static void tomoyo_del_acl(struct tomoyo_acl_info *acl) | ||
87 | { | ||
88 | switch (acl->type) { | ||
89 | case TOMOYO_TYPE_PATH_ACL: | ||
90 | { | ||
91 | struct tomoyo_path_acl *entry | ||
92 | = container_of(acl, typeof(*entry), head); | ||
93 | tomoyo_put_name(entry->filename); | ||
94 | } | ||
95 | break; | ||
96 | case TOMOYO_TYPE_PATH2_ACL: | ||
97 | { | ||
98 | struct tomoyo_path2_acl *entry | ||
99 | = container_of(acl, typeof(*entry), head); | ||
100 | tomoyo_put_name(entry->filename1); | ||
101 | tomoyo_put_name(entry->filename2); | ||
102 | } | ||
103 | break; | ||
104 | default: | ||
105 | printk(KERN_WARNING "Unknown type\n"); | ||
106 | break; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | static bool tomoyo_del_domain(struct tomoyo_domain_info *domain) | ||
111 | { | ||
112 | struct tomoyo_acl_info *acl; | ||
113 | struct tomoyo_acl_info *tmp; | ||
114 | /* | ||
115 | * Since we don't protect whole execve() operation using SRCU, | ||
116 | * we need to recheck domain->users at this point. | ||
117 | * | ||
118 | * (1) Reader starts SRCU section upon execve(). | ||
119 | * (2) Reader traverses tomoyo_domain_list and finds this domain. | ||
120 | * (3) Writer marks this domain as deleted. | ||
121 | * (4) Garbage collector removes this domain from tomoyo_domain_list | ||
122 | * because this domain is marked as deleted and used by nobody. | ||
123 | * (5) Reader saves reference to this domain into | ||
124 | * "struct linux_binprm"->cred->security . | ||
125 | * (6) Reader finishes SRCU section, although execve() operation has | ||
126 | * not finished yet. | ||
127 | * (7) Garbage collector waits for SRCU synchronization. | ||
128 | * (8) Garbage collector kfree() this domain because this domain is | ||
129 | * used by nobody. | ||
130 | * (9) Reader finishes execve() operation and restores this domain from | ||
131 | * "struct linux_binprm"->cred->security. | ||
132 | * | ||
133 | * By updating domain->users at (5), we can solve this race problem | ||
134 | * by rechecking domain->users at (8). | ||
135 | */ | ||
136 | if (atomic_read(&domain->users)) | ||
137 | return false; | ||
138 | list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { | ||
139 | tomoyo_del_acl(acl); | ||
140 | tomoyo_memory_free(acl); | ||
141 | } | ||
142 | tomoyo_put_name(domain->domainname); | ||
143 | return true; | ||
144 | } | ||
145 | |||
146 | |||
147 | static void tomoyo_del_name(const struct tomoyo_name_entry *ptr) | ||
148 | { | ||
149 | } | ||
150 | |||
151 | static void tomoyo_collect_entry(void) | ||
152 | { | ||
153 | mutex_lock(&tomoyo_policy_lock); | ||
154 | { | ||
155 | struct tomoyo_globally_readable_file_entry *ptr; | ||
156 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, | ||
157 | list) { | ||
158 | if (!ptr->is_deleted) | ||
159 | continue; | ||
160 | if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr)) | ||
161 | list_del_rcu(&ptr->list); | ||
162 | else | ||
163 | break; | ||
164 | } | ||
165 | } | ||
166 | { | ||
167 | struct tomoyo_pattern_entry *ptr; | ||
168 | list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { | ||
169 | if (!ptr->is_deleted) | ||
170 | continue; | ||
171 | if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr)) | ||
172 | list_del_rcu(&ptr->list); | ||
173 | else | ||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | { | ||
178 | struct tomoyo_no_rewrite_entry *ptr; | ||
179 | list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { | ||
180 | if (!ptr->is_deleted) | ||
181 | continue; | ||
182 | if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr)) | ||
183 | list_del_rcu(&ptr->list); | ||
184 | else | ||
185 | break; | ||
186 | } | ||
187 | } | ||
188 | { | ||
189 | struct tomoyo_domain_initializer_entry *ptr; | ||
190 | list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, | ||
191 | list) { | ||
192 | if (!ptr->is_deleted) | ||
193 | continue; | ||
194 | if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr)) | ||
195 | list_del_rcu(&ptr->list); | ||
196 | else | ||
197 | break; | ||
198 | } | ||
199 | } | ||
200 | { | ||
201 | struct tomoyo_domain_keeper_entry *ptr; | ||
202 | list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { | ||
203 | if (!ptr->is_deleted) | ||
204 | continue; | ||
205 | if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr)) | ||
206 | list_del_rcu(&ptr->list); | ||
207 | else | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | { | ||
212 | struct tomoyo_alias_entry *ptr; | ||
213 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { | ||
214 | if (!ptr->is_deleted) | ||
215 | continue; | ||
216 | if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr)) | ||
217 | list_del_rcu(&ptr->list); | ||
218 | else | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | { | ||
223 | struct tomoyo_policy_manager_entry *ptr; | ||
224 | list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, | ||
225 | list) { | ||
226 | if (!ptr->is_deleted) | ||
227 | continue; | ||
228 | if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr)) | ||
229 | list_del_rcu(&ptr->list); | ||
230 | else | ||
231 | break; | ||
232 | } | ||
233 | } | ||
234 | { | ||
235 | struct tomoyo_domain_info *domain; | ||
236 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | ||
237 | struct tomoyo_acl_info *acl; | ||
238 | list_for_each_entry_rcu(acl, &domain->acl_info_list, | ||
239 | list) { | ||
240 | switch (acl->type) { | ||
241 | case TOMOYO_TYPE_PATH_ACL: | ||
242 | if (container_of(acl, | ||
243 | struct tomoyo_path_acl, | ||
244 | head)->perm || | ||
245 | container_of(acl, | ||
246 | struct tomoyo_path_acl, | ||
247 | head)->perm_high) | ||
248 | continue; | ||
249 | break; | ||
250 | case TOMOYO_TYPE_PATH2_ACL: | ||
251 | if (container_of(acl, | ||
252 | struct tomoyo_path2_acl, | ||
253 | head)->perm) | ||
254 | continue; | ||
255 | break; | ||
256 | default: | ||
257 | continue; | ||
258 | } | ||
259 | if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl)) | ||
260 | list_del_rcu(&acl->list); | ||
261 | else | ||
262 | break; | ||
263 | } | ||
264 | if (!domain->is_deleted || atomic_read(&domain->users)) | ||
265 | continue; | ||
266 | /* | ||
267 | * Nobody is referring this domain. But somebody may | ||
268 | * refer this domain after successful execve(). | ||
269 | * We recheck domain->users after SRCU synchronization. | ||
270 | */ | ||
271 | if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain)) | ||
272 | list_del_rcu(&domain->list); | ||
273 | else | ||
274 | break; | ||
275 | } | ||
276 | } | ||
277 | mutex_unlock(&tomoyo_policy_lock); | ||
278 | mutex_lock(&tomoyo_name_list_lock); | ||
279 | { | ||
280 | int i; | ||
281 | for (i = 0; i < TOMOYO_MAX_HASH; i++) { | ||
282 | struct tomoyo_name_entry *ptr; | ||
283 | list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], | ||
284 | list) { | ||
285 | if (atomic_read(&ptr->users)) | ||
286 | continue; | ||
287 | if (tomoyo_add_to_gc(TOMOYO_ID_NAME, ptr)) | ||
288 | list_del_rcu(&ptr->list); | ||
289 | else { | ||
290 | i = TOMOYO_MAX_HASH; | ||
291 | break; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | mutex_unlock(&tomoyo_name_list_lock); | ||
297 | } | ||
298 | |||
299 | static void tomoyo_kfree_entry(void) | ||
300 | { | ||
301 | struct tomoyo_gc_entry *p; | ||
302 | struct tomoyo_gc_entry *tmp; | ||
303 | |||
304 | list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) { | ||
305 | switch (p->type) { | ||
306 | case TOMOYO_ID_DOMAIN_INITIALIZER: | ||
307 | tomoyo_del_domain_initializer(p->element); | ||
308 | break; | ||
309 | case TOMOYO_ID_DOMAIN_KEEPER: | ||
310 | tomoyo_del_domain_keeper(p->element); | ||
311 | break; | ||
312 | case TOMOYO_ID_ALIAS: | ||
313 | tomoyo_del_alias(p->element); | ||
314 | break; | ||
315 | case TOMOYO_ID_GLOBALLY_READABLE: | ||
316 | tomoyo_del_allow_read(p->element); | ||
317 | break; | ||
318 | case TOMOYO_ID_PATTERN: | ||
319 | tomoyo_del_file_pattern(p->element); | ||
320 | break; | ||
321 | case TOMOYO_ID_NO_REWRITE: | ||
322 | tomoyo_del_no_rewrite(p->element); | ||
323 | break; | ||
324 | case TOMOYO_ID_MANAGER: | ||
325 | tomoyo_del_manager(p->element); | ||
326 | break; | ||
327 | case TOMOYO_ID_NAME: | ||
328 | tomoyo_del_name(p->element); | ||
329 | break; | ||
330 | case TOMOYO_ID_ACL: | ||
331 | tomoyo_del_acl(p->element); | ||
332 | break; | ||
333 | case TOMOYO_ID_DOMAIN: | ||
334 | if (!tomoyo_del_domain(p->element)) | ||
335 | continue; | ||
336 | break; | ||
337 | default: | ||
338 | printk(KERN_WARNING "Unknown type\n"); | ||
339 | break; | ||
340 | } | ||
341 | tomoyo_memory_free(p->element); | ||
342 | list_del(&p->list); | ||
343 | kfree(p); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | static int tomoyo_gc_thread(void *unused) | ||
348 | { | ||
349 | daemonize("GC for TOMOYO"); | ||
350 | if (mutex_trylock(&tomoyo_gc_mutex)) { | ||
351 | int i; | ||
352 | for (i = 0; i < 10; i++) { | ||
353 | tomoyo_collect_entry(); | ||
354 | if (list_empty(&tomoyo_gc_queue)) | ||
355 | break; | ||
356 | synchronize_srcu(&tomoyo_ss); | ||
357 | tomoyo_kfree_entry(); | ||
358 | } | ||
359 | mutex_unlock(&tomoyo_gc_mutex); | ||
360 | } | ||
361 | do_exit(0); | ||
362 | } | ||
363 | |||
364 | void tomoyo_run_gc(void) | ||
365 | { | ||
366 | struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL, | ||
367 | "GC for TOMOYO"); | ||
368 | if (!IS_ERR(task)) | ||
369 | wake_up_process(task); | ||
370 | } | ||
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 18369d497eb8..c00df45c7ede 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -14,9 +14,8 @@ | |||
14 | #include <linux/mnt_namespace.h> | 14 | #include <linux/mnt_namespace.h> |
15 | #include <linux/fs_struct.h> | 15 | #include <linux/fs_struct.h> |
16 | #include <linux/hash.h> | 16 | #include <linux/hash.h> |
17 | 17 | #include <linux/magic.h> | |
18 | #include "common.h" | 18 | #include "common.h" |
19 | #include "realpath.h" | ||
20 | 19 | ||
21 | /** | 20 | /** |
22 | * tomoyo_encode: Convert binary string to ascii string. | 21 | * tomoyo_encode: Convert binary string to ascii string. |
@@ -112,7 +111,7 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname, | |||
112 | path_put(&ns_root); | 111 | path_put(&ns_root); |
113 | /* Prepend "/proc" prefix if using internal proc vfs mount. */ | 112 | /* Prepend "/proc" prefix if using internal proc vfs mount. */ |
114 | if (!IS_ERR(sp) && (path->mnt->mnt_parent == path->mnt) && | 113 | if (!IS_ERR(sp) && (path->mnt->mnt_parent == path->mnt) && |
115 | (strcmp(path->mnt->mnt_sb->s_type->name, "proc") == 0)) { | 114 | (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) { |
116 | sp -= 5; | 115 | sp -= 5; |
117 | if (sp >= newname) | 116 | if (sp >= newname) |
118 | memcpy(sp, "/proc", 5); | 117 | memcpy(sp, "/proc", 5); |
@@ -149,12 +148,12 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname, | |||
149 | * | 148 | * |
150 | * Returns the realpath of the given @path on success, NULL otherwise. | 149 | * Returns the realpath of the given @path on success, NULL otherwise. |
151 | * | 150 | * |
152 | * These functions use tomoyo_alloc(), so the caller must call tomoyo_free() | 151 | * These functions use kzalloc(), so the caller must call kfree() |
153 | * if these functions didn't return NULL. | 152 | * if these functions didn't return NULL. |
154 | */ | 153 | */ |
155 | char *tomoyo_realpath_from_path(struct path *path) | 154 | char *tomoyo_realpath_from_path(struct path *path) |
156 | { | 155 | { |
157 | char *buf = tomoyo_alloc(sizeof(struct tomoyo_page_buffer)); | 156 | char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_KERNEL); |
158 | 157 | ||
159 | BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) | 158 | BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) |
160 | <= TOMOYO_MAX_PATHNAME_LEN - 1); | 159 | <= TOMOYO_MAX_PATHNAME_LEN - 1); |
@@ -163,7 +162,7 @@ char *tomoyo_realpath_from_path(struct path *path) | |||
163 | if (tomoyo_realpath_from_path2(path, buf, | 162 | if (tomoyo_realpath_from_path2(path, buf, |
164 | TOMOYO_MAX_PATHNAME_LEN - 1) == 0) | 163 | TOMOYO_MAX_PATHNAME_LEN - 1) == 0) |
165 | return buf; | 164 | return buf; |
166 | tomoyo_free(buf); | 165 | kfree(buf); |
167 | return NULL; | 166 | return NULL; |
168 | } | 167 | } |
169 | 168 | ||
@@ -206,98 +205,47 @@ char *tomoyo_realpath_nofollow(const char *pathname) | |||
206 | } | 205 | } |
207 | 206 | ||
208 | /* Memory allocated for non-string data. */ | 207 | /* Memory allocated for non-string data. */ |
209 | static unsigned int tomoyo_allocated_memory_for_elements; | 208 | static atomic_t tomoyo_policy_memory_size; |
210 | /* Quota for holding non-string data. */ | 209 | /* Quota for holding policy. */ |
211 | static unsigned int tomoyo_quota_for_elements; | 210 | static unsigned int tomoyo_quota_for_policy; |
212 | 211 | ||
213 | /** | 212 | /** |
214 | * tomoyo_alloc_element - Allocate permanent memory for structures. | 213 | * tomoyo_memory_ok - Check memory quota. |
215 | * | 214 | * |
216 | * @size: Size in bytes. | 215 | * @ptr: Pointer to allocated memory. |
217 | * | 216 | * |
218 | * Returns pointer to allocated memory on success, NULL otherwise. | 217 | * Returns true on success, false otherwise. |
219 | * | 218 | * |
220 | * Memory has to be zeroed. | 219 | * Caller holds tomoyo_policy_lock. |
221 | * The RAM is chunked, so NEVER try to kfree() the returned pointer. | 220 | * Memory pointed by @ptr will be zeroed on success. |
222 | */ | 221 | */ |
223 | void *tomoyo_alloc_element(const unsigned int size) | 222 | bool tomoyo_memory_ok(void *ptr) |
224 | { | 223 | { |
225 | static char *buf; | 224 | int allocated_len = ptr ? ksize(ptr) : 0; |
226 | static DEFINE_MUTEX(lock); | 225 | atomic_add(allocated_len, &tomoyo_policy_memory_size); |
227 | static unsigned int buf_used_len = PATH_MAX; | 226 | if (ptr && (!tomoyo_quota_for_policy || |
228 | char *ptr = NULL; | 227 | atomic_read(&tomoyo_policy_memory_size) |
229 | /*Assumes sizeof(void *) >= sizeof(long) is true. */ | 228 | <= tomoyo_quota_for_policy)) { |
230 | const unsigned int word_aligned_size | 229 | memset(ptr, 0, allocated_len); |
231 | = roundup(size, max(sizeof(void *), sizeof(long))); | 230 | return true; |
232 | if (word_aligned_size > PATH_MAX) | ||
233 | return NULL; | ||
234 | mutex_lock(&lock); | ||
235 | if (buf_used_len + word_aligned_size > PATH_MAX) { | ||
236 | if (!tomoyo_quota_for_elements || | ||
237 | tomoyo_allocated_memory_for_elements | ||
238 | + PATH_MAX <= tomoyo_quota_for_elements) | ||
239 | ptr = kzalloc(PATH_MAX, GFP_KERNEL); | ||
240 | if (!ptr) { | ||
241 | printk(KERN_WARNING "ERROR: Out of memory " | ||
242 | "for tomoyo_alloc_element().\n"); | ||
243 | if (!tomoyo_policy_loaded) | ||
244 | panic("MAC Initialization failed.\n"); | ||
245 | } else { | ||
246 | buf = ptr; | ||
247 | tomoyo_allocated_memory_for_elements += PATH_MAX; | ||
248 | buf_used_len = word_aligned_size; | ||
249 | ptr = buf; | ||
250 | } | ||
251 | } else if (word_aligned_size) { | ||
252 | int i; | ||
253 | ptr = buf + buf_used_len; | ||
254 | buf_used_len += word_aligned_size; | ||
255 | for (i = 0; i < word_aligned_size; i++) { | ||
256 | if (!ptr[i]) | ||
257 | continue; | ||
258 | printk(KERN_ERR "WARNING: Reserved memory was tainted! " | ||
259 | "The system might go wrong.\n"); | ||
260 | ptr[i] = '\0'; | ||
261 | } | ||
262 | } | 231 | } |
263 | mutex_unlock(&lock); | 232 | printk(KERN_WARNING "ERROR: Out of memory " |
264 | return ptr; | 233 | "for tomoyo_alloc_element().\n"); |
234 | if (!tomoyo_policy_loaded) | ||
235 | panic("MAC Initialization failed.\n"); | ||
236 | return false; | ||
265 | } | 237 | } |
266 | 238 | ||
267 | /* Memory allocated for string data in bytes. */ | 239 | /** |
268 | static unsigned int tomoyo_allocated_memory_for_savename; | 240 | * tomoyo_memory_free - Free memory for elements. |
269 | /* Quota for holding string data in bytes. */ | ||
270 | static unsigned int tomoyo_quota_for_savename; | ||
271 | |||
272 | /* | ||
273 | * TOMOYO uses this hash only when appending a string into the string | ||
274 | * table. Frequency of appending strings is very low. So we don't need | ||
275 | * large (e.g. 64k) hash size. 256 will be sufficient. | ||
276 | */ | ||
277 | #define TOMOYO_HASH_BITS 8 | ||
278 | #define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS) | ||
279 | |||
280 | /* | ||
281 | * tomoyo_name_entry is a structure which is used for linking | ||
282 | * "struct tomoyo_path_info" into tomoyo_name_list . | ||
283 | * | 241 | * |
284 | * Since tomoyo_name_list manages a list of strings which are shared by | 242 | * @ptr: Pointer to allocated memory. |
285 | * multiple processes (whereas "struct tomoyo_path_info" inside | ||
286 | * "struct tomoyo_path_info_with_data" is not shared), a reference counter will | ||
287 | * be added to "struct tomoyo_name_entry" rather than "struct tomoyo_path_info" | ||
288 | * when TOMOYO starts supporting garbage collector. | ||
289 | */ | 243 | */ |
290 | struct tomoyo_name_entry { | 244 | void tomoyo_memory_free(void *ptr) |
291 | struct list_head list; | 245 | { |
292 | struct tomoyo_path_info entry; | 246 | atomic_sub(ksize(ptr), &tomoyo_policy_memory_size); |
293 | }; | 247 | kfree(ptr); |
294 | 248 | } | |
295 | /* Structure for available memory region. */ | ||
296 | struct tomoyo_free_memory_block_list { | ||
297 | struct list_head list; | ||
298 | char *ptr; /* Pointer to a free area. */ | ||
299 | int len; /* Length of the area. */ | ||
300 | }; | ||
301 | 249 | ||
302 | /* | 250 | /* |
303 | * tomoyo_name_list is used for holding string data used by TOMOYO. | 251 | * tomoyo_name_list is used for holding string data used by TOMOYO. |
@@ -305,87 +253,58 @@ struct tomoyo_free_memory_block_list { | |||
305 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of | 253 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of |
306 | * "const struct tomoyo_path_info *". | 254 | * "const struct tomoyo_path_info *". |
307 | */ | 255 | */ |
308 | static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | 256 | struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; |
257 | /* Lock for protecting tomoyo_name_list . */ | ||
258 | DEFINE_MUTEX(tomoyo_name_list_lock); | ||
309 | 259 | ||
310 | /** | 260 | /** |
311 | * tomoyo_save_name - Allocate permanent memory for string data. | 261 | * tomoyo_get_name - Allocate permanent memory for string data. |
312 | * | 262 | * |
313 | * @name: The string to store into the permernent memory. | 263 | * @name: The string to store into the permernent memory. |
314 | * | 264 | * |
315 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. | 265 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. |
316 | * | ||
317 | * The RAM is shared, so NEVER try to modify or kfree() the returned name. | ||
318 | */ | 266 | */ |
319 | const struct tomoyo_path_info *tomoyo_save_name(const char *name) | 267 | const struct tomoyo_path_info *tomoyo_get_name(const char *name) |
320 | { | 268 | { |
321 | static LIST_HEAD(fmb_list); | ||
322 | static DEFINE_MUTEX(lock); | ||
323 | struct tomoyo_name_entry *ptr; | 269 | struct tomoyo_name_entry *ptr; |
324 | unsigned int hash; | 270 | unsigned int hash; |
325 | /* fmb contains available size in bytes. | ||
326 | fmb is removed from the fmb_list when fmb->len becomes 0. */ | ||
327 | struct tomoyo_free_memory_block_list *fmb; | ||
328 | int len; | 271 | int len; |
329 | char *cp; | 272 | int allocated_len; |
330 | struct list_head *head; | 273 | struct list_head *head; |
331 | 274 | ||
332 | if (!name) | 275 | if (!name) |
333 | return NULL; | 276 | return NULL; |
334 | len = strlen(name) + 1; | 277 | len = strlen(name) + 1; |
335 | if (len > TOMOYO_MAX_PATHNAME_LEN) { | ||
336 | printk(KERN_WARNING "ERROR: Name too long " | ||
337 | "for tomoyo_save_name().\n"); | ||
338 | return NULL; | ||
339 | } | ||
340 | hash = full_name_hash((const unsigned char *) name, len - 1); | 278 | hash = full_name_hash((const unsigned char *) name, len - 1); |
341 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; | 279 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; |
342 | 280 | mutex_lock(&tomoyo_name_list_lock); | |
343 | mutex_lock(&lock); | ||
344 | list_for_each_entry(ptr, head, list) { | 281 | list_for_each_entry(ptr, head, list) { |
345 | if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name)) | 282 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) |
346 | goto out; | 283 | continue; |
347 | } | 284 | atomic_inc(&ptr->users); |
348 | list_for_each_entry(fmb, &fmb_list, list) { | 285 | goto out; |
349 | if (len <= fmb->len) | ||
350 | goto ready; | ||
351 | } | 286 | } |
352 | if (!tomoyo_quota_for_savename || | 287 | ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL); |
353 | tomoyo_allocated_memory_for_savename + PATH_MAX | 288 | allocated_len = ptr ? ksize(ptr) : 0; |
354 | <= tomoyo_quota_for_savename) | 289 | if (!ptr || (tomoyo_quota_for_policy && |
355 | cp = kzalloc(PATH_MAX, GFP_KERNEL); | 290 | atomic_read(&tomoyo_policy_memory_size) + allocated_len |
356 | else | 291 | > tomoyo_quota_for_policy)) { |
357 | cp = NULL; | 292 | kfree(ptr); |
358 | fmb = kzalloc(sizeof(*fmb), GFP_KERNEL); | ||
359 | if (!cp || !fmb) { | ||
360 | kfree(cp); | ||
361 | kfree(fmb); | ||
362 | printk(KERN_WARNING "ERROR: Out of memory " | 293 | printk(KERN_WARNING "ERROR: Out of memory " |
363 | "for tomoyo_save_name().\n"); | 294 | "for tomoyo_get_name().\n"); |
364 | if (!tomoyo_policy_loaded) | 295 | if (!tomoyo_policy_loaded) |
365 | panic("MAC Initialization failed.\n"); | 296 | panic("MAC Initialization failed.\n"); |
366 | ptr = NULL; | 297 | ptr = NULL; |
367 | goto out; | 298 | goto out; |
368 | } | 299 | } |
369 | tomoyo_allocated_memory_for_savename += PATH_MAX; | 300 | atomic_add(allocated_len, &tomoyo_policy_memory_size); |
370 | list_add(&fmb->list, &fmb_list); | 301 | ptr->entry.name = ((char *) ptr) + sizeof(*ptr); |
371 | fmb->ptr = cp; | 302 | memmove((char *) ptr->entry.name, name, len); |
372 | fmb->len = PATH_MAX; | 303 | atomic_set(&ptr->users, 1); |
373 | ready: | ||
374 | ptr = tomoyo_alloc_element(sizeof(*ptr)); | ||
375 | if (!ptr) | ||
376 | goto out; | ||
377 | ptr->entry.name = fmb->ptr; | ||
378 | memmove(fmb->ptr, name, len); | ||
379 | tomoyo_fill_path_info(&ptr->entry); | 304 | tomoyo_fill_path_info(&ptr->entry); |
380 | fmb->ptr += len; | ||
381 | fmb->len -= len; | ||
382 | list_add_tail(&ptr->list, head); | 305 | list_add_tail(&ptr->list, head); |
383 | if (fmb->len == 0) { | ||
384 | list_del(&fmb->list); | ||
385 | kfree(fmb); | ||
386 | } | ||
387 | out: | 306 | out: |
388 | mutex_unlock(&lock); | 307 | mutex_unlock(&tomoyo_name_list_lock); |
389 | return ptr ? &ptr->entry : NULL; | 308 | return ptr ? &ptr->entry : NULL; |
390 | } | 309 | } |
391 | 310 | ||
@@ -400,45 +319,14 @@ void __init tomoyo_realpath_init(void) | |||
400 | for (i = 0; i < TOMOYO_MAX_HASH; i++) | 319 | for (i = 0; i < TOMOYO_MAX_HASH; i++) |
401 | INIT_LIST_HEAD(&tomoyo_name_list[i]); | 320 | INIT_LIST_HEAD(&tomoyo_name_list[i]); |
402 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); | 321 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); |
403 | tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME); | 322 | tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME); |
404 | list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list); | 323 | /* |
405 | down_read(&tomoyo_domain_list_lock); | 324 | * tomoyo_read_lock() is not needed because this function is |
325 | * called before the first "delete" request. | ||
326 | */ | ||
327 | list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); | ||
406 | if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) | 328 | if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) |
407 | panic("Can't register tomoyo_kernel_domain"); | 329 | panic("Can't register tomoyo_kernel_domain"); |
408 | up_read(&tomoyo_domain_list_lock); | ||
409 | } | ||
410 | |||
411 | /* Memory allocated for temporary purpose. */ | ||
412 | static atomic_t tomoyo_dynamic_memory_size; | ||
413 | |||
414 | /** | ||
415 | * tomoyo_alloc - Allocate memory for temporary purpose. | ||
416 | * | ||
417 | * @size: Size in bytes. | ||
418 | * | ||
419 | * Returns pointer to allocated memory on success, NULL otherwise. | ||
420 | */ | ||
421 | void *tomoyo_alloc(const size_t size) | ||
422 | { | ||
423 | void *p = kzalloc(size, GFP_KERNEL); | ||
424 | if (p) | ||
425 | atomic_add(ksize(p), &tomoyo_dynamic_memory_size); | ||
426 | return p; | ||
427 | } | ||
428 | |||
429 | /** | ||
430 | * tomoyo_free - Release memory allocated by tomoyo_alloc(). | ||
431 | * | ||
432 | * @p: Pointer returned by tomoyo_alloc(). May be NULL. | ||
433 | * | ||
434 | * Returns nothing. | ||
435 | */ | ||
436 | void tomoyo_free(const void *p) | ||
437 | { | ||
438 | if (p) { | ||
439 | atomic_sub(ksize(p), &tomoyo_dynamic_memory_size); | ||
440 | kfree(p); | ||
441 | } | ||
442 | } | 330 | } |
443 | 331 | ||
444 | /** | 332 | /** |
@@ -451,32 +339,19 @@ void tomoyo_free(const void *p) | |||
451 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) | 339 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) |
452 | { | 340 | { |
453 | if (!head->read_eof) { | 341 | if (!head->read_eof) { |
454 | const unsigned int shared | 342 | const unsigned int policy |
455 | = tomoyo_allocated_memory_for_savename; | 343 | = atomic_read(&tomoyo_policy_memory_size); |
456 | const unsigned int private | ||
457 | = tomoyo_allocated_memory_for_elements; | ||
458 | const unsigned int dynamic | ||
459 | = atomic_read(&tomoyo_dynamic_memory_size); | ||
460 | char buffer[64]; | 344 | char buffer[64]; |
461 | 345 | ||
462 | memset(buffer, 0, sizeof(buffer)); | 346 | memset(buffer, 0, sizeof(buffer)); |
463 | if (tomoyo_quota_for_savename) | 347 | if (tomoyo_quota_for_policy) |
464 | snprintf(buffer, sizeof(buffer) - 1, | ||
465 | " (Quota: %10u)", | ||
466 | tomoyo_quota_for_savename); | ||
467 | else | ||
468 | buffer[0] = '\0'; | ||
469 | tomoyo_io_printf(head, "Shared: %10u%s\n", shared, buffer); | ||
470 | if (tomoyo_quota_for_elements) | ||
471 | snprintf(buffer, sizeof(buffer) - 1, | 348 | snprintf(buffer, sizeof(buffer) - 1, |
472 | " (Quota: %10u)", | 349 | " (Quota: %10u)", |
473 | tomoyo_quota_for_elements); | 350 | tomoyo_quota_for_policy); |
474 | else | 351 | else |
475 | buffer[0] = '\0'; | 352 | buffer[0] = '\0'; |
476 | tomoyo_io_printf(head, "Private: %10u%s\n", private, buffer); | 353 | tomoyo_io_printf(head, "Policy: %10u%s\n", policy, buffer); |
477 | tomoyo_io_printf(head, "Dynamic: %10u\n", dynamic); | 354 | tomoyo_io_printf(head, "Total: %10u\n", policy); |
478 | tomoyo_io_printf(head, "Total: %10u\n", | ||
479 | shared + private + dynamic); | ||
480 | head->read_eof = true; | 355 | head->read_eof = true; |
481 | } | 356 | } |
482 | return 0; | 357 | return 0; |
@@ -494,9 +369,7 @@ int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head) | |||
494 | char *data = head->write_buf; | 369 | char *data = head->write_buf; |
495 | unsigned int size; | 370 | unsigned int size; |
496 | 371 | ||
497 | if (sscanf(data, "Shared: %u", &size) == 1) | 372 | if (sscanf(data, "Policy: %u", &size) == 1) |
498 | tomoyo_quota_for_savename = size; | 373 | tomoyo_quota_for_policy = size; |
499 | else if (sscanf(data, "Private: %u", &size) == 1) | ||
500 | tomoyo_quota_for_elements = size; | ||
501 | return 0; | 374 | return 0; |
502 | } | 375 | } |
diff --git a/security/tomoyo/realpath.h b/security/tomoyo/realpath.h deleted file mode 100644 index 78217a37960b..000000000000 --- a/security/tomoyo/realpath.h +++ /dev/null | |||
@@ -1,66 +0,0 @@ | |||
1 | /* | ||
2 | * security/tomoyo/realpath.h | ||
3 | * | ||
4 | * Get the canonicalized absolute pathnames. The basis for TOMOYO. | ||
5 | * | ||
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | ||
7 | * | ||
8 | * Version: 2.2.0 2009/04/01 | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #ifndef _SECURITY_TOMOYO_REALPATH_H | ||
13 | #define _SECURITY_TOMOYO_REALPATH_H | ||
14 | |||
15 | struct path; | ||
16 | struct tomoyo_path_info; | ||
17 | struct tomoyo_io_buffer; | ||
18 | |||
19 | /* Convert binary string to ascii string. */ | ||
20 | int tomoyo_encode(char *buffer, int buflen, const char *str); | ||
21 | |||
22 | /* Returns realpath(3) of the given pathname but ignores chroot'ed root. */ | ||
23 | int tomoyo_realpath_from_path2(struct path *path, char *newname, | ||
24 | int newname_len); | ||
25 | |||
26 | /* | ||
27 | * Returns realpath(3) of the given pathname but ignores chroot'ed root. | ||
28 | * These functions use tomoyo_alloc(), so the caller must call tomoyo_free() | ||
29 | * if these functions didn't return NULL. | ||
30 | */ | ||
31 | char *tomoyo_realpath(const char *pathname); | ||
32 | /* | ||
33 | * Same with tomoyo_realpath() except that it doesn't follow the final symlink. | ||
34 | */ | ||
35 | char *tomoyo_realpath_nofollow(const char *pathname); | ||
36 | /* Same with tomoyo_realpath() except that the pathname is already solved. */ | ||
37 | char *tomoyo_realpath_from_path(struct path *path); | ||
38 | |||
39 | /* | ||
40 | * Allocate memory for ACL entry. | ||
41 | * The RAM is chunked, so NEVER try to kfree() the returned pointer. | ||
42 | */ | ||
43 | void *tomoyo_alloc_element(const unsigned int size); | ||
44 | |||
45 | /* | ||
46 | * Keep the given name on the RAM. | ||
47 | * The RAM is shared, so NEVER try to modify or kfree() the returned name. | ||
48 | */ | ||
49 | const struct tomoyo_path_info *tomoyo_save_name(const char *name); | ||
50 | |||
51 | /* Allocate memory for temporary use (e.g. permission checks). */ | ||
52 | void *tomoyo_alloc(const size_t size); | ||
53 | |||
54 | /* Free memory allocated by tomoyo_alloc(). */ | ||
55 | void tomoyo_free(const void *p); | ||
56 | |||
57 | /* Check for memory usage. */ | ||
58 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head); | ||
59 | |||
60 | /* Set memory quota. */ | ||
61 | int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head); | ||
62 | |||
63 | /* Initialize realpath related code. */ | ||
64 | void __init tomoyo_realpath_init(void); | ||
65 | |||
66 | #endif /* !defined(_SECURITY_TOMOYO_REALPATH_H) */ | ||
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 2aceebf5f354..dedd97d0c163 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -11,8 +11,6 @@ | |||
11 | 11 | ||
12 | #include <linux/security.h> | 12 | #include <linux/security.h> |
13 | #include "common.h" | 13 | #include "common.h" |
14 | #include "tomoyo.h" | ||
15 | #include "realpath.h" | ||
16 | 14 | ||
17 | static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) | 15 | static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) |
18 | { | 16 | { |
@@ -23,21 +21,23 @@ static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) | |||
23 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | 21 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, |
24 | gfp_t gfp) | 22 | gfp_t gfp) |
25 | { | 23 | { |
26 | /* | 24 | struct tomoyo_domain_info *domain = old->security; |
27 | * Since "struct tomoyo_domain_info *" is a sharable pointer, | 25 | new->security = domain; |
28 | * we don't need to duplicate. | 26 | if (domain) |
29 | */ | 27 | atomic_inc(&domain->users); |
30 | new->security = old->security; | ||
31 | return 0; | 28 | return 0; |
32 | } | 29 | } |
33 | 30 | ||
34 | static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) | 31 | static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) |
35 | { | 32 | { |
36 | /* | 33 | tomoyo_cred_prepare(new, old, 0); |
37 | * Since "struct tomoyo_domain_info *" is a sharable pointer, | 34 | } |
38 | * we don't need to duplicate. | 35 | |
39 | */ | 36 | static void tomoyo_cred_free(struct cred *cred) |
40 | new->security = old->security; | 37 | { |
38 | struct tomoyo_domain_info *domain = cred->security; | ||
39 | if (domain) | ||
40 | atomic_dec(&domain->users); | ||
41 | } | 41 | } |
42 | 42 | ||
43 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | 43 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) |
@@ -61,6 +61,14 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | |||
61 | if (!tomoyo_policy_loaded) | 61 | if (!tomoyo_policy_loaded) |
62 | tomoyo_load_policy(bprm->filename); | 62 | tomoyo_load_policy(bprm->filename); |
63 | /* | 63 | /* |
64 | * Release reference to "struct tomoyo_domain_info" stored inside | ||
65 | * "bprm->cred->security". New reference to "struct tomoyo_domain_info" | ||
66 | * stored inside "bprm->cred->security" will be acquired later inside | ||
67 | * tomoyo_find_next_domain(). | ||
68 | */ | ||
69 | atomic_dec(&((struct tomoyo_domain_info *) | ||
70 | bprm->cred->security)->users); | ||
71 | /* | ||
64 | * Tell tomoyo_bprm_check_security() is called for the first time of an | 72 | * Tell tomoyo_bprm_check_security() is called for the first time of an |
65 | * execve operation. | 73 | * execve operation. |
66 | */ | 74 | */ |
@@ -76,8 +84,12 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) | |||
76 | * Execute permission is checked against pathname passed to do_execve() | 84 | * Execute permission is checked against pathname passed to do_execve() |
77 | * using current domain. | 85 | * using current domain. |
78 | */ | 86 | */ |
79 | if (!domain) | 87 | if (!domain) { |
80 | return tomoyo_find_next_domain(bprm); | 88 | const int idx = tomoyo_read_lock(); |
89 | const int err = tomoyo_find_next_domain(bprm); | ||
90 | tomoyo_read_unlock(idx); | ||
91 | return err; | ||
92 | } | ||
81 | /* | 93 | /* |
82 | * Read permission is checked against interpreters using next domain. | 94 | * Read permission is checked against interpreters using next domain. |
83 | */ | 95 | */ |
@@ -87,67 +99,56 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) | |||
87 | static int tomoyo_path_truncate(struct path *path, loff_t length, | 99 | static int tomoyo_path_truncate(struct path *path, loff_t length, |
88 | unsigned int time_attrs) | 100 | unsigned int time_attrs) |
89 | { | 101 | { |
90 | return tomoyo_check_1path_perm(tomoyo_domain(), | 102 | return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path); |
91 | TOMOYO_TYPE_TRUNCATE_ACL, | ||
92 | path); | ||
93 | } | 103 | } |
94 | 104 | ||
95 | static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) | 105 | static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) |
96 | { | 106 | { |
97 | struct path path = { parent->mnt, dentry }; | 107 | struct path path = { parent->mnt, dentry }; |
98 | return tomoyo_check_1path_perm(tomoyo_domain(), | 108 | return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path); |
99 | TOMOYO_TYPE_UNLINK_ACL, | ||
100 | &path); | ||
101 | } | 109 | } |
102 | 110 | ||
103 | static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, | 111 | static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, |
104 | int mode) | 112 | int mode) |
105 | { | 113 | { |
106 | struct path path = { parent->mnt, dentry }; | 114 | struct path path = { parent->mnt, dentry }; |
107 | return tomoyo_check_1path_perm(tomoyo_domain(), | 115 | return tomoyo_path_perm(TOMOYO_TYPE_MKDIR, &path); |
108 | TOMOYO_TYPE_MKDIR_ACL, | ||
109 | &path); | ||
110 | } | 116 | } |
111 | 117 | ||
112 | static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) | 118 | static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) |
113 | { | 119 | { |
114 | struct path path = { parent->mnt, dentry }; | 120 | struct path path = { parent->mnt, dentry }; |
115 | return tomoyo_check_1path_perm(tomoyo_domain(), | 121 | return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path); |
116 | TOMOYO_TYPE_RMDIR_ACL, | ||
117 | &path); | ||
118 | } | 122 | } |
119 | 123 | ||
120 | static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, | 124 | static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, |
121 | const char *old_name) | 125 | const char *old_name) |
122 | { | 126 | { |
123 | struct path path = { parent->mnt, dentry }; | 127 | struct path path = { parent->mnt, dentry }; |
124 | return tomoyo_check_1path_perm(tomoyo_domain(), | 128 | return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path); |
125 | TOMOYO_TYPE_SYMLINK_ACL, | ||
126 | &path); | ||
127 | } | 129 | } |
128 | 130 | ||
129 | static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, | 131 | static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, |
130 | int mode, unsigned int dev) | 132 | int mode, unsigned int dev) |
131 | { | 133 | { |
132 | struct path path = { parent->mnt, dentry }; | 134 | struct path path = { parent->mnt, dentry }; |
133 | int type = TOMOYO_TYPE_CREATE_ACL; | 135 | int type = TOMOYO_TYPE_CREATE; |
134 | 136 | ||
135 | switch (mode & S_IFMT) { | 137 | switch (mode & S_IFMT) { |
136 | case S_IFCHR: | 138 | case S_IFCHR: |
137 | type = TOMOYO_TYPE_MKCHAR_ACL; | 139 | type = TOMOYO_TYPE_MKCHAR; |
138 | break; | 140 | break; |
139 | case S_IFBLK: | 141 | case S_IFBLK: |
140 | type = TOMOYO_TYPE_MKBLOCK_ACL; | 142 | type = TOMOYO_TYPE_MKBLOCK; |
141 | break; | 143 | break; |
142 | case S_IFIFO: | 144 | case S_IFIFO: |
143 | type = TOMOYO_TYPE_MKFIFO_ACL; | 145 | type = TOMOYO_TYPE_MKFIFO; |
144 | break; | 146 | break; |
145 | case S_IFSOCK: | 147 | case S_IFSOCK: |
146 | type = TOMOYO_TYPE_MKSOCK_ACL; | 148 | type = TOMOYO_TYPE_MKSOCK; |
147 | break; | 149 | break; |
148 | } | 150 | } |
149 | return tomoyo_check_1path_perm(tomoyo_domain(), | 151 | return tomoyo_path_perm(type, &path); |
150 | type, &path); | ||
151 | } | 152 | } |
152 | 153 | ||
153 | static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, | 154 | static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, |
@@ -155,9 +156,7 @@ static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, | |||
155 | { | 156 | { |
156 | struct path path1 = { new_dir->mnt, old_dentry }; | 157 | struct path path1 = { new_dir->mnt, old_dentry }; |
157 | struct path path2 = { new_dir->mnt, new_dentry }; | 158 | struct path path2 = { new_dir->mnt, new_dentry }; |
158 | return tomoyo_check_2path_perm(tomoyo_domain(), | 159 | return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); |
159 | TOMOYO_TYPE_LINK_ACL, | ||
160 | &path1, &path2); | ||
161 | } | 160 | } |
162 | 161 | ||
163 | static int tomoyo_path_rename(struct path *old_parent, | 162 | static int tomoyo_path_rename(struct path *old_parent, |
@@ -167,16 +166,14 @@ static int tomoyo_path_rename(struct path *old_parent, | |||
167 | { | 166 | { |
168 | struct path path1 = { old_parent->mnt, old_dentry }; | 167 | struct path path1 = { old_parent->mnt, old_dentry }; |
169 | struct path path2 = { new_parent->mnt, new_dentry }; | 168 | struct path path2 = { new_parent->mnt, new_dentry }; |
170 | return tomoyo_check_2path_perm(tomoyo_domain(), | 169 | return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); |
171 | TOMOYO_TYPE_RENAME_ACL, | ||
172 | &path1, &path2); | ||
173 | } | 170 | } |
174 | 171 | ||
175 | static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, | 172 | static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, |
176 | unsigned long arg) | 173 | unsigned long arg) |
177 | { | 174 | { |
178 | if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)) | 175 | if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)) |
179 | return tomoyo_check_rewrite_permission(tomoyo_domain(), file); | 176 | return tomoyo_check_rewrite_permission(file); |
180 | return 0; | 177 | return 0; |
181 | } | 178 | } |
182 | 179 | ||
@@ -189,6 +186,51 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred) | |||
189 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); | 186 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); |
190 | } | 187 | } |
191 | 188 | ||
189 | static int tomoyo_file_ioctl(struct file *file, unsigned int cmd, | ||
190 | unsigned long arg) | ||
191 | { | ||
192 | return tomoyo_path_perm(TOMOYO_TYPE_IOCTL, &file->f_path); | ||
193 | } | ||
194 | |||
195 | static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt, | ||
196 | mode_t mode) | ||
197 | { | ||
198 | struct path path = { mnt, dentry }; | ||
199 | return tomoyo_path_perm(TOMOYO_TYPE_CHMOD, &path); | ||
200 | } | ||
201 | |||
202 | static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid) | ||
203 | { | ||
204 | int error = 0; | ||
205 | if (uid != (uid_t) -1) | ||
206 | error = tomoyo_path_perm(TOMOYO_TYPE_CHOWN, path); | ||
207 | if (!error && gid != (gid_t) -1) | ||
208 | error = tomoyo_path_perm(TOMOYO_TYPE_CHGRP, path); | ||
209 | return error; | ||
210 | } | ||
211 | |||
212 | static int tomoyo_path_chroot(struct path *path) | ||
213 | { | ||
214 | return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path); | ||
215 | } | ||
216 | |||
217 | static int tomoyo_sb_mount(char *dev_name, struct path *path, | ||
218 | char *type, unsigned long flags, void *data) | ||
219 | { | ||
220 | return tomoyo_path_perm(TOMOYO_TYPE_MOUNT, path); | ||
221 | } | ||
222 | |||
223 | static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) | ||
224 | { | ||
225 | struct path path = { mnt, mnt->mnt_root }; | ||
226 | return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path); | ||
227 | } | ||
228 | |||
229 | static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path) | ||
230 | { | ||
231 | return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path); | ||
232 | } | ||
233 | |||
192 | /* | 234 | /* |
193 | * tomoyo_security_ops is a "struct security_operations" which is used for | 235 | * tomoyo_security_ops is a "struct security_operations" which is used for |
194 | * registering TOMOYO. | 236 | * registering TOMOYO. |
@@ -198,6 +240,7 @@ static struct security_operations tomoyo_security_ops = { | |||
198 | .cred_alloc_blank = tomoyo_cred_alloc_blank, | 240 | .cred_alloc_blank = tomoyo_cred_alloc_blank, |
199 | .cred_prepare = tomoyo_cred_prepare, | 241 | .cred_prepare = tomoyo_cred_prepare, |
200 | .cred_transfer = tomoyo_cred_transfer, | 242 | .cred_transfer = tomoyo_cred_transfer, |
243 | .cred_free = tomoyo_cred_free, | ||
201 | .bprm_set_creds = tomoyo_bprm_set_creds, | 244 | .bprm_set_creds = tomoyo_bprm_set_creds, |
202 | .bprm_check_security = tomoyo_bprm_check_security, | 245 | .bprm_check_security = tomoyo_bprm_check_security, |
203 | .file_fcntl = tomoyo_file_fcntl, | 246 | .file_fcntl = tomoyo_file_fcntl, |
@@ -210,8 +253,18 @@ static struct security_operations tomoyo_security_ops = { | |||
210 | .path_mknod = tomoyo_path_mknod, | 253 | .path_mknod = tomoyo_path_mknod, |
211 | .path_link = tomoyo_path_link, | 254 | .path_link = tomoyo_path_link, |
212 | .path_rename = tomoyo_path_rename, | 255 | .path_rename = tomoyo_path_rename, |
256 | .file_ioctl = tomoyo_file_ioctl, | ||
257 | .path_chmod = tomoyo_path_chmod, | ||
258 | .path_chown = tomoyo_path_chown, | ||
259 | .path_chroot = tomoyo_path_chroot, | ||
260 | .sb_mount = tomoyo_sb_mount, | ||
261 | .sb_umount = tomoyo_sb_umount, | ||
262 | .sb_pivotroot = tomoyo_sb_pivotroot, | ||
213 | }; | 263 | }; |
214 | 264 | ||
265 | /* Lock for GC. */ | ||
266 | struct srcu_struct tomoyo_ss; | ||
267 | |||
215 | static int __init tomoyo_init(void) | 268 | static int __init tomoyo_init(void) |
216 | { | 269 | { |
217 | struct cred *cred = (struct cred *) current_cred(); | 270 | struct cred *cred = (struct cred *) current_cred(); |
@@ -219,7 +272,8 @@ static int __init tomoyo_init(void) | |||
219 | if (!security_module_enable(&tomoyo_security_ops)) | 272 | if (!security_module_enable(&tomoyo_security_ops)) |
220 | return 0; | 273 | return 0; |
221 | /* register ourselves with the security framework */ | 274 | /* register ourselves with the security framework */ |
222 | if (register_security(&tomoyo_security_ops)) | 275 | if (register_security(&tomoyo_security_ops) || |
276 | init_srcu_struct(&tomoyo_ss)) | ||
223 | panic("Failure registering TOMOYO Linux"); | 277 | panic("Failure registering TOMOYO Linux"); |
224 | printk(KERN_INFO "TOMOYO Linux initialized\n"); | 278 | printk(KERN_INFO "TOMOYO Linux initialized\n"); |
225 | cred->security = &tomoyo_kernel_domain; | 279 | cred->security = &tomoyo_kernel_domain; |
diff --git a/security/tomoyo/tomoyo.h b/security/tomoyo/tomoyo.h deleted file mode 100644 index ed758325b1ae..000000000000 --- a/security/tomoyo/tomoyo.h +++ /dev/null | |||
@@ -1,94 +0,0 @@ | |||
1 | /* | ||
2 | * security/tomoyo/tomoyo.h | ||
3 | * | ||
4 | * Implementation of the Domain-Based Mandatory Access Control. | ||
5 | * | ||
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | ||
7 | * | ||
8 | * Version: 2.2.0 2009/04/01 | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #ifndef _SECURITY_TOMOYO_TOMOYO_H | ||
13 | #define _SECURITY_TOMOYO_TOMOYO_H | ||
14 | |||
15 | struct tomoyo_path_info; | ||
16 | struct path; | ||
17 | struct inode; | ||
18 | struct linux_binprm; | ||
19 | struct pt_regs; | ||
20 | |||
21 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, | ||
22 | const struct tomoyo_path_info *filename); | ||
23 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | ||
24 | struct path *path, const int flag); | ||
25 | int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, | ||
26 | const u8 operation, struct path *path); | ||
27 | int tomoyo_check_2path_perm(struct tomoyo_domain_info *domain, | ||
28 | const u8 operation, struct path *path1, | ||
29 | struct path *path2); | ||
30 | int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, | ||
31 | struct file *filp); | ||
32 | int tomoyo_find_next_domain(struct linux_binprm *bprm); | ||
33 | |||
34 | /* Index numbers for Access Controls. */ | ||
35 | |||
36 | #define TOMOYO_TYPE_SINGLE_PATH_ACL 0 | ||
37 | #define TOMOYO_TYPE_DOUBLE_PATH_ACL 1 | ||
38 | |||
39 | /* Index numbers for File Controls. */ | ||
40 | |||
41 | /* | ||
42 | * TYPE_READ_WRITE_ACL is special. TYPE_READ_WRITE_ACL is automatically set | ||
43 | * if both TYPE_READ_ACL and TYPE_WRITE_ACL are set. Both TYPE_READ_ACL and | ||
44 | * TYPE_WRITE_ACL are automatically set if TYPE_READ_WRITE_ACL is set. | ||
45 | * TYPE_READ_WRITE_ACL is automatically cleared if either TYPE_READ_ACL or | ||
46 | * TYPE_WRITE_ACL is cleared. Both TYPE_READ_ACL and TYPE_WRITE_ACL are | ||
47 | * automatically cleared if TYPE_READ_WRITE_ACL is cleared. | ||
48 | */ | ||
49 | |||
50 | #define TOMOYO_TYPE_READ_WRITE_ACL 0 | ||
51 | #define TOMOYO_TYPE_EXECUTE_ACL 1 | ||
52 | #define TOMOYO_TYPE_READ_ACL 2 | ||
53 | #define TOMOYO_TYPE_WRITE_ACL 3 | ||
54 | #define TOMOYO_TYPE_CREATE_ACL 4 | ||
55 | #define TOMOYO_TYPE_UNLINK_ACL 5 | ||
56 | #define TOMOYO_TYPE_MKDIR_ACL 6 | ||
57 | #define TOMOYO_TYPE_RMDIR_ACL 7 | ||
58 | #define TOMOYO_TYPE_MKFIFO_ACL 8 | ||
59 | #define TOMOYO_TYPE_MKSOCK_ACL 9 | ||
60 | #define TOMOYO_TYPE_MKBLOCK_ACL 10 | ||
61 | #define TOMOYO_TYPE_MKCHAR_ACL 11 | ||
62 | #define TOMOYO_TYPE_TRUNCATE_ACL 12 | ||
63 | #define TOMOYO_TYPE_SYMLINK_ACL 13 | ||
64 | #define TOMOYO_TYPE_REWRITE_ACL 14 | ||
65 | #define TOMOYO_MAX_SINGLE_PATH_OPERATION 15 | ||
66 | |||
67 | #define TOMOYO_TYPE_LINK_ACL 0 | ||
68 | #define TOMOYO_TYPE_RENAME_ACL 1 | ||
69 | #define TOMOYO_MAX_DOUBLE_PATH_OPERATION 2 | ||
70 | |||
71 | #define TOMOYO_DOMAINPOLICY 0 | ||
72 | #define TOMOYO_EXCEPTIONPOLICY 1 | ||
73 | #define TOMOYO_DOMAIN_STATUS 2 | ||
74 | #define TOMOYO_PROCESS_STATUS 3 | ||
75 | #define TOMOYO_MEMINFO 4 | ||
76 | #define TOMOYO_SELFDOMAIN 5 | ||
77 | #define TOMOYO_VERSION 6 | ||
78 | #define TOMOYO_PROFILE 7 | ||
79 | #define TOMOYO_MANAGER 8 | ||
80 | |||
81 | extern struct tomoyo_domain_info tomoyo_kernel_domain; | ||
82 | |||
83 | static inline struct tomoyo_domain_info *tomoyo_domain(void) | ||
84 | { | ||
85 | return current_cred()->security; | ||
86 | } | ||
87 | |||
88 | static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct | ||
89 | *task) | ||
90 | { | ||
91 | return task_cred_xxx(task, security); | ||
92 | } | ||
93 | |||
94 | #endif /* !defined(_SECURITY_TOMOYO_TOMOYO_H) */ | ||