aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>2011-09-10 02:25:58 -0400
committerJames Morris <jmorris@namei.org>2011-09-13 18:27:06 -0400
commit731d37aa70c7b9de3be6bf2c8287366223bf5ce5 (patch)
tree8ac6028511485862572695eb91e2d461e0636182
parent1f067a682a9bd252107ac6f6946b7332fde42344 (diff)
TOMOYO: Allow domain transition without execve().
To be able to split permissions for Apache's CGI programs which are executed without execve(), add special domain transition which is performed by writing a TOMOYO's domainname to /sys/kernel/security/tomoyo/self_domain interface. This is an API for TOMOYO-aware userland applications. However, since I expect TOMOYO and other LSM modules to run in parallel, this patch does not use /proc/self/attr/ interface in order to avoid conflicts with other LSM modules when it became possible to run multiple LSM modules in parallel. Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r--security/tomoyo/common.c75
-rw-r--r--security/tomoyo/common.h16
-rw-r--r--security/tomoyo/securityfs_if.c122
-rw-r--r--security/tomoyo/util.c25
4 files changed, 210 insertions, 28 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index 2704c384bf1e..1fd0fc1059ba 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -1011,6 +1011,48 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
1011} 1011}
1012 1012
1013/** 1013/**
1014 * tomoyo_same_task_acl - Check for duplicated "struct tomoyo_task_acl" entry.
1015 *
1016 * @a: Pointer to "struct tomoyo_acl_info".
1017 * @b: Pointer to "struct tomoyo_acl_info".
1018 *
1019 * Returns true if @a == @b, false otherwise.
1020 */
1021static bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a,
1022 const struct tomoyo_acl_info *b)
1023{
1024 const struct tomoyo_task_acl *p1 = container_of(a, typeof(*p1), head);
1025 const struct tomoyo_task_acl *p2 = container_of(b, typeof(*p2), head);
1026 return p1->domainname == p2->domainname;
1027}
1028
1029/**
1030 * tomoyo_write_task - Update task related list.
1031 *
1032 * @param: Pointer to "struct tomoyo_acl_param".
1033 *
1034 * Returns 0 on success, negative value otherwise.
1035 *
1036 * Caller holds tomoyo_read_lock().
1037 */
1038static int tomoyo_write_task(struct tomoyo_acl_param *param)
1039{
1040 int error = -EINVAL;
1041 if (tomoyo_str_starts(&param->data, "manual_domain_transition ")) {
1042 struct tomoyo_task_acl e = {
1043 .head.type = TOMOYO_TYPE_MANUAL_TASK_ACL,
1044 .domainname = tomoyo_get_domainname(param),
1045 };
1046 if (e.domainname)
1047 error = tomoyo_update_domain(&e.head, sizeof(e), param,
1048 tomoyo_same_task_acl,
1049 NULL);
1050 tomoyo_put_name(e.domainname);
1051 }
1052 return error;
1053}
1054
1055/**
1014 * tomoyo_delete_domain - Delete a domain. 1056 * tomoyo_delete_domain - Delete a domain.
1015 * 1057 *
1016 * @domainname: The name of domain. 1058 * @domainname: The name of domain.
@@ -1068,11 +1110,12 @@ static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns,
1068 static const struct { 1110 static const struct {
1069 const char *keyword; 1111 const char *keyword;
1070 int (*write) (struct tomoyo_acl_param *); 1112 int (*write) (struct tomoyo_acl_param *);
1071 } tomoyo_callback[4] = { 1113 } tomoyo_callback[5] = {
1072 { "file ", tomoyo_write_file }, 1114 { "file ", tomoyo_write_file },
1073 { "network inet ", tomoyo_write_inet_network }, 1115 { "network inet ", tomoyo_write_inet_network },
1074 { "network unix ", tomoyo_write_unix_network }, 1116 { "network unix ", tomoyo_write_unix_network },
1075 { "misc ", tomoyo_write_misc }, 1117 { "misc ", tomoyo_write_misc },
1118 { "task ", tomoyo_write_task },
1076 }; 1119 };
1077 u8 i; 1120 u8 i;
1078 1121
@@ -1343,6 +1386,12 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
1343 if (first) 1386 if (first)
1344 return true; 1387 return true;
1345 tomoyo_print_name_union(head, &ptr->name); 1388 tomoyo_print_name_union(head, &ptr->name);
1389 } else if (acl_type == TOMOYO_TYPE_MANUAL_TASK_ACL) {
1390 struct tomoyo_task_acl *ptr =
1391 container_of(acl, typeof(*ptr), head);
1392 tomoyo_set_group(head, "task ");
1393 tomoyo_set_string(head, "manual_domain_transition ");
1394 tomoyo_set_string(head, ptr->domainname->name);
1346 } else if (head->r.print_transition_related_only) { 1395 } else if (head->r.print_transition_related_only) {
1347 return true; 1396 return true;
1348 } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { 1397 } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
@@ -2178,26 +2227,6 @@ static void tomoyo_read_version(struct tomoyo_io_buffer *head)
2178 } 2227 }
2179} 2228}
2180 2229
2181/**
2182 * tomoyo_read_self_domain - Get the current process's domainname.
2183 *
2184 * @head: Pointer to "struct tomoyo_io_buffer".
2185 *
2186 * Returns the current process's domainname.
2187 */
2188static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
2189{
2190 if (!head->r.eof) {
2191 /*
2192 * tomoyo_domain()->domainname != NULL
2193 * because every process belongs to a domain and
2194 * the domain's name cannot be NULL.
2195 */
2196 tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name);
2197 head->r.eof = true;
2198 }
2199}
2200
2201/* String table for /sys/kernel/security/tomoyo/stat interface. */ 2230/* String table for /sys/kernel/security/tomoyo/stat interface. */
2202static const char * const tomoyo_policy_headers[TOMOYO_MAX_POLICY_STAT] = { 2231static const char * const tomoyo_policy_headers[TOMOYO_MAX_POLICY_STAT] = {
2203 [TOMOYO_STAT_POLICY_UPDATES] = "update:", 2232 [TOMOYO_STAT_POLICY_UPDATES] = "update:",
@@ -2328,10 +2357,6 @@ int tomoyo_open_control(const u8 type, struct file *file)
2328 head->poll = tomoyo_poll_log; 2357 head->poll = tomoyo_poll_log;
2329 head->read = tomoyo_read_log; 2358 head->read = tomoyo_read_log;
2330 break; 2359 break;
2331 case TOMOYO_SELFDOMAIN:
2332 /* /sys/kernel/security/tomoyo/self_domain */
2333 head->read = tomoyo_read_self_domain;
2334 break;
2335 case TOMOYO_PROCESS_STATUS: 2360 case TOMOYO_PROCESS_STATUS:
2336 /* /sys/kernel/security/tomoyo/.process_status */ 2361 /* /sys/kernel/security/tomoyo/.process_status */
2337 head->write = tomoyo_write_pid; 2362 head->write = tomoyo_write_pid;
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 435b3d869fc5..af82683df7ff 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -227,6 +227,7 @@ enum tomoyo_acl_entry_type_index {
227 TOMOYO_TYPE_INET_ACL, 227 TOMOYO_TYPE_INET_ACL,
228 TOMOYO_TYPE_UNIX_ACL, 228 TOMOYO_TYPE_UNIX_ACL,
229 TOMOYO_TYPE_ENV_ACL, 229 TOMOYO_TYPE_ENV_ACL,
230 TOMOYO_TYPE_MANUAL_TASK_ACL,
230}; 231};
231 232
232/* Index numbers for access controls with one pathname. */ 233/* Index numbers for access controls with one pathname. */
@@ -295,7 +296,6 @@ enum tomoyo_securityfs_interface_index {
295 TOMOYO_EXCEPTIONPOLICY, 296 TOMOYO_EXCEPTIONPOLICY,
296 TOMOYO_PROCESS_STATUS, 297 TOMOYO_PROCESS_STATUS,
297 TOMOYO_STAT, 298 TOMOYO_STAT,
298 TOMOYO_SELFDOMAIN,
299 TOMOYO_AUDIT, 299 TOMOYO_AUDIT,
300 TOMOYO_VERSION, 300 TOMOYO_VERSION,
301 TOMOYO_PROFILE, 301 TOMOYO_PROFILE,
@@ -480,6 +480,9 @@ struct tomoyo_request_info {
480 unsigned long flags; 480 unsigned long flags;
481 int need_dev; 481 int need_dev;
482 } mount; 482 } mount;
483 struct {
484 const struct tomoyo_path_info *domainname;
485 } task;
483 } param; 486 } param;
484 struct tomoyo_acl_info *matched_acl; 487 struct tomoyo_acl_info *matched_acl;
485 u8 param_type; 488 u8 param_type;
@@ -680,6 +683,15 @@ struct tomoyo_domain_info {
680}; 683};
681 684
682/* 685/*
686 * Structure for "task manual_domain_transition" directive.
687 */
688struct tomoyo_task_acl {
689 struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MANUAL_TASK_ACL */
690 /* Pointer to domainname. */
691 const struct tomoyo_path_info *domainname;
692};
693
694/*
683 * Structure for "file execute", "file read", "file write", "file append", 695 * Structure for "file execute", "file read", "file write", "file append",
684 * "file unlink", "file getattr", "file rmdir", "file truncate", 696 * "file unlink", "file getattr", "file rmdir", "file truncate",
685 * "file symlink", "file chroot" and "file unmount" directive. 697 * "file symlink", "file chroot" and "file unmount" directive.
@@ -935,6 +947,8 @@ const char *tomoyo_get_exe(void);
935const char *tomoyo_yesno(const unsigned int value); 947const char *tomoyo_yesno(const unsigned int value);
936const struct tomoyo_path_info *tomoyo_compare_name_union 948const struct tomoyo_path_info *tomoyo_compare_name_union
937(const struct tomoyo_path_info *name, const struct tomoyo_name_union *ptr); 949(const struct tomoyo_path_info *name, const struct tomoyo_name_union *ptr);
950const struct tomoyo_path_info *tomoyo_get_domainname
951(struct tomoyo_acl_param *param);
938const struct tomoyo_path_info *tomoyo_get_name(const char *name); 952const struct tomoyo_path_info *tomoyo_get_name(const char *name);
939const struct tomoyo_path_info *tomoyo_path_matches_group 953const struct tomoyo_path_info *tomoyo_path_matches_group
940(const struct tomoyo_path_info *pathname, const struct tomoyo_group *group); 954(const struct tomoyo_path_info *pathname, const struct tomoyo_group *group);
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
index a49c3bfd4dd5..d08296a4882b 100644
--- a/security/tomoyo/securityfs_if.c
+++ b/security/tomoyo/securityfs_if.c
@@ -8,6 +8,124 @@
8#include "common.h" 8#include "common.h"
9 9
10/** 10/**
11 * tomoyo_check_task_acl - Check permission for task operation.
12 *
13 * @r: Pointer to "struct tomoyo_request_info".
14 * @ptr: Pointer to "struct tomoyo_acl_info".
15 *
16 * Returns true if granted, false otherwise.
17 */
18static bool tomoyo_check_task_acl(struct tomoyo_request_info *r,
19 const struct tomoyo_acl_info *ptr)
20{
21 const struct tomoyo_task_acl *acl = container_of(ptr, typeof(*acl),
22 head);
23 return !tomoyo_pathcmp(r->param.task.domainname, acl->domainname);
24}
25
26/**
27 * tomoyo_write_self - write() for /sys/kernel/security/tomoyo/self_domain interface.
28 *
29 * @file: Pointer to "struct file".
30 * @buf: Domainname to transit to.
31 * @count: Size of @buf.
32 * @ppos: Unused.
33 *
34 * Returns @count on success, negative value otherwise.
35 *
36 * If domain transition was permitted but the domain transition failed, this
37 * function returns error rather than terminating current thread with SIGKILL.
38 */
39static ssize_t tomoyo_write_self(struct file *file, const char __user *buf,
40 size_t count, loff_t *ppos)
41{
42 char *data;
43 int error;
44 if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10)
45 return -ENOMEM;
46 data = kzalloc(count + 1, GFP_NOFS);
47 if (!data)
48 return -ENOMEM;
49 if (copy_from_user(data, buf, count)) {
50 error = -EFAULT;
51 goto out;
52 }
53 tomoyo_normalize_line(data);
54 if (tomoyo_correct_domain(data)) {
55 const int idx = tomoyo_read_lock();
56 struct tomoyo_path_info name;
57 struct tomoyo_request_info r;
58 name.name = data;
59 tomoyo_fill_path_info(&name);
60 /* Check "task manual_domain_transition" permission. */
61 tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
62 r.param_type = TOMOYO_TYPE_MANUAL_TASK_ACL;
63 r.param.task.domainname = &name;
64 tomoyo_check_acl(&r, tomoyo_check_task_acl);
65 if (!r.granted)
66 error = -EPERM;
67 else {
68 struct tomoyo_domain_info *new_domain =
69 tomoyo_assign_domain(data, true);
70 if (!new_domain) {
71 error = -ENOENT;
72 } else {
73 struct cred *cred = prepare_creds();
74 if (!cred) {
75 error = -ENOMEM;
76 } else {
77 struct tomoyo_domain_info *old_domain =
78 cred->security;
79 cred->security = new_domain;
80 atomic_inc(&new_domain->users);
81 atomic_dec(&old_domain->users);
82 commit_creds(cred);
83 error = 0;
84 }
85 }
86 }
87 tomoyo_read_unlock(idx);
88 } else
89 error = -EINVAL;
90out:
91 kfree(data);
92 return error ? error : count;
93}
94
95/**
96 * tomoyo_read_self - read() for /sys/kernel/security/tomoyo/self_domain interface.
97 *
98 * @file: Pointer to "struct file".
99 * @buf: Domainname which current thread belongs to.
100 * @count: Size of @buf.
101 * @ppos: Bytes read by now.
102 *
103 * Returns read size on success, negative value otherwise.
104 */
105static ssize_t tomoyo_read_self(struct file *file, char __user *buf,
106 size_t count, loff_t *ppos)
107{
108 const char *domain = tomoyo_domain()->domainname->name;
109 loff_t len = strlen(domain);
110 loff_t pos = *ppos;
111 if (pos >= len || !count)
112 return 0;
113 len -= pos;
114 if (count < len)
115 len = count;
116 if (copy_to_user(buf, domain + pos, len))
117 return -EFAULT;
118 *ppos += len;
119 return len;
120}
121
122/* Operations for /sys/kernel/security/tomoyo/self_domain interface. */
123static const struct file_operations tomoyo_self_operations = {
124 .write = tomoyo_write_self,
125 .read = tomoyo_read_self,
126};
127
128/**
11 * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. 129 * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
12 * 130 *
13 * @inode: Pointer to "struct inode". 131 * @inode: Pointer to "struct inode".
@@ -135,8 +253,6 @@ static int __init tomoyo_initerface_init(void)
135 TOMOYO_EXCEPTIONPOLICY); 253 TOMOYO_EXCEPTIONPOLICY);
136 tomoyo_create_entry("audit", 0400, tomoyo_dir, 254 tomoyo_create_entry("audit", 0400, tomoyo_dir,
137 TOMOYO_AUDIT); 255 TOMOYO_AUDIT);
138 tomoyo_create_entry("self_domain", 0400, tomoyo_dir,
139 TOMOYO_SELFDOMAIN);
140 tomoyo_create_entry(".process_status", 0600, tomoyo_dir, 256 tomoyo_create_entry(".process_status", 0600, tomoyo_dir,
141 TOMOYO_PROCESS_STATUS); 257 TOMOYO_PROCESS_STATUS);
142 tomoyo_create_entry("stat", 0644, tomoyo_dir, 258 tomoyo_create_entry("stat", 0644, tomoyo_dir,
@@ -147,6 +263,8 @@ static int __init tomoyo_initerface_init(void)
147 TOMOYO_MANAGER); 263 TOMOYO_MANAGER);
148 tomoyo_create_entry("version", 0400, tomoyo_dir, 264 tomoyo_create_entry("version", 0400, tomoyo_dir,
149 TOMOYO_VERSION); 265 TOMOYO_VERSION);
266 securityfs_create_file("self_domain", 0666, tomoyo_dir, NULL,
267 &tomoyo_self_operations);
150 return 0; 268 return 0;
151} 269}
152 270
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c
index a1c3d9ccebfa..50e9b4c73ceb 100644
--- a/security/tomoyo/util.c
+++ b/security/tomoyo/util.c
@@ -159,6 +159,31 @@ char *tomoyo_read_token(struct tomoyo_acl_param *param)
159} 159}
160 160
161/** 161/**
162 * tomoyo_get_domainname - Read a domainname from a line.
163 *
164 * @param: Pointer to "struct tomoyo_acl_param".
165 *
166 * Returns a domainname on success, NULL otherwise.
167 */
168const struct tomoyo_path_info *tomoyo_get_domainname
169(struct tomoyo_acl_param *param)
170{
171 char *start = param->data;
172 char *pos = start;
173 while (*pos) {
174 if (*pos++ != ' ' || *pos++ == '/')
175 continue;
176 pos -= 2;
177 *pos++ = '\0';
178 break;
179 }
180 param->data = pos;
181 if (tomoyo_correct_domain(start))
182 return tomoyo_get_name(start);
183 return NULL;
184}
185
186/**
162 * tomoyo_parse_ulong - Parse an "unsigned long" value. 187 * tomoyo_parse_ulong - Parse an "unsigned long" value.
163 * 188 *
164 * @result: Pointer to "unsigned long". 189 * @result: Pointer to "unsigned long".