diff options
Diffstat (limited to 'security/tomoyo/common.c')
-rw-r--r-- | security/tomoyo/common.c | 1959 |
1 files changed, 1263 insertions, 696 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index a0d09e56874b..c8439cf2a448 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/common.c | 2 | * security/tomoyo/common.c |
3 | * | 3 | * |
4 | * Common functions for TOMOYO. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include <linux/uaccess.h> | 7 | #include <linux/uaccess.h> |
@@ -11,54 +9,131 @@ | |||
11 | #include <linux/security.h> | 9 | #include <linux/security.h> |
12 | #include "common.h" | 10 | #include "common.h" |
13 | 11 | ||
14 | static struct tomoyo_profile tomoyo_default_profile = { | 12 | /* String table for operation mode. */ |
15 | .learning = &tomoyo_default_profile.preference, | 13 | const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = { |
16 | .permissive = &tomoyo_default_profile.preference, | 14 | [TOMOYO_CONFIG_DISABLED] = "disabled", |
17 | .enforcing = &tomoyo_default_profile.preference, | 15 | [TOMOYO_CONFIG_LEARNING] = "learning", |
18 | .preference.enforcing_verbose = true, | 16 | [TOMOYO_CONFIG_PERMISSIVE] = "permissive", |
19 | .preference.learning_max_entry = 2048, | 17 | [TOMOYO_CONFIG_ENFORCING] = "enforcing" |
20 | .preference.learning_verbose = false, | ||
21 | .preference.permissive_verbose = true | ||
22 | }; | 18 | }; |
23 | 19 | ||
24 | /* Profile version. Currently only 20090903 is defined. */ | 20 | /* String table for /sys/kernel/security/tomoyo/profile */ |
25 | static unsigned int tomoyo_profile_version; | 21 | const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX |
22 | + TOMOYO_MAX_MAC_CATEGORY_INDEX] = { | ||
23 | [TOMOYO_MAC_FILE_EXECUTE] = "execute", | ||
24 | [TOMOYO_MAC_FILE_OPEN] = "open", | ||
25 | [TOMOYO_MAC_FILE_CREATE] = "create", | ||
26 | [TOMOYO_MAC_FILE_UNLINK] = "unlink", | ||
27 | [TOMOYO_MAC_FILE_GETATTR] = "getattr", | ||
28 | [TOMOYO_MAC_FILE_MKDIR] = "mkdir", | ||
29 | [TOMOYO_MAC_FILE_RMDIR] = "rmdir", | ||
30 | [TOMOYO_MAC_FILE_MKFIFO] = "mkfifo", | ||
31 | [TOMOYO_MAC_FILE_MKSOCK] = "mksock", | ||
32 | [TOMOYO_MAC_FILE_TRUNCATE] = "truncate", | ||
33 | [TOMOYO_MAC_FILE_SYMLINK] = "symlink", | ||
34 | [TOMOYO_MAC_FILE_MKBLOCK] = "mkblock", | ||
35 | [TOMOYO_MAC_FILE_MKCHAR] = "mkchar", | ||
36 | [TOMOYO_MAC_FILE_LINK] = "link", | ||
37 | [TOMOYO_MAC_FILE_RENAME] = "rename", | ||
38 | [TOMOYO_MAC_FILE_CHMOD] = "chmod", | ||
39 | [TOMOYO_MAC_FILE_CHOWN] = "chown", | ||
40 | [TOMOYO_MAC_FILE_CHGRP] = "chgrp", | ||
41 | [TOMOYO_MAC_FILE_IOCTL] = "ioctl", | ||
42 | [TOMOYO_MAC_FILE_CHROOT] = "chroot", | ||
43 | [TOMOYO_MAC_FILE_MOUNT] = "mount", | ||
44 | [TOMOYO_MAC_FILE_UMOUNT] = "unmount", | ||
45 | [TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root", | ||
46 | [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file", | ||
47 | }; | ||
26 | 48 | ||
27 | /* Profile table. Memory is allocated as needed. */ | 49 | /* String table for conditions. */ |
28 | static struct tomoyo_profile *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES]; | 50 | const char * const tomoyo_condition_keyword[TOMOYO_MAX_CONDITION_KEYWORD] = { |
51 | [TOMOYO_TASK_UID] = "task.uid", | ||
52 | [TOMOYO_TASK_EUID] = "task.euid", | ||
53 | [TOMOYO_TASK_SUID] = "task.suid", | ||
54 | [TOMOYO_TASK_FSUID] = "task.fsuid", | ||
55 | [TOMOYO_TASK_GID] = "task.gid", | ||
56 | [TOMOYO_TASK_EGID] = "task.egid", | ||
57 | [TOMOYO_TASK_SGID] = "task.sgid", | ||
58 | [TOMOYO_TASK_FSGID] = "task.fsgid", | ||
59 | [TOMOYO_TASK_PID] = "task.pid", | ||
60 | [TOMOYO_TASK_PPID] = "task.ppid", | ||
61 | [TOMOYO_EXEC_ARGC] = "exec.argc", | ||
62 | [TOMOYO_EXEC_ENVC] = "exec.envc", | ||
63 | [TOMOYO_TYPE_IS_SOCKET] = "socket", | ||
64 | [TOMOYO_TYPE_IS_SYMLINK] = "symlink", | ||
65 | [TOMOYO_TYPE_IS_FILE] = "file", | ||
66 | [TOMOYO_TYPE_IS_BLOCK_DEV] = "block", | ||
67 | [TOMOYO_TYPE_IS_DIRECTORY] = "directory", | ||
68 | [TOMOYO_TYPE_IS_CHAR_DEV] = "char", | ||
69 | [TOMOYO_TYPE_IS_FIFO] = "fifo", | ||
70 | [TOMOYO_MODE_SETUID] = "setuid", | ||
71 | [TOMOYO_MODE_SETGID] = "setgid", | ||
72 | [TOMOYO_MODE_STICKY] = "sticky", | ||
73 | [TOMOYO_MODE_OWNER_READ] = "owner_read", | ||
74 | [TOMOYO_MODE_OWNER_WRITE] = "owner_write", | ||
75 | [TOMOYO_MODE_OWNER_EXECUTE] = "owner_execute", | ||
76 | [TOMOYO_MODE_GROUP_READ] = "group_read", | ||
77 | [TOMOYO_MODE_GROUP_WRITE] = "group_write", | ||
78 | [TOMOYO_MODE_GROUP_EXECUTE] = "group_execute", | ||
79 | [TOMOYO_MODE_OTHERS_READ] = "others_read", | ||
80 | [TOMOYO_MODE_OTHERS_WRITE] = "others_write", | ||
81 | [TOMOYO_MODE_OTHERS_EXECUTE] = "others_execute", | ||
82 | [TOMOYO_EXEC_REALPATH] = "exec.realpath", | ||
83 | [TOMOYO_SYMLINK_TARGET] = "symlink.target", | ||
84 | [TOMOYO_PATH1_UID] = "path1.uid", | ||
85 | [TOMOYO_PATH1_GID] = "path1.gid", | ||
86 | [TOMOYO_PATH1_INO] = "path1.ino", | ||
87 | [TOMOYO_PATH1_MAJOR] = "path1.major", | ||
88 | [TOMOYO_PATH1_MINOR] = "path1.minor", | ||
89 | [TOMOYO_PATH1_PERM] = "path1.perm", | ||
90 | [TOMOYO_PATH1_TYPE] = "path1.type", | ||
91 | [TOMOYO_PATH1_DEV_MAJOR] = "path1.dev_major", | ||
92 | [TOMOYO_PATH1_DEV_MINOR] = "path1.dev_minor", | ||
93 | [TOMOYO_PATH2_UID] = "path2.uid", | ||
94 | [TOMOYO_PATH2_GID] = "path2.gid", | ||
95 | [TOMOYO_PATH2_INO] = "path2.ino", | ||
96 | [TOMOYO_PATH2_MAJOR] = "path2.major", | ||
97 | [TOMOYO_PATH2_MINOR] = "path2.minor", | ||
98 | [TOMOYO_PATH2_PERM] = "path2.perm", | ||
99 | [TOMOYO_PATH2_TYPE] = "path2.type", | ||
100 | [TOMOYO_PATH2_DEV_MAJOR] = "path2.dev_major", | ||
101 | [TOMOYO_PATH2_DEV_MINOR] = "path2.dev_minor", | ||
102 | [TOMOYO_PATH1_PARENT_UID] = "path1.parent.uid", | ||
103 | [TOMOYO_PATH1_PARENT_GID] = "path1.parent.gid", | ||
104 | [TOMOYO_PATH1_PARENT_INO] = "path1.parent.ino", | ||
105 | [TOMOYO_PATH1_PARENT_PERM] = "path1.parent.perm", | ||
106 | [TOMOYO_PATH2_PARENT_UID] = "path2.parent.uid", | ||
107 | [TOMOYO_PATH2_PARENT_GID] = "path2.parent.gid", | ||
108 | [TOMOYO_PATH2_PARENT_INO] = "path2.parent.ino", | ||
109 | [TOMOYO_PATH2_PARENT_PERM] = "path2.parent.perm", | ||
110 | }; | ||
29 | 111 | ||
30 | /* String table for functionality that takes 4 modes. */ | 112 | /* String table for PREFERENCE keyword. */ |
31 | static const char *tomoyo_mode[4] = { | 113 | static const char * const tomoyo_pref_keywords[TOMOYO_MAX_PREF] = { |
32 | "disabled", "learning", "permissive", "enforcing" | 114 | [TOMOYO_PREF_MAX_AUDIT_LOG] = "max_audit_log", |
115 | [TOMOYO_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry", | ||
33 | }; | 116 | }; |
34 | 117 | ||
35 | /* String table for /sys/kernel/security/tomoyo/profile */ | 118 | /* String table for path operation. */ |
36 | static const char *tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX | 119 | const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { |
37 | + TOMOYO_MAX_MAC_CATEGORY_INDEX] = { | 120 | [TOMOYO_TYPE_EXECUTE] = "execute", |
38 | [TOMOYO_MAC_FILE_EXECUTE] = "file::execute", | 121 | [TOMOYO_TYPE_READ] = "read", |
39 | [TOMOYO_MAC_FILE_OPEN] = "file::open", | 122 | [TOMOYO_TYPE_WRITE] = "write", |
40 | [TOMOYO_MAC_FILE_CREATE] = "file::create", | 123 | [TOMOYO_TYPE_APPEND] = "append", |
41 | [TOMOYO_MAC_FILE_UNLINK] = "file::unlink", | 124 | [TOMOYO_TYPE_UNLINK] = "unlink", |
42 | [TOMOYO_MAC_FILE_MKDIR] = "file::mkdir", | 125 | [TOMOYO_TYPE_GETATTR] = "getattr", |
43 | [TOMOYO_MAC_FILE_RMDIR] = "file::rmdir", | 126 | [TOMOYO_TYPE_RMDIR] = "rmdir", |
44 | [TOMOYO_MAC_FILE_MKFIFO] = "file::mkfifo", | 127 | [TOMOYO_TYPE_TRUNCATE] = "truncate", |
45 | [TOMOYO_MAC_FILE_MKSOCK] = "file::mksock", | 128 | [TOMOYO_TYPE_SYMLINK] = "symlink", |
46 | [TOMOYO_MAC_FILE_TRUNCATE] = "file::truncate", | 129 | [TOMOYO_TYPE_CHROOT] = "chroot", |
47 | [TOMOYO_MAC_FILE_SYMLINK] = "file::symlink", | 130 | [TOMOYO_TYPE_UMOUNT] = "unmount", |
48 | [TOMOYO_MAC_FILE_REWRITE] = "file::rewrite", | 131 | }; |
49 | [TOMOYO_MAC_FILE_MKBLOCK] = "file::mkblock", | 132 | |
50 | [TOMOYO_MAC_FILE_MKCHAR] = "file::mkchar", | 133 | /* String table for categories. */ |
51 | [TOMOYO_MAC_FILE_LINK] = "file::link", | 134 | static const char * const tomoyo_category_keywords |
52 | [TOMOYO_MAC_FILE_RENAME] = "file::rename", | 135 | [TOMOYO_MAX_MAC_CATEGORY_INDEX] = { |
53 | [TOMOYO_MAC_FILE_CHMOD] = "file::chmod", | 136 | [TOMOYO_MAC_CATEGORY_FILE] = "file", |
54 | [TOMOYO_MAC_FILE_CHOWN] = "file::chown", | ||
55 | [TOMOYO_MAC_FILE_CHGRP] = "file::chgrp", | ||
56 | [TOMOYO_MAC_FILE_IOCTL] = "file::ioctl", | ||
57 | [TOMOYO_MAC_FILE_CHROOT] = "file::chroot", | ||
58 | [TOMOYO_MAC_FILE_MOUNT] = "file::mount", | ||
59 | [TOMOYO_MAC_FILE_UMOUNT] = "file::umount", | ||
60 | [TOMOYO_MAC_FILE_PIVOT_ROOT] = "file::pivot_root", | ||
61 | [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file", | ||
62 | }; | 137 | }; |
63 | 138 | ||
64 | /* Permit policy management by non-root user? */ | 139 | /* Permit policy management by non-root user? */ |
@@ -71,11 +146,20 @@ static bool tomoyo_manage_by_non_root; | |||
71 | * | 146 | * |
72 | * @value: Bool value. | 147 | * @value: Bool value. |
73 | */ | 148 | */ |
74 | static const char *tomoyo_yesno(const unsigned int value) | 149 | const char *tomoyo_yesno(const unsigned int value) |
75 | { | 150 | { |
76 | return value ? "yes" : "no"; | 151 | return value ? "yes" : "no"; |
77 | } | 152 | } |
78 | 153 | ||
154 | /** | ||
155 | * tomoyo_addprintf - strncat()-like-snprintf(). | ||
156 | * | ||
157 | * @buffer: Buffer to write to. Must be '\0'-terminated. | ||
158 | * @len: Size of @buffer. | ||
159 | * @fmt: The printf()'s format string, followed by parameters. | ||
160 | * | ||
161 | * Returns nothing. | ||
162 | */ | ||
79 | static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...) | 163 | static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...) |
80 | { | 164 | { |
81 | va_list args; | 165 | va_list args; |
@@ -96,7 +180,7 @@ static bool tomoyo_flush(struct tomoyo_io_buffer *head) | |||
96 | { | 180 | { |
97 | while (head->r.w_pos) { | 181 | while (head->r.w_pos) { |
98 | const char *w = head->r.w[0]; | 182 | const char *w = head->r.w[0]; |
99 | int len = strlen(w); | 183 | size_t len = strlen(w); |
100 | if (len) { | 184 | if (len) { |
101 | if (len > head->read_user_buf_avail) | 185 | if (len > head->read_user_buf_avail) |
102 | len = head->read_user_buf_avail; | 186 | len = head->read_user_buf_avail; |
@@ -111,7 +195,7 @@ static bool tomoyo_flush(struct tomoyo_io_buffer *head) | |||
111 | head->r.w[0] = w; | 195 | head->r.w[0] = w; |
112 | if (*w) | 196 | if (*w) |
113 | return false; | 197 | return false; |
114 | /* Add '\0' for query. */ | 198 | /* Add '\0' for audit logs and query. */ |
115 | if (head->poll) { | 199 | if (head->poll) { |
116 | if (!head->read_user_buf_avail || | 200 | if (!head->read_user_buf_avail || |
117 | copy_to_user(head->read_user_buf, "", 1)) | 201 | copy_to_user(head->read_user_buf, "", 1)) |
@@ -155,8 +239,8 @@ static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string) | |||
155 | void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | 239 | void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) |
156 | { | 240 | { |
157 | va_list args; | 241 | va_list args; |
158 | int len; | 242 | size_t len; |
159 | int pos = head->r.avail; | 243 | size_t pos = head->r.avail; |
160 | int size = head->readbuf_size - pos; | 244 | int size = head->readbuf_size - pos; |
161 | if (size <= 0) | 245 | if (size <= 0) |
162 | return; | 246 | return; |
@@ -171,11 +255,25 @@ void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | |||
171 | tomoyo_set_string(head, head->read_buf + pos); | 255 | tomoyo_set_string(head, head->read_buf + pos); |
172 | } | 256 | } |
173 | 257 | ||
258 | /** | ||
259 | * tomoyo_set_space - Put a space to "struct tomoyo_io_buffer" structure. | ||
260 | * | ||
261 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
262 | * | ||
263 | * Returns nothing. | ||
264 | */ | ||
174 | static void tomoyo_set_space(struct tomoyo_io_buffer *head) | 265 | static void tomoyo_set_space(struct tomoyo_io_buffer *head) |
175 | { | 266 | { |
176 | tomoyo_set_string(head, " "); | 267 | tomoyo_set_string(head, " "); |
177 | } | 268 | } |
178 | 269 | ||
270 | /** | ||
271 | * tomoyo_set_lf - Put a line feed to "struct tomoyo_io_buffer" structure. | ||
272 | * | ||
273 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
274 | * | ||
275 | * Returns nothing. | ||
276 | */ | ||
179 | static bool tomoyo_set_lf(struct tomoyo_io_buffer *head) | 277 | static bool tomoyo_set_lf(struct tomoyo_io_buffer *head) |
180 | { | 278 | { |
181 | tomoyo_set_string(head, "\n"); | 279 | tomoyo_set_string(head, "\n"); |
@@ -183,6 +281,62 @@ static bool tomoyo_set_lf(struct tomoyo_io_buffer *head) | |||
183 | } | 281 | } |
184 | 282 | ||
185 | /** | 283 | /** |
284 | * tomoyo_set_slash - Put a shash to "struct tomoyo_io_buffer" structure. | ||
285 | * | ||
286 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
287 | * | ||
288 | * Returns nothing. | ||
289 | */ | ||
290 | static void tomoyo_set_slash(struct tomoyo_io_buffer *head) | ||
291 | { | ||
292 | tomoyo_set_string(head, "/"); | ||
293 | } | ||
294 | |||
295 | /* List of namespaces. */ | ||
296 | LIST_HEAD(tomoyo_namespace_list); | ||
297 | /* True if namespace other than tomoyo_kernel_namespace is defined. */ | ||
298 | static bool tomoyo_namespace_enabled; | ||
299 | |||
300 | /** | ||
301 | * tomoyo_init_policy_namespace - Initialize namespace. | ||
302 | * | ||
303 | * @ns: Pointer to "struct tomoyo_policy_namespace". | ||
304 | * | ||
305 | * Returns nothing. | ||
306 | */ | ||
307 | void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns) | ||
308 | { | ||
309 | unsigned int idx; | ||
310 | for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++) | ||
311 | INIT_LIST_HEAD(&ns->acl_group[idx]); | ||
312 | for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++) | ||
313 | INIT_LIST_HEAD(&ns->group_list[idx]); | ||
314 | for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++) | ||
315 | INIT_LIST_HEAD(&ns->policy_list[idx]); | ||
316 | ns->profile_version = 20100903; | ||
317 | tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list); | ||
318 | list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list); | ||
319 | } | ||
320 | |||
321 | /** | ||
322 | * tomoyo_print_namespace - Print namespace header. | ||
323 | * | ||
324 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
325 | * | ||
326 | * Returns nothing. | ||
327 | */ | ||
328 | static void tomoyo_print_namespace(struct tomoyo_io_buffer *head) | ||
329 | { | ||
330 | if (!tomoyo_namespace_enabled) | ||
331 | return; | ||
332 | tomoyo_set_string(head, | ||
333 | container_of(head->r.ns, | ||
334 | struct tomoyo_policy_namespace, | ||
335 | namespace_list)->name); | ||
336 | tomoyo_set_space(head); | ||
337 | } | ||
338 | |||
339 | /** | ||
186 | * tomoyo_print_name_union - Print a tomoyo_name_union. | 340 | * tomoyo_print_name_union - Print a tomoyo_name_union. |
187 | * | 341 | * |
188 | * @head: Pointer to "struct tomoyo_io_buffer". | 342 | * @head: Pointer to "struct tomoyo_io_buffer". |
@@ -192,7 +346,7 @@ static void tomoyo_print_name_union(struct tomoyo_io_buffer *head, | |||
192 | const struct tomoyo_name_union *ptr) | 346 | const struct tomoyo_name_union *ptr) |
193 | { | 347 | { |
194 | tomoyo_set_space(head); | 348 | tomoyo_set_space(head); |
195 | if (ptr->is_group) { | 349 | if (ptr->group) { |
196 | tomoyo_set_string(head, "@"); | 350 | tomoyo_set_string(head, "@"); |
197 | tomoyo_set_string(head, ptr->group->group_name->name); | 351 | tomoyo_set_string(head, ptr->group->group_name->name); |
198 | } else { | 352 | } else { |
@@ -201,24 +355,46 @@ static void tomoyo_print_name_union(struct tomoyo_io_buffer *head, | |||
201 | } | 355 | } |
202 | 356 | ||
203 | /** | 357 | /** |
204 | * tomoyo_print_number_union - Print a tomoyo_number_union. | 358 | * tomoyo_print_name_union_quoted - Print a tomoyo_name_union with a quote. |
205 | * | 359 | * |
206 | * @head: Pointer to "struct tomoyo_io_buffer". | 360 | * @head: Pointer to "struct tomoyo_io_buffer". |
207 | * @ptr: Pointer to "struct tomoyo_number_union". | 361 | * @ptr: Pointer to "struct tomoyo_name_union". |
362 | * | ||
363 | * Returns nothing. | ||
208 | */ | 364 | */ |
209 | static void tomoyo_print_number_union(struct tomoyo_io_buffer *head, | 365 | static void tomoyo_print_name_union_quoted(struct tomoyo_io_buffer *head, |
210 | const struct tomoyo_number_union *ptr) | 366 | const struct tomoyo_name_union *ptr) |
211 | { | 367 | { |
212 | tomoyo_set_space(head); | 368 | if (ptr->group) { |
213 | if (ptr->is_group) { | 369 | tomoyo_set_string(head, "@"); |
370 | tomoyo_set_string(head, ptr->group->group_name->name); | ||
371 | } else { | ||
372 | tomoyo_set_string(head, "\""); | ||
373 | tomoyo_set_string(head, ptr->filename->name); | ||
374 | tomoyo_set_string(head, "\""); | ||
375 | } | ||
376 | } | ||
377 | |||
378 | /** | ||
379 | * tomoyo_print_number_union_nospace - Print a tomoyo_number_union without a space. | ||
380 | * | ||
381 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
382 | * @ptr: Pointer to "struct tomoyo_number_union". | ||
383 | * | ||
384 | * Returns nothing. | ||
385 | */ | ||
386 | static void tomoyo_print_number_union_nospace | ||
387 | (struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr) | ||
388 | { | ||
389 | if (ptr->group) { | ||
214 | tomoyo_set_string(head, "@"); | 390 | tomoyo_set_string(head, "@"); |
215 | tomoyo_set_string(head, ptr->group->group_name->name); | 391 | tomoyo_set_string(head, ptr->group->group_name->name); |
216 | } else { | 392 | } else { |
217 | int i; | 393 | int i; |
218 | unsigned long min = ptr->values[0]; | 394 | unsigned long min = ptr->values[0]; |
219 | const unsigned long max = ptr->values[1]; | 395 | const unsigned long max = ptr->values[1]; |
220 | u8 min_type = ptr->min_type; | 396 | u8 min_type = ptr->value_type[0]; |
221 | const u8 max_type = ptr->max_type; | 397 | const u8 max_type = ptr->value_type[1]; |
222 | char buffer[128]; | 398 | char buffer[128]; |
223 | buffer[0] = '\0'; | 399 | buffer[0] = '\0'; |
224 | for (i = 0; i < 2; i++) { | 400 | for (i = 0; i < 2; i++) { |
@@ -232,8 +408,8 @@ static void tomoyo_print_number_union(struct tomoyo_io_buffer *head, | |||
232 | "0%lo", min); | 408 | "0%lo", min); |
233 | break; | 409 | break; |
234 | default: | 410 | default: |
235 | tomoyo_addprintf(buffer, sizeof(buffer), | 411 | tomoyo_addprintf(buffer, sizeof(buffer), "%lu", |
236 | "%lu", min); | 412 | min); |
237 | break; | 413 | break; |
238 | } | 414 | } |
239 | if (min == max && min_type == max_type) | 415 | if (min == max && min_type == max_type) |
@@ -247,35 +423,53 @@ static void tomoyo_print_number_union(struct tomoyo_io_buffer *head, | |||
247 | } | 423 | } |
248 | 424 | ||
249 | /** | 425 | /** |
426 | * tomoyo_print_number_union - Print a tomoyo_number_union. | ||
427 | * | ||
428 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
429 | * @ptr: Pointer to "struct tomoyo_number_union". | ||
430 | * | ||
431 | * Returns nothing. | ||
432 | */ | ||
433 | static void tomoyo_print_number_union(struct tomoyo_io_buffer *head, | ||
434 | const struct tomoyo_number_union *ptr) | ||
435 | { | ||
436 | tomoyo_set_space(head); | ||
437 | tomoyo_print_number_union_nospace(head, ptr); | ||
438 | } | ||
439 | |||
440 | /** | ||
250 | * tomoyo_assign_profile - Create a new profile. | 441 | * tomoyo_assign_profile - Create a new profile. |
251 | * | 442 | * |
443 | * @ns: Pointer to "struct tomoyo_policy_namespace". | ||
252 | * @profile: Profile number to create. | 444 | * @profile: Profile number to create. |
253 | * | 445 | * |
254 | * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise. | 446 | * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise. |
255 | */ | 447 | */ |
256 | static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile) | 448 | static struct tomoyo_profile *tomoyo_assign_profile |
449 | (struct tomoyo_policy_namespace *ns, const unsigned int profile) | ||
257 | { | 450 | { |
258 | struct tomoyo_profile *ptr; | 451 | struct tomoyo_profile *ptr; |
259 | struct tomoyo_profile *entry; | 452 | struct tomoyo_profile *entry; |
260 | if (profile >= TOMOYO_MAX_PROFILES) | 453 | if (profile >= TOMOYO_MAX_PROFILES) |
261 | return NULL; | 454 | return NULL; |
262 | ptr = tomoyo_profile_ptr[profile]; | 455 | ptr = ns->profile_ptr[profile]; |
263 | if (ptr) | 456 | if (ptr) |
264 | return ptr; | 457 | return ptr; |
265 | entry = kzalloc(sizeof(*entry), GFP_NOFS); | 458 | entry = kzalloc(sizeof(*entry), GFP_NOFS); |
266 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 459 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
267 | goto out; | 460 | goto out; |
268 | ptr = tomoyo_profile_ptr[profile]; | 461 | ptr = ns->profile_ptr[profile]; |
269 | if (!ptr && tomoyo_memory_ok(entry)) { | 462 | if (!ptr && tomoyo_memory_ok(entry)) { |
270 | ptr = entry; | 463 | ptr = entry; |
271 | ptr->learning = &tomoyo_default_profile.preference; | 464 | ptr->default_config = TOMOYO_CONFIG_DISABLED | |
272 | ptr->permissive = &tomoyo_default_profile.preference; | 465 | TOMOYO_CONFIG_WANT_GRANT_LOG | |
273 | ptr->enforcing = &tomoyo_default_profile.preference; | 466 | TOMOYO_CONFIG_WANT_REJECT_LOG; |
274 | ptr->default_config = TOMOYO_CONFIG_DISABLED; | ||
275 | memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT, | 467 | memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT, |
276 | sizeof(ptr->config)); | 468 | sizeof(ptr->config)); |
469 | ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 1024; | ||
470 | ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048; | ||
277 | mb(); /* Avoid out-of-order execution. */ | 471 | mb(); /* Avoid out-of-order execution. */ |
278 | tomoyo_profile_ptr[profile] = ptr; | 472 | ns->profile_ptr[profile] = ptr; |
279 | entry = NULL; | 473 | entry = NULL; |
280 | } | 474 | } |
281 | mutex_unlock(&tomoyo_policy_lock); | 475 | mutex_unlock(&tomoyo_policy_lock); |
@@ -287,19 +481,29 @@ static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile) | |||
287 | /** | 481 | /** |
288 | * tomoyo_profile - Find a profile. | 482 | * tomoyo_profile - Find a profile. |
289 | * | 483 | * |
484 | * @ns: Pointer to "struct tomoyo_policy_namespace". | ||
290 | * @profile: Profile number to find. | 485 | * @profile: Profile number to find. |
291 | * | 486 | * |
292 | * Returns pointer to "struct tomoyo_profile". | 487 | * Returns pointer to "struct tomoyo_profile". |
293 | */ | 488 | */ |
294 | struct tomoyo_profile *tomoyo_profile(const u8 profile) | 489 | struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns, |
490 | const u8 profile) | ||
295 | { | 491 | { |
296 | struct tomoyo_profile *ptr = tomoyo_profile_ptr[profile]; | 492 | static struct tomoyo_profile tomoyo_null_profile; |
297 | if (!tomoyo_policy_loaded) | 493 | struct tomoyo_profile *ptr = ns->profile_ptr[profile]; |
298 | return &tomoyo_default_profile; | 494 | if (!ptr) |
299 | BUG_ON(!ptr); | 495 | ptr = &tomoyo_null_profile; |
300 | return ptr; | 496 | return ptr; |
301 | } | 497 | } |
302 | 498 | ||
499 | /** | ||
500 | * tomoyo_find_yesno - Find values for specified keyword. | ||
501 | * | ||
502 | * @string: String to check. | ||
503 | * @find: Name of keyword. | ||
504 | * | ||
505 | * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise. | ||
506 | */ | ||
303 | static s8 tomoyo_find_yesno(const char *string, const char *find) | 507 | static s8 tomoyo_find_yesno(const char *string, const char *find) |
304 | { | 508 | { |
305 | const char *cp = strstr(string, find); | 509 | const char *cp = strstr(string, find); |
@@ -313,18 +517,15 @@ static s8 tomoyo_find_yesno(const char *string, const char *find) | |||
313 | return -1; | 517 | return -1; |
314 | } | 518 | } |
315 | 519 | ||
316 | static void tomoyo_set_bool(bool *b, const char *string, const char *find) | 520 | /** |
317 | { | 521 | * tomoyo_set_uint - Set value for specified preference. |
318 | switch (tomoyo_find_yesno(string, find)) { | 522 | * |
319 | case 1: | 523 | * @i: Pointer to "unsigned int". |
320 | *b = true; | 524 | * @string: String to check. |
321 | break; | 525 | * @find: Name of keyword. |
322 | case 0: | 526 | * |
323 | *b = false; | 527 | * Returns nothing. |
324 | break; | 528 | */ |
325 | } | ||
326 | } | ||
327 | |||
328 | static void tomoyo_set_uint(unsigned int *i, const char *string, | 529 | static void tomoyo_set_uint(unsigned int *i, const char *string, |
329 | const char *find) | 530 | const char *find) |
330 | { | 531 | { |
@@ -333,51 +534,16 @@ static void tomoyo_set_uint(unsigned int *i, const char *string, | |||
333 | sscanf(cp + strlen(find), "=%u", i); | 534 | sscanf(cp + strlen(find), "=%u", i); |
334 | } | 535 | } |
335 | 536 | ||
336 | static void tomoyo_set_pref(const char *name, const char *value, | 537 | /** |
337 | const bool use_default, | 538 | * tomoyo_set_mode - Set mode for specified profile. |
338 | struct tomoyo_profile *profile) | 539 | * |
339 | { | 540 | * @name: Name of functionality. |
340 | struct tomoyo_preference **pref; | 541 | * @value: Mode for @name. |
341 | bool *verbose; | 542 | * @profile: Pointer to "struct tomoyo_profile". |
342 | if (!strcmp(name, "enforcing")) { | 543 | * |
343 | if (use_default) { | 544 | * Returns 0 on success, negative value otherwise. |
344 | pref = &profile->enforcing; | 545 | */ |
345 | goto set_default; | ||
346 | } | ||
347 | profile->enforcing = &profile->preference; | ||
348 | verbose = &profile->preference.enforcing_verbose; | ||
349 | goto set_verbose; | ||
350 | } | ||
351 | if (!strcmp(name, "permissive")) { | ||
352 | if (use_default) { | ||
353 | pref = &profile->permissive; | ||
354 | goto set_default; | ||
355 | } | ||
356 | profile->permissive = &profile->preference; | ||
357 | verbose = &profile->preference.permissive_verbose; | ||
358 | goto set_verbose; | ||
359 | } | ||
360 | if (!strcmp(name, "learning")) { | ||
361 | if (use_default) { | ||
362 | pref = &profile->learning; | ||
363 | goto set_default; | ||
364 | } | ||
365 | profile->learning = &profile->preference; | ||
366 | tomoyo_set_uint(&profile->preference.learning_max_entry, value, | ||
367 | "max_entry"); | ||
368 | verbose = &profile->preference.learning_verbose; | ||
369 | goto set_verbose; | ||
370 | } | ||
371 | return; | ||
372 | set_default: | ||
373 | *pref = &tomoyo_default_profile.preference; | ||
374 | return; | ||
375 | set_verbose: | ||
376 | tomoyo_set_bool(verbose, value, "verbose"); | ||
377 | } | ||
378 | |||
379 | static int tomoyo_set_mode(char *name, const char *value, | 546 | static int tomoyo_set_mode(char *name, const char *value, |
380 | const bool use_default, | ||
381 | struct tomoyo_profile *profile) | 547 | struct tomoyo_profile *profile) |
382 | { | 548 | { |
383 | u8 i; | 549 | u8 i; |
@@ -389,7 +555,17 @@ static int tomoyo_set_mode(char *name, const char *value, | |||
389 | config = 0; | 555 | config = 0; |
390 | for (i = 0; i < TOMOYO_MAX_MAC_INDEX | 556 | for (i = 0; i < TOMOYO_MAX_MAC_INDEX |
391 | + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) { | 557 | + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) { |
392 | if (strcmp(name, tomoyo_mac_keywords[i])) | 558 | int len = 0; |
559 | if (i < TOMOYO_MAX_MAC_INDEX) { | ||
560 | const u8 c = tomoyo_index2category[i]; | ||
561 | const char *category = | ||
562 | tomoyo_category_keywords[c]; | ||
563 | len = strlen(category); | ||
564 | if (strncmp(name, category, len) || | ||
565 | name[len++] != ':' || name[len++] != ':') | ||
566 | continue; | ||
567 | } | ||
568 | if (strcmp(name + len, tomoyo_mac_keywords[i])) | ||
393 | continue; | 569 | continue; |
394 | config = profile->config[i]; | 570 | config = profile->config[i]; |
395 | break; | 571 | break; |
@@ -399,7 +575,7 @@ static int tomoyo_set_mode(char *name, const char *value, | |||
399 | } else { | 575 | } else { |
400 | return -EINVAL; | 576 | return -EINVAL; |
401 | } | 577 | } |
402 | if (use_default) { | 578 | if (strstr(value, "use_default")) { |
403 | config = TOMOYO_CONFIG_USE_DEFAULT; | 579 | config = TOMOYO_CONFIG_USE_DEFAULT; |
404 | } else { | 580 | } else { |
405 | u8 mode; | 581 | u8 mode; |
@@ -410,6 +586,24 @@ static int tomoyo_set_mode(char *name, const char *value, | |||
410 | * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'. | 586 | * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'. |
411 | */ | 587 | */ |
412 | config = (config & ~7) | mode; | 588 | config = (config & ~7) | mode; |
589 | if (config != TOMOYO_CONFIG_USE_DEFAULT) { | ||
590 | switch (tomoyo_find_yesno(value, "grant_log")) { | ||
591 | case 1: | ||
592 | config |= TOMOYO_CONFIG_WANT_GRANT_LOG; | ||
593 | break; | ||
594 | case 0: | ||
595 | config &= ~TOMOYO_CONFIG_WANT_GRANT_LOG; | ||
596 | break; | ||
597 | } | ||
598 | switch (tomoyo_find_yesno(value, "reject_log")) { | ||
599 | case 1: | ||
600 | config |= TOMOYO_CONFIG_WANT_REJECT_LOG; | ||
601 | break; | ||
602 | case 0: | ||
603 | config &= ~TOMOYO_CONFIG_WANT_REJECT_LOG; | ||
604 | break; | ||
605 | } | ||
606 | } | ||
413 | } | 607 | } |
414 | if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX) | 608 | if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX) |
415 | profile->config[i] = config; | 609 | profile->config[i] = config; |
@@ -429,34 +623,22 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | |||
429 | { | 623 | { |
430 | char *data = head->write_buf; | 624 | char *data = head->write_buf; |
431 | unsigned int i; | 625 | unsigned int i; |
432 | bool use_default = false; | ||
433 | char *cp; | 626 | char *cp; |
434 | struct tomoyo_profile *profile; | 627 | struct tomoyo_profile *profile; |
435 | if (sscanf(data, "PROFILE_VERSION=%u", &tomoyo_profile_version) == 1) | 628 | if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version) |
629 | == 1) | ||
436 | return 0; | 630 | return 0; |
437 | i = simple_strtoul(data, &cp, 10); | 631 | i = simple_strtoul(data, &cp, 10); |
438 | if (data == cp) { | 632 | if (*cp != '-') |
439 | profile = &tomoyo_default_profile; | 633 | return -EINVAL; |
440 | } else { | 634 | data = cp + 1; |
441 | if (*cp != '-') | 635 | profile = tomoyo_assign_profile(head->w.ns, i); |
442 | return -EINVAL; | 636 | if (!profile) |
443 | data = cp + 1; | 637 | return -EINVAL; |
444 | profile = tomoyo_assign_profile(i); | ||
445 | if (!profile) | ||
446 | return -EINVAL; | ||
447 | } | ||
448 | cp = strchr(data, '='); | 638 | cp = strchr(data, '='); |
449 | if (!cp) | 639 | if (!cp) |
450 | return -EINVAL; | 640 | return -EINVAL; |
451 | *cp++ = '\0'; | 641 | *cp++ = '\0'; |
452 | if (profile != &tomoyo_default_profile) | ||
453 | use_default = strstr(cp, "use_default") != NULL; | ||
454 | if (tomoyo_str_starts(&data, "PREFERENCE::")) { | ||
455 | tomoyo_set_pref(data, cp, use_default, profile); | ||
456 | return 0; | ||
457 | } | ||
458 | if (profile == &tomoyo_default_profile) | ||
459 | return -EINVAL; | ||
460 | if (!strcmp(data, "COMMENT")) { | 642 | if (!strcmp(data, "COMMENT")) { |
461 | static DEFINE_SPINLOCK(lock); | 643 | static DEFINE_SPINLOCK(lock); |
462 | const struct tomoyo_path_info *new_comment | 644 | const struct tomoyo_path_info *new_comment |
@@ -471,77 +653,62 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | |||
471 | tomoyo_put_name(old_comment); | 653 | tomoyo_put_name(old_comment); |
472 | return 0; | 654 | return 0; |
473 | } | 655 | } |
474 | return tomoyo_set_mode(data, cp, use_default, profile); | 656 | if (!strcmp(data, "PREFERENCE")) { |
475 | } | 657 | for (i = 0; i < TOMOYO_MAX_PREF; i++) |
476 | 658 | tomoyo_set_uint(&profile->pref[i], cp, | |
477 | static void tomoyo_print_preference(struct tomoyo_io_buffer *head, | 659 | tomoyo_pref_keywords[i]); |
478 | const int idx) | 660 | return 0; |
479 | { | ||
480 | struct tomoyo_preference *pref = &tomoyo_default_profile.preference; | ||
481 | const struct tomoyo_profile *profile = idx >= 0 ? | ||
482 | tomoyo_profile_ptr[idx] : NULL; | ||
483 | char buffer[16] = ""; | ||
484 | if (profile) { | ||
485 | buffer[sizeof(buffer) - 1] = '\0'; | ||
486 | snprintf(buffer, sizeof(buffer) - 1, "%u-", idx); | ||
487 | } | ||
488 | if (profile) { | ||
489 | pref = profile->learning; | ||
490 | if (pref == &tomoyo_default_profile.preference) | ||
491 | goto skip1; | ||
492 | } | ||
493 | tomoyo_io_printf(head, "%sPREFERENCE::%s={ " | ||
494 | "verbose=%s max_entry=%u }\n", | ||
495 | buffer, "learning", | ||
496 | tomoyo_yesno(pref->learning_verbose), | ||
497 | pref->learning_max_entry); | ||
498 | skip1: | ||
499 | if (profile) { | ||
500 | pref = profile->permissive; | ||
501 | if (pref == &tomoyo_default_profile.preference) | ||
502 | goto skip2; | ||
503 | } | ||
504 | tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n", | ||
505 | buffer, "permissive", | ||
506 | tomoyo_yesno(pref->permissive_verbose)); | ||
507 | skip2: | ||
508 | if (profile) { | ||
509 | pref = profile->enforcing; | ||
510 | if (pref == &tomoyo_default_profile.preference) | ||
511 | return; | ||
512 | } | 661 | } |
513 | tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n", | 662 | return tomoyo_set_mode(data, cp, profile); |
514 | buffer, "enforcing", | ||
515 | tomoyo_yesno(pref->enforcing_verbose)); | ||
516 | } | 663 | } |
517 | 664 | ||
665 | /** | ||
666 | * tomoyo_print_config - Print mode for specified functionality. | ||
667 | * | ||
668 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
669 | * @config: Mode for that functionality. | ||
670 | * | ||
671 | * Returns nothing. | ||
672 | * | ||
673 | * Caller prints functionality's name. | ||
674 | */ | ||
518 | static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config) | 675 | static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config) |
519 | { | 676 | { |
520 | tomoyo_io_printf(head, "={ mode=%s }\n", tomoyo_mode[config & 3]); | 677 | tomoyo_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n", |
678 | tomoyo_mode[config & 3], | ||
679 | tomoyo_yesno(config & TOMOYO_CONFIG_WANT_GRANT_LOG), | ||
680 | tomoyo_yesno(config & TOMOYO_CONFIG_WANT_REJECT_LOG)); | ||
521 | } | 681 | } |
522 | 682 | ||
523 | /** | 683 | /** |
524 | * tomoyo_read_profile - Read profile table. | 684 | * tomoyo_read_profile - Read profile table. |
525 | * | 685 | * |
526 | * @head: Pointer to "struct tomoyo_io_buffer". | 686 | * @head: Pointer to "struct tomoyo_io_buffer". |
687 | * | ||
688 | * Returns nothing. | ||
527 | */ | 689 | */ |
528 | static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | 690 | static void tomoyo_read_profile(struct tomoyo_io_buffer *head) |
529 | { | 691 | { |
530 | u8 index; | 692 | u8 index; |
693 | struct tomoyo_policy_namespace *ns = | ||
694 | container_of(head->r.ns, typeof(*ns), namespace_list); | ||
531 | const struct tomoyo_profile *profile; | 695 | const struct tomoyo_profile *profile; |
696 | if (head->r.eof) | ||
697 | return; | ||
532 | next: | 698 | next: |
533 | index = head->r.index; | 699 | index = head->r.index; |
534 | profile = tomoyo_profile_ptr[index]; | 700 | profile = ns->profile_ptr[index]; |
535 | switch (head->r.step) { | 701 | switch (head->r.step) { |
536 | case 0: | 702 | case 0: |
537 | tomoyo_io_printf(head, "PROFILE_VERSION=%s\n", "20090903"); | 703 | tomoyo_print_namespace(head); |
538 | tomoyo_print_preference(head, -1); | 704 | tomoyo_io_printf(head, "PROFILE_VERSION=%u\n", |
705 | ns->profile_version); | ||
539 | head->r.step++; | 706 | head->r.step++; |
540 | break; | 707 | break; |
541 | case 1: | 708 | case 1: |
542 | for ( ; head->r.index < TOMOYO_MAX_PROFILES; | 709 | for ( ; head->r.index < TOMOYO_MAX_PROFILES; |
543 | head->r.index++) | 710 | head->r.index++) |
544 | if (tomoyo_profile_ptr[head->r.index]) | 711 | if (ns->profile_ptr[head->r.index]) |
545 | break; | 712 | break; |
546 | if (head->r.index == TOMOYO_MAX_PROFILES) | 713 | if (head->r.index == TOMOYO_MAX_PROFILES) |
547 | return; | 714 | return; |
@@ -549,16 +716,25 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
549 | break; | 716 | break; |
550 | case 2: | 717 | case 2: |
551 | { | 718 | { |
719 | u8 i; | ||
552 | const struct tomoyo_path_info *comment = | 720 | const struct tomoyo_path_info *comment = |
553 | profile->comment; | 721 | profile->comment; |
722 | tomoyo_print_namespace(head); | ||
554 | tomoyo_io_printf(head, "%u-COMMENT=", index); | 723 | tomoyo_io_printf(head, "%u-COMMENT=", index); |
555 | tomoyo_set_string(head, comment ? comment->name : ""); | 724 | tomoyo_set_string(head, comment ? comment->name : ""); |
556 | tomoyo_set_lf(head); | 725 | tomoyo_set_lf(head); |
726 | tomoyo_io_printf(head, "%u-PREFERENCE={ ", index); | ||
727 | for (i = 0; i < TOMOYO_MAX_PREF; i++) | ||
728 | tomoyo_io_printf(head, "%s=%u ", | ||
729 | tomoyo_pref_keywords[i], | ||
730 | profile->pref[i]); | ||
731 | tomoyo_set_string(head, "}\n"); | ||
557 | head->r.step++; | 732 | head->r.step++; |
558 | } | 733 | } |
559 | break; | 734 | break; |
560 | case 3: | 735 | case 3: |
561 | { | 736 | { |
737 | tomoyo_print_namespace(head); | ||
562 | tomoyo_io_printf(head, "%u-%s", index, "CONFIG"); | 738 | tomoyo_io_printf(head, "%u-%s", index, "CONFIG"); |
563 | tomoyo_print_config(head, profile->default_config); | 739 | tomoyo_print_config(head, profile->default_config); |
564 | head->r.bit = 0; | 740 | head->r.bit = 0; |
@@ -572,15 +748,22 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
572 | const u8 config = profile->config[i]; | 748 | const u8 config = profile->config[i]; |
573 | if (config == TOMOYO_CONFIG_USE_DEFAULT) | 749 | if (config == TOMOYO_CONFIG_USE_DEFAULT) |
574 | continue; | 750 | continue; |
575 | tomoyo_io_printf(head, "%u-%s%s", index, "CONFIG::", | 751 | tomoyo_print_namespace(head); |
576 | tomoyo_mac_keywords[i]); | 752 | if (i < TOMOYO_MAX_MAC_INDEX) |
753 | tomoyo_io_printf(head, "%u-CONFIG::%s::%s", | ||
754 | index, | ||
755 | tomoyo_category_keywords | ||
756 | [tomoyo_index2category[i]], | ||
757 | tomoyo_mac_keywords[i]); | ||
758 | else | ||
759 | tomoyo_io_printf(head, "%u-CONFIG::%s", index, | ||
760 | tomoyo_mac_keywords[i]); | ||
577 | tomoyo_print_config(head, config); | 761 | tomoyo_print_config(head, config); |
578 | head->r.bit++; | 762 | head->r.bit++; |
579 | break; | 763 | break; |
580 | } | 764 | } |
581 | if (head->r.bit == TOMOYO_MAX_MAC_INDEX | 765 | if (head->r.bit == TOMOYO_MAX_MAC_INDEX |
582 | + TOMOYO_MAX_MAC_CATEGORY_INDEX) { | 766 | + TOMOYO_MAX_MAC_CATEGORY_INDEX) { |
583 | tomoyo_print_preference(head, index); | ||
584 | head->r.index++; | 767 | head->r.index++; |
585 | head->r.step = 1; | 768 | head->r.step = 1; |
586 | } | 769 | } |
@@ -590,6 +773,14 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
590 | goto next; | 773 | goto next; |
591 | } | 774 | } |
592 | 775 | ||
776 | /** | ||
777 | * tomoyo_same_manager - Check for duplicated "struct tomoyo_manager" entry. | ||
778 | * | ||
779 | * @a: Pointer to "struct tomoyo_acl_head". | ||
780 | * @b: Pointer to "struct tomoyo_acl_head". | ||
781 | * | ||
782 | * Returns true if @a == @b, false otherwise. | ||
783 | */ | ||
593 | static bool tomoyo_same_manager(const struct tomoyo_acl_head *a, | 784 | static bool tomoyo_same_manager(const struct tomoyo_acl_head *a, |
594 | const struct tomoyo_acl_head *b) | 785 | const struct tomoyo_acl_head *b) |
595 | { | 786 | { |
@@ -611,8 +802,13 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
611 | const bool is_delete) | 802 | const bool is_delete) |
612 | { | 803 | { |
613 | struct tomoyo_manager e = { }; | 804 | struct tomoyo_manager e = { }; |
614 | int error; | 805 | struct tomoyo_acl_param param = { |
615 | 806 | /* .ns = &tomoyo_kernel_namespace, */ | |
807 | .is_delete = is_delete, | ||
808 | .list = &tomoyo_kernel_namespace. | ||
809 | policy_list[TOMOYO_ID_MANAGER], | ||
810 | }; | ||
811 | int error = is_delete ? -ENOENT : -ENOMEM; | ||
616 | if (tomoyo_domain_def(manager)) { | 812 | if (tomoyo_domain_def(manager)) { |
617 | if (!tomoyo_correct_domain(manager)) | 813 | if (!tomoyo_correct_domain(manager)) |
618 | return -EINVAL; | 814 | return -EINVAL; |
@@ -622,12 +818,11 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
622 | return -EINVAL; | 818 | return -EINVAL; |
623 | } | 819 | } |
624 | e.manager = tomoyo_get_name(manager); | 820 | e.manager = tomoyo_get_name(manager); |
625 | if (!e.manager) | 821 | if (e.manager) { |
626 | return -ENOMEM; | 822 | error = tomoyo_update_policy(&e.head, sizeof(e), ¶m, |
627 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | 823 | tomoyo_same_manager); |
628 | &tomoyo_policy_list[TOMOYO_ID_MANAGER], | 824 | tomoyo_put_name(e.manager); |
629 | tomoyo_same_manager); | 825 | } |
630 | tomoyo_put_name(e.manager); | ||
631 | return error; | 826 | return error; |
632 | } | 827 | } |
633 | 828 | ||
@@ -643,13 +838,12 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
643 | static int tomoyo_write_manager(struct tomoyo_io_buffer *head) | 838 | static int tomoyo_write_manager(struct tomoyo_io_buffer *head) |
644 | { | 839 | { |
645 | char *data = head->write_buf; | 840 | char *data = head->write_buf; |
646 | bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE); | ||
647 | 841 | ||
648 | if (!strcmp(data, "manage_by_non_root")) { | 842 | if (!strcmp(data, "manage_by_non_root")) { |
649 | tomoyo_manage_by_non_root = !is_delete; | 843 | tomoyo_manage_by_non_root = !head->w.is_delete; |
650 | return 0; | 844 | return 0; |
651 | } | 845 | } |
652 | return tomoyo_update_manager_entry(data, is_delete); | 846 | return tomoyo_update_manager_entry(data, head->w.is_delete); |
653 | } | 847 | } |
654 | 848 | ||
655 | /** | 849 | /** |
@@ -663,8 +857,8 @@ static void tomoyo_read_manager(struct tomoyo_io_buffer *head) | |||
663 | { | 857 | { |
664 | if (head->r.eof) | 858 | if (head->r.eof) |
665 | return; | 859 | return; |
666 | list_for_each_cookie(head->r.acl, | 860 | list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace. |
667 | &tomoyo_policy_list[TOMOYO_ID_MANAGER]) { | 861 | policy_list[TOMOYO_ID_MANAGER]) { |
668 | struct tomoyo_manager *ptr = | 862 | struct tomoyo_manager *ptr = |
669 | list_entry(head->r.acl, typeof(*ptr), head.list); | 863 | list_entry(head->r.acl, typeof(*ptr), head.list); |
670 | if (ptr->head.is_deleted) | 864 | if (ptr->head.is_deleted) |
@@ -697,8 +891,8 @@ static bool tomoyo_manager(void) | |||
697 | return true; | 891 | return true; |
698 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) | 892 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) |
699 | return false; | 893 | return false; |
700 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER], | 894 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. |
701 | head.list) { | 895 | policy_list[TOMOYO_ID_MANAGER], head.list) { |
702 | if (!ptr->head.is_deleted && ptr->is_domain | 896 | if (!ptr->head.is_deleted && ptr->is_domain |
703 | && !tomoyo_pathcmp(domainname, ptr->manager)) { | 897 | && !tomoyo_pathcmp(domainname, ptr->manager)) { |
704 | found = true; | 898 | found = true; |
@@ -710,8 +904,8 @@ static bool tomoyo_manager(void) | |||
710 | exe = tomoyo_get_exe(); | 904 | exe = tomoyo_get_exe(); |
711 | if (!exe) | 905 | if (!exe) |
712 | return false; | 906 | return false; |
713 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER], | 907 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. |
714 | head.list) { | 908 | policy_list[TOMOYO_ID_MANAGER], head.list) { |
715 | if (!ptr->head.is_deleted && !ptr->is_domain | 909 | if (!ptr->head.is_deleted && !ptr->is_domain |
716 | && !strcmp(exe, ptr->manager->name)) { | 910 | && !strcmp(exe, ptr->manager->name)) { |
717 | found = true; | 911 | found = true; |
@@ -732,7 +926,7 @@ static bool tomoyo_manager(void) | |||
732 | } | 926 | } |
733 | 927 | ||
734 | /** | 928 | /** |
735 | * tomoyo_select_one - Parse select command. | 929 | * tomoyo_select_domain - Parse select command. |
736 | * | 930 | * |
737 | * @head: Pointer to "struct tomoyo_io_buffer". | 931 | * @head: Pointer to "struct tomoyo_io_buffer". |
738 | * @data: String to parse. | 932 | * @data: String to parse. |
@@ -741,16 +935,15 @@ static bool tomoyo_manager(void) | |||
741 | * | 935 | * |
742 | * Caller holds tomoyo_read_lock(). | 936 | * Caller holds tomoyo_read_lock(). |
743 | */ | 937 | */ |
744 | static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data) | 938 | static bool tomoyo_select_domain(struct tomoyo_io_buffer *head, |
939 | const char *data) | ||
745 | { | 940 | { |
746 | unsigned int pid; | 941 | unsigned int pid; |
747 | struct tomoyo_domain_info *domain = NULL; | 942 | struct tomoyo_domain_info *domain = NULL; |
748 | bool global_pid = false; | 943 | bool global_pid = false; |
749 | 944 | if (strncmp(data, "select ", 7)) | |
750 | if (!strcmp(data, "allow_execute")) { | 945 | return false; |
751 | head->r.print_execute_only = true; | 946 | data += 7; |
752 | return true; | ||
753 | } | ||
754 | if (sscanf(data, "pid=%u", &pid) == 1 || | 947 | if (sscanf(data, "pid=%u", &pid) == 1 || |
755 | (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { | 948 | (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { |
756 | struct task_struct *p; | 949 | struct task_struct *p; |
@@ -769,7 +962,7 @@ static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data) | |||
769 | domain = tomoyo_find_domain(data + 7); | 962 | domain = tomoyo_find_domain(data + 7); |
770 | } else | 963 | } else |
771 | return false; | 964 | return false; |
772 | head->write_var1 = domain; | 965 | head->w.domain = domain; |
773 | /* Accessing read_buf is safe because head->io_sem is held. */ | 966 | /* Accessing read_buf is safe because head->io_sem is held. */ |
774 | if (!head->read_buf) | 967 | if (!head->read_buf) |
775 | return true; /* Do nothing if open(O_WRONLY). */ | 968 | return true; /* Do nothing if open(O_WRONLY). */ |
@@ -821,20 +1014,47 @@ static int tomoyo_delete_domain(char *domainname) | |||
821 | /** | 1014 | /** |
822 | * tomoyo_write_domain2 - Write domain policy. | 1015 | * tomoyo_write_domain2 - Write domain policy. |
823 | * | 1016 | * |
824 | * @head: Pointer to "struct tomoyo_io_buffer". | 1017 | * @ns: Pointer to "struct tomoyo_policy_namespace". |
1018 | * @list: Pointer to "struct list_head". | ||
1019 | * @data: Policy to be interpreted. | ||
1020 | * @is_delete: True if it is a delete request. | ||
825 | * | 1021 | * |
826 | * Returns 0 on success, negative value otherwise. | 1022 | * Returns 0 on success, negative value otherwise. |
827 | * | 1023 | * |
828 | * Caller holds tomoyo_read_lock(). | 1024 | * Caller holds tomoyo_read_lock(). |
829 | */ | 1025 | */ |
830 | static int tomoyo_write_domain2(char *data, struct tomoyo_domain_info *domain, | 1026 | static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns, |
1027 | struct list_head *list, char *data, | ||
831 | const bool is_delete) | 1028 | const bool is_delete) |
832 | { | 1029 | { |
833 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_MOUNT)) | 1030 | struct tomoyo_acl_param param = { |
834 | return tomoyo_write_mount(data, domain, is_delete); | 1031 | .ns = ns, |
835 | return tomoyo_write_file(data, domain, is_delete); | 1032 | .list = list, |
1033 | .data = data, | ||
1034 | .is_delete = is_delete, | ||
1035 | }; | ||
1036 | static const struct { | ||
1037 | const char *keyword; | ||
1038 | int (*write) (struct tomoyo_acl_param *); | ||
1039 | } tomoyo_callback[1] = { | ||
1040 | { "file ", tomoyo_write_file }, | ||
1041 | }; | ||
1042 | u8 i; | ||
1043 | for (i = 0; i < 1; i++) { | ||
1044 | if (!tomoyo_str_starts(¶m.data, | ||
1045 | tomoyo_callback[i].keyword)) | ||
1046 | continue; | ||
1047 | return tomoyo_callback[i].write(¶m); | ||
1048 | } | ||
1049 | return -EINVAL; | ||
836 | } | 1050 | } |
837 | 1051 | ||
1052 | /* String table for domain flags. */ | ||
1053 | const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS] = { | ||
1054 | [TOMOYO_DIF_QUOTA_WARNED] = "quota_exceeded\n", | ||
1055 | [TOMOYO_DIF_TRANSITION_FAILED] = "transition_failed\n", | ||
1056 | }; | ||
1057 | |||
838 | /** | 1058 | /** |
839 | * tomoyo_write_domain - Write domain policy. | 1059 | * tomoyo_write_domain - Write domain policy. |
840 | * | 1060 | * |
@@ -847,69 +1067,198 @@ static int tomoyo_write_domain2(char *data, struct tomoyo_domain_info *domain, | |||
847 | static int tomoyo_write_domain(struct tomoyo_io_buffer *head) | 1067 | static int tomoyo_write_domain(struct tomoyo_io_buffer *head) |
848 | { | 1068 | { |
849 | char *data = head->write_buf; | 1069 | char *data = head->write_buf; |
850 | struct tomoyo_domain_info *domain = head->write_var1; | 1070 | struct tomoyo_policy_namespace *ns; |
851 | bool is_delete = false; | 1071 | struct tomoyo_domain_info *domain = head->w.domain; |
852 | bool is_select = false; | 1072 | const bool is_delete = head->w.is_delete; |
1073 | bool is_select = !is_delete && tomoyo_str_starts(&data, "select "); | ||
853 | unsigned int profile; | 1074 | unsigned int profile; |
854 | 1075 | if (*data == '<') { | |
855 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE)) | ||
856 | is_delete = true; | ||
857 | else if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_SELECT)) | ||
858 | is_select = true; | ||
859 | if (is_select && tomoyo_select_one(head, data)) | ||
860 | return 0; | ||
861 | /* Don't allow updating policies by non manager programs. */ | ||
862 | if (!tomoyo_manager()) | ||
863 | return -EPERM; | ||
864 | if (tomoyo_domain_def(data)) { | ||
865 | domain = NULL; | 1076 | domain = NULL; |
866 | if (is_delete) | 1077 | if (is_delete) |
867 | tomoyo_delete_domain(data); | 1078 | tomoyo_delete_domain(data); |
868 | else if (is_select) | 1079 | else if (is_select) |
869 | domain = tomoyo_find_domain(data); | 1080 | domain = tomoyo_find_domain(data); |
870 | else | 1081 | else |
871 | domain = tomoyo_assign_domain(data, 0); | 1082 | domain = tomoyo_assign_domain(data, false); |
872 | head->write_var1 = domain; | 1083 | head->w.domain = domain; |
873 | return 0; | 1084 | return 0; |
874 | } | 1085 | } |
875 | if (!domain) | 1086 | if (!domain) |
876 | return -EINVAL; | 1087 | return -EINVAL; |
877 | 1088 | ns = domain->ns; | |
878 | if (sscanf(data, TOMOYO_KEYWORD_USE_PROFILE "%u", &profile) == 1 | 1089 | if (sscanf(data, "use_profile %u", &profile) == 1 |
879 | && profile < TOMOYO_MAX_PROFILES) { | 1090 | && profile < TOMOYO_MAX_PROFILES) { |
880 | if (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded) | 1091 | if (!tomoyo_policy_loaded || ns->profile_ptr[profile]) |
881 | domain->profile = (u8) profile; | 1092 | domain->profile = (u8) profile; |
882 | return 0; | 1093 | return 0; |
883 | } | 1094 | } |
884 | if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) { | 1095 | if (sscanf(data, "use_group %u\n", &profile) == 1 |
885 | domain->ignore_global_allow_read = !is_delete; | 1096 | && profile < TOMOYO_MAX_ACL_GROUPS) { |
1097 | if (!is_delete) | ||
1098 | domain->group = (u8) profile; | ||
886 | return 0; | 1099 | return 0; |
887 | } | 1100 | } |
888 | if (!strcmp(data, TOMOYO_KEYWORD_QUOTA_EXCEEDED)) { | 1101 | for (profile = 0; profile < TOMOYO_MAX_DOMAIN_INFO_FLAGS; profile++) { |
889 | domain->quota_warned = !is_delete; | 1102 | const char *cp = tomoyo_dif[profile]; |
890 | return 0; | 1103 | if (strncmp(data, cp, strlen(cp) - 1)) |
891 | } | 1104 | continue; |
892 | if (!strcmp(data, TOMOYO_KEYWORD_TRANSITION_FAILED)) { | 1105 | domain->flags[profile] = !is_delete; |
893 | domain->transition_failed = !is_delete; | ||
894 | return 0; | 1106 | return 0; |
895 | } | 1107 | } |
896 | return tomoyo_write_domain2(data, domain, is_delete); | 1108 | return tomoyo_write_domain2(ns, &domain->acl_info_list, data, |
1109 | is_delete); | ||
897 | } | 1110 | } |
898 | 1111 | ||
899 | /** | 1112 | /** |
900 | * tomoyo_fns - Find next set bit. | 1113 | * tomoyo_print_condition - Print condition part. |
901 | * | 1114 | * |
902 | * @perm: 8 bits value. | 1115 | * @head: Pointer to "struct tomoyo_io_buffer". |
903 | * @bit: First bit to find. | 1116 | * @cond: Pointer to "struct tomoyo_condition". |
904 | * | 1117 | * |
905 | * Returns next on-bit on success, 8 otherwise. | 1118 | * Returns true on success, false otherwise. |
906 | */ | 1119 | */ |
907 | static u8 tomoyo_fns(const u8 perm, u8 bit) | 1120 | static bool tomoyo_print_condition(struct tomoyo_io_buffer *head, |
1121 | const struct tomoyo_condition *cond) | ||
908 | { | 1122 | { |
909 | for ( ; bit < 8; bit++) | 1123 | switch (head->r.cond_step) { |
910 | if (perm & (1 << bit)) | 1124 | case 0: |
1125 | head->r.cond_index = 0; | ||
1126 | head->r.cond_step++; | ||
1127 | /* fall through */ | ||
1128 | case 1: | ||
1129 | { | ||
1130 | const u16 condc = cond->condc; | ||
1131 | const struct tomoyo_condition_element *condp = | ||
1132 | (typeof(condp)) (cond + 1); | ||
1133 | const struct tomoyo_number_union *numbers_p = | ||
1134 | (typeof(numbers_p)) (condp + condc); | ||
1135 | const struct tomoyo_name_union *names_p = | ||
1136 | (typeof(names_p)) | ||
1137 | (numbers_p + cond->numbers_count); | ||
1138 | const struct tomoyo_argv *argv = | ||
1139 | (typeof(argv)) (names_p + cond->names_count); | ||
1140 | const struct tomoyo_envp *envp = | ||
1141 | (typeof(envp)) (argv + cond->argc); | ||
1142 | u16 skip; | ||
1143 | for (skip = 0; skip < head->r.cond_index; skip++) { | ||
1144 | const u8 left = condp->left; | ||
1145 | const u8 right = condp->right; | ||
1146 | condp++; | ||
1147 | switch (left) { | ||
1148 | case TOMOYO_ARGV_ENTRY: | ||
1149 | argv++; | ||
1150 | continue; | ||
1151 | case TOMOYO_ENVP_ENTRY: | ||
1152 | envp++; | ||
1153 | continue; | ||
1154 | case TOMOYO_NUMBER_UNION: | ||
1155 | numbers_p++; | ||
1156 | break; | ||
1157 | } | ||
1158 | switch (right) { | ||
1159 | case TOMOYO_NAME_UNION: | ||
1160 | names_p++; | ||
1161 | break; | ||
1162 | case TOMOYO_NUMBER_UNION: | ||
1163 | numbers_p++; | ||
1164 | break; | ||
1165 | } | ||
1166 | } | ||
1167 | while (head->r.cond_index < condc) { | ||
1168 | const u8 match = condp->equals; | ||
1169 | const u8 left = condp->left; | ||
1170 | const u8 right = condp->right; | ||
1171 | if (!tomoyo_flush(head)) | ||
1172 | return false; | ||
1173 | condp++; | ||
1174 | head->r.cond_index++; | ||
1175 | tomoyo_set_space(head); | ||
1176 | switch (left) { | ||
1177 | case TOMOYO_ARGV_ENTRY: | ||
1178 | tomoyo_io_printf(head, | ||
1179 | "exec.argv[%lu]%s=\"", | ||
1180 | argv->index, argv-> | ||
1181 | is_not ? "!" : ""); | ||
1182 | tomoyo_set_string(head, | ||
1183 | argv->value->name); | ||
1184 | tomoyo_set_string(head, "\""); | ||
1185 | argv++; | ||
1186 | continue; | ||
1187 | case TOMOYO_ENVP_ENTRY: | ||
1188 | tomoyo_set_string(head, | ||
1189 | "exec.envp[\""); | ||
1190 | tomoyo_set_string(head, | ||
1191 | envp->name->name); | ||
1192 | tomoyo_io_printf(head, "\"]%s=", envp-> | ||
1193 | is_not ? "!" : ""); | ||
1194 | if (envp->value) { | ||
1195 | tomoyo_set_string(head, "\""); | ||
1196 | tomoyo_set_string(head, envp-> | ||
1197 | value->name); | ||
1198 | tomoyo_set_string(head, "\""); | ||
1199 | } else { | ||
1200 | tomoyo_set_string(head, | ||
1201 | "NULL"); | ||
1202 | } | ||
1203 | envp++; | ||
1204 | continue; | ||
1205 | case TOMOYO_NUMBER_UNION: | ||
1206 | tomoyo_print_number_union_nospace | ||
1207 | (head, numbers_p++); | ||
1208 | break; | ||
1209 | default: | ||
1210 | tomoyo_set_string(head, | ||
1211 | tomoyo_condition_keyword[left]); | ||
1212 | break; | ||
1213 | } | ||
1214 | tomoyo_set_string(head, match ? "=" : "!="); | ||
1215 | switch (right) { | ||
1216 | case TOMOYO_NAME_UNION: | ||
1217 | tomoyo_print_name_union_quoted | ||
1218 | (head, names_p++); | ||
1219 | break; | ||
1220 | case TOMOYO_NUMBER_UNION: | ||
1221 | tomoyo_print_number_union_nospace | ||
1222 | (head, numbers_p++); | ||
1223 | break; | ||
1224 | default: | ||
1225 | tomoyo_set_string(head, | ||
1226 | tomoyo_condition_keyword[right]); | ||
1227 | break; | ||
1228 | } | ||
1229 | } | ||
1230 | } | ||
1231 | head->r.cond_step++; | ||
1232 | /* fall through */ | ||
1233 | case 2: | ||
1234 | if (!tomoyo_flush(head)) | ||
911 | break; | 1235 | break; |
912 | return bit; | 1236 | head->r.cond_step++; |
1237 | /* fall through */ | ||
1238 | case 3: | ||
1239 | tomoyo_set_lf(head); | ||
1240 | return true; | ||
1241 | } | ||
1242 | return false; | ||
1243 | } | ||
1244 | |||
1245 | /** | ||
1246 | * tomoyo_set_group - Print "acl_group " header keyword and category name. | ||
1247 | * | ||
1248 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
1249 | * @category: Category name. | ||
1250 | * | ||
1251 | * Returns nothing. | ||
1252 | */ | ||
1253 | static void tomoyo_set_group(struct tomoyo_io_buffer *head, | ||
1254 | const char *category) | ||
1255 | { | ||
1256 | if (head->type == TOMOYO_EXCEPTIONPOLICY) { | ||
1257 | tomoyo_print_namespace(head); | ||
1258 | tomoyo_io_printf(head, "acl_group %u ", | ||
1259 | head->r.acl_group_index); | ||
1260 | } | ||
1261 | tomoyo_set_string(head, category); | ||
913 | } | 1262 | } |
914 | 1263 | ||
915 | /** | 1264 | /** |
@@ -924,63 +1273,96 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
924 | struct tomoyo_acl_info *acl) | 1273 | struct tomoyo_acl_info *acl) |
925 | { | 1274 | { |
926 | const u8 acl_type = acl->type; | 1275 | const u8 acl_type = acl->type; |
1276 | bool first = true; | ||
927 | u8 bit; | 1277 | u8 bit; |
928 | 1278 | ||
1279 | if (head->r.print_cond_part) | ||
1280 | goto print_cond_part; | ||
929 | if (acl->is_deleted) | 1281 | if (acl->is_deleted) |
930 | return true; | 1282 | return true; |
931 | next: | ||
932 | bit = head->r.bit; | ||
933 | if (!tomoyo_flush(head)) | 1283 | if (!tomoyo_flush(head)) |
934 | return false; | 1284 | return false; |
935 | else if (acl_type == TOMOYO_TYPE_PATH_ACL) { | 1285 | else if (acl_type == TOMOYO_TYPE_PATH_ACL) { |
936 | struct tomoyo_path_acl *ptr = | 1286 | struct tomoyo_path_acl *ptr = |
937 | container_of(acl, typeof(*ptr), head); | 1287 | container_of(acl, typeof(*ptr), head); |
938 | const u16 perm = ptr->perm; | 1288 | const u16 perm = ptr->perm; |
939 | for ( ; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { | 1289 | for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { |
940 | if (!(perm & (1 << bit))) | 1290 | if (!(perm & (1 << bit))) |
941 | continue; | 1291 | continue; |
942 | if (head->r.print_execute_only && | 1292 | if (head->r.print_transition_related_only && |
943 | bit != TOMOYO_TYPE_EXECUTE) | 1293 | bit != TOMOYO_TYPE_EXECUTE) |
944 | continue; | 1294 | continue; |
945 | /* Print "read/write" instead of "read" and "write". */ | 1295 | if (first) { |
946 | if ((bit == TOMOYO_TYPE_READ || | 1296 | tomoyo_set_group(head, "file "); |
947 | bit == TOMOYO_TYPE_WRITE) | 1297 | first = false; |
948 | && (perm & (1 << TOMOYO_TYPE_READ_WRITE))) | 1298 | } else { |
949 | continue; | 1299 | tomoyo_set_slash(head); |
950 | break; | 1300 | } |
1301 | tomoyo_set_string(head, tomoyo_path_keyword[bit]); | ||
951 | } | 1302 | } |
952 | if (bit >= TOMOYO_MAX_PATH_OPERATION) | 1303 | if (first) |
953 | goto done; | 1304 | return true; |
954 | tomoyo_io_printf(head, "allow_%s", tomoyo_path_keyword[bit]); | ||
955 | tomoyo_print_name_union(head, &ptr->name); | 1305 | tomoyo_print_name_union(head, &ptr->name); |
956 | } else if (head->r.print_execute_only) { | 1306 | } else if (head->r.print_transition_related_only) { |
957 | return true; | 1307 | return true; |
958 | } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { | 1308 | } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { |
959 | struct tomoyo_path2_acl *ptr = | 1309 | struct tomoyo_path2_acl *ptr = |
960 | container_of(acl, typeof(*ptr), head); | 1310 | container_of(acl, typeof(*ptr), head); |
961 | bit = tomoyo_fns(ptr->perm, bit); | 1311 | const u8 perm = ptr->perm; |
962 | if (bit >= TOMOYO_MAX_PATH2_OPERATION) | 1312 | for (bit = 0; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { |
963 | goto done; | 1313 | if (!(perm & (1 << bit))) |
964 | tomoyo_io_printf(head, "allow_%s", tomoyo_path2_keyword[bit]); | 1314 | continue; |
1315 | if (first) { | ||
1316 | tomoyo_set_group(head, "file "); | ||
1317 | first = false; | ||
1318 | } else { | ||
1319 | tomoyo_set_slash(head); | ||
1320 | } | ||
1321 | tomoyo_set_string(head, tomoyo_mac_keywords | ||
1322 | [tomoyo_pp2mac[bit]]); | ||
1323 | } | ||
1324 | if (first) | ||
1325 | return true; | ||
965 | tomoyo_print_name_union(head, &ptr->name1); | 1326 | tomoyo_print_name_union(head, &ptr->name1); |
966 | tomoyo_print_name_union(head, &ptr->name2); | 1327 | tomoyo_print_name_union(head, &ptr->name2); |
967 | } else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) { | 1328 | } else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) { |
968 | struct tomoyo_path_number_acl *ptr = | 1329 | struct tomoyo_path_number_acl *ptr = |
969 | container_of(acl, typeof(*ptr), head); | 1330 | container_of(acl, typeof(*ptr), head); |
970 | bit = tomoyo_fns(ptr->perm, bit); | 1331 | const u8 perm = ptr->perm; |
971 | if (bit >= TOMOYO_MAX_PATH_NUMBER_OPERATION) | 1332 | for (bit = 0; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION; bit++) { |
972 | goto done; | 1333 | if (!(perm & (1 << bit))) |
973 | tomoyo_io_printf(head, "allow_%s", | 1334 | continue; |
974 | tomoyo_path_number_keyword[bit]); | 1335 | if (first) { |
1336 | tomoyo_set_group(head, "file "); | ||
1337 | first = false; | ||
1338 | } else { | ||
1339 | tomoyo_set_slash(head); | ||
1340 | } | ||
1341 | tomoyo_set_string(head, tomoyo_mac_keywords | ||
1342 | [tomoyo_pn2mac[bit]]); | ||
1343 | } | ||
1344 | if (first) | ||
1345 | return true; | ||
975 | tomoyo_print_name_union(head, &ptr->name); | 1346 | tomoyo_print_name_union(head, &ptr->name); |
976 | tomoyo_print_number_union(head, &ptr->number); | 1347 | tomoyo_print_number_union(head, &ptr->number); |
977 | } else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) { | 1348 | } else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) { |
978 | struct tomoyo_mkdev_acl *ptr = | 1349 | struct tomoyo_mkdev_acl *ptr = |
979 | container_of(acl, typeof(*ptr), head); | 1350 | container_of(acl, typeof(*ptr), head); |
980 | bit = tomoyo_fns(ptr->perm, bit); | 1351 | const u8 perm = ptr->perm; |
981 | if (bit >= TOMOYO_MAX_MKDEV_OPERATION) | 1352 | for (bit = 0; bit < TOMOYO_MAX_MKDEV_OPERATION; bit++) { |
982 | goto done; | 1353 | if (!(perm & (1 << bit))) |
983 | tomoyo_io_printf(head, "allow_%s", tomoyo_mkdev_keyword[bit]); | 1354 | continue; |
1355 | if (first) { | ||
1356 | tomoyo_set_group(head, "file "); | ||
1357 | first = false; | ||
1358 | } else { | ||
1359 | tomoyo_set_slash(head); | ||
1360 | } | ||
1361 | tomoyo_set_string(head, tomoyo_mac_keywords | ||
1362 | [tomoyo_pnnn2mac[bit]]); | ||
1363 | } | ||
1364 | if (first) | ||
1365 | return true; | ||
984 | tomoyo_print_name_union(head, &ptr->name); | 1366 | tomoyo_print_name_union(head, &ptr->name); |
985 | tomoyo_print_number_union(head, &ptr->mode); | 1367 | tomoyo_print_number_union(head, &ptr->mode); |
986 | tomoyo_print_number_union(head, &ptr->major); | 1368 | tomoyo_print_number_union(head, &ptr->major); |
@@ -988,35 +1370,41 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
988 | } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { | 1370 | } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { |
989 | struct tomoyo_mount_acl *ptr = | 1371 | struct tomoyo_mount_acl *ptr = |
990 | container_of(acl, typeof(*ptr), head); | 1372 | container_of(acl, typeof(*ptr), head); |
991 | tomoyo_io_printf(head, "allow_mount"); | 1373 | tomoyo_set_group(head, "file mount"); |
992 | tomoyo_print_name_union(head, &ptr->dev_name); | 1374 | tomoyo_print_name_union(head, &ptr->dev_name); |
993 | tomoyo_print_name_union(head, &ptr->dir_name); | 1375 | tomoyo_print_name_union(head, &ptr->dir_name); |
994 | tomoyo_print_name_union(head, &ptr->fs_type); | 1376 | tomoyo_print_name_union(head, &ptr->fs_type); |
995 | tomoyo_print_number_union(head, &ptr->flags); | 1377 | tomoyo_print_number_union(head, &ptr->flags); |
996 | } | 1378 | } |
997 | head->r.bit = bit + 1; | 1379 | if (acl->cond) { |
998 | tomoyo_io_printf(head, "\n"); | 1380 | head->r.print_cond_part = true; |
999 | if (acl_type != TOMOYO_TYPE_MOUNT_ACL) | 1381 | head->r.cond_step = 0; |
1000 | goto next; | 1382 | if (!tomoyo_flush(head)) |
1001 | done: | 1383 | return false; |
1002 | head->r.bit = 0; | 1384 | print_cond_part: |
1385 | if (!tomoyo_print_condition(head, acl->cond)) | ||
1386 | return false; | ||
1387 | head->r.print_cond_part = false; | ||
1388 | } else { | ||
1389 | tomoyo_set_lf(head); | ||
1390 | } | ||
1003 | return true; | 1391 | return true; |
1004 | } | 1392 | } |
1005 | 1393 | ||
1006 | /** | 1394 | /** |
1007 | * tomoyo_read_domain2 - Read domain policy. | 1395 | * tomoyo_read_domain2 - Read domain policy. |
1008 | * | 1396 | * |
1009 | * @head: Pointer to "struct tomoyo_io_buffer". | 1397 | * @head: Pointer to "struct tomoyo_io_buffer". |
1010 | * @domain: Pointer to "struct tomoyo_domain_info". | 1398 | * @list: Pointer to "struct list_head". |
1011 | * | 1399 | * |
1012 | * Caller holds tomoyo_read_lock(). | 1400 | * Caller holds tomoyo_read_lock(). |
1013 | * | 1401 | * |
1014 | * Returns true on success, false otherwise. | 1402 | * Returns true on success, false otherwise. |
1015 | */ | 1403 | */ |
1016 | static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head, | 1404 | static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head, |
1017 | struct tomoyo_domain_info *domain) | 1405 | struct list_head *list) |
1018 | { | 1406 | { |
1019 | list_for_each_cookie(head->r.acl, &domain->acl_info_list) { | 1407 | list_for_each_cookie(head->r.acl, list) { |
1020 | struct tomoyo_acl_info *ptr = | 1408 | struct tomoyo_acl_info *ptr = |
1021 | list_entry(head->r.acl, typeof(*ptr), list); | 1409 | list_entry(head->r.acl, typeof(*ptr), list); |
1022 | if (!tomoyo_print_entry(head, ptr)) | 1410 | if (!tomoyo_print_entry(head, ptr)) |
@@ -1041,6 +1429,7 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head) | |||
1041 | struct tomoyo_domain_info *domain = | 1429 | struct tomoyo_domain_info *domain = |
1042 | list_entry(head->r.domain, typeof(*domain), list); | 1430 | list_entry(head->r.domain, typeof(*domain), list); |
1043 | switch (head->r.step) { | 1431 | switch (head->r.step) { |
1432 | u8 i; | ||
1044 | case 0: | 1433 | case 0: |
1045 | if (domain->is_deleted && | 1434 | if (domain->is_deleted && |
1046 | !head->r.print_this_domain_only) | 1435 | !head->r.print_this_domain_only) |
@@ -1048,22 +1437,18 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head) | |||
1048 | /* Print domainname and flags. */ | 1437 | /* Print domainname and flags. */ |
1049 | tomoyo_set_string(head, domain->domainname->name); | 1438 | tomoyo_set_string(head, domain->domainname->name); |
1050 | tomoyo_set_lf(head); | 1439 | tomoyo_set_lf(head); |
1051 | tomoyo_io_printf(head, | 1440 | tomoyo_io_printf(head, "use_profile %u\n", |
1052 | TOMOYO_KEYWORD_USE_PROFILE "%u\n", | ||
1053 | domain->profile); | 1441 | domain->profile); |
1054 | if (domain->quota_warned) | 1442 | tomoyo_io_printf(head, "use_group %u\n", |
1055 | tomoyo_set_string(head, "quota_exceeded\n"); | 1443 | domain->group); |
1056 | if (domain->transition_failed) | 1444 | for (i = 0; i < TOMOYO_MAX_DOMAIN_INFO_FLAGS; i++) |
1057 | tomoyo_set_string(head, "transition_failed\n"); | 1445 | if (domain->flags[i]) |
1058 | if (domain->ignore_global_allow_read) | 1446 | tomoyo_set_string(head, tomoyo_dif[i]); |
1059 | tomoyo_set_string(head, | ||
1060 | TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ | ||
1061 | "\n"); | ||
1062 | head->r.step++; | 1447 | head->r.step++; |
1063 | tomoyo_set_lf(head); | 1448 | tomoyo_set_lf(head); |
1064 | /* fall through */ | 1449 | /* fall through */ |
1065 | case 1: | 1450 | case 1: |
1066 | if (!tomoyo_read_domain2(head, domain)) | 1451 | if (!tomoyo_read_domain2(head, &domain->acl_info_list)) |
1067 | return; | 1452 | return; |
1068 | head->r.step++; | 1453 | head->r.step++; |
1069 | if (!tomoyo_set_lf(head)) | 1454 | if (!tomoyo_set_lf(head)) |
@@ -1080,73 +1465,6 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head) | |||
1080 | } | 1465 | } |
1081 | 1466 | ||
1082 | /** | 1467 | /** |
1083 | * tomoyo_write_domain_profile - Assign profile for specified domain. | ||
1084 | * | ||
1085 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
1086 | * | ||
1087 | * Returns 0 on success, -EINVAL otherwise. | ||
1088 | * | ||
1089 | * This is equivalent to doing | ||
1090 | * | ||
1091 | * ( echo "select " $domainname; echo "use_profile " $profile ) | | ||
1092 | * /usr/sbin/tomoyo-loadpolicy -d | ||
1093 | * | ||
1094 | * Caller holds tomoyo_read_lock(). | ||
1095 | */ | ||
1096 | static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) | ||
1097 | { | ||
1098 | char *data = head->write_buf; | ||
1099 | char *cp = strchr(data, ' '); | ||
1100 | struct tomoyo_domain_info *domain; | ||
1101 | unsigned long profile; | ||
1102 | |||
1103 | if (!cp) | ||
1104 | return -EINVAL; | ||
1105 | *cp = '\0'; | ||
1106 | domain = tomoyo_find_domain(cp + 1); | ||
1107 | if (strict_strtoul(data, 10, &profile)) | ||
1108 | return -EINVAL; | ||
1109 | if (domain && profile < TOMOYO_MAX_PROFILES | ||
1110 | && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded)) | ||
1111 | domain->profile = (u8) profile; | ||
1112 | return 0; | ||
1113 | } | ||
1114 | |||
1115 | /** | ||
1116 | * tomoyo_read_domain_profile - Read only domainname and profile. | ||
1117 | * | ||
1118 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
1119 | * | ||
1120 | * Returns list of profile number and domainname pairs. | ||
1121 | * | ||
1122 | * This is equivalent to doing | ||
1123 | * | ||
1124 | * grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy | | ||
1125 | * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" ) | ||
1126 | * domainname = $0; } else if ( $1 == "use_profile" ) { | ||
1127 | * print $2 " " domainname; domainname = ""; } } ; ' | ||
1128 | * | ||
1129 | * Caller holds tomoyo_read_lock(). | ||
1130 | */ | ||
1131 | static void tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) | ||
1132 | { | ||
1133 | if (head->r.eof) | ||
1134 | return; | ||
1135 | list_for_each_cookie(head->r.domain, &tomoyo_domain_list) { | ||
1136 | struct tomoyo_domain_info *domain = | ||
1137 | list_entry(head->r.domain, typeof(*domain), list); | ||
1138 | if (domain->is_deleted) | ||
1139 | continue; | ||
1140 | if (!tomoyo_flush(head)) | ||
1141 | return; | ||
1142 | tomoyo_io_printf(head, "%u ", domain->profile); | ||
1143 | tomoyo_set_string(head, domain->domainname->name); | ||
1144 | tomoyo_set_lf(head); | ||
1145 | } | ||
1146 | head->r.eof = true; | ||
1147 | } | ||
1148 | |||
1149 | /** | ||
1150 | * tomoyo_write_pid: Specify PID to obtain domainname. | 1468 | * tomoyo_write_pid: Specify PID to obtain domainname. |
1151 | * | 1469 | * |
1152 | * @head: Pointer to "struct tomoyo_io_buffer". | 1470 | * @head: Pointer to "struct tomoyo_io_buffer". |
@@ -1204,18 +1522,20 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head) | |||
1204 | tomoyo_set_string(head, domain->domainname->name); | 1522 | tomoyo_set_string(head, domain->domainname->name); |
1205 | } | 1523 | } |
1206 | 1524 | ||
1525 | /* String table for domain transition control keywords. */ | ||
1207 | static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { | 1526 | static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { |
1208 | [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] | 1527 | [TOMOYO_TRANSITION_CONTROL_NO_RESET] = "no_reset_domain ", |
1209 | = TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN, | 1528 | [TOMOYO_TRANSITION_CONTROL_RESET] = "reset_domain ", |
1210 | [TOMOYO_TRANSITION_CONTROL_INITIALIZE] | 1529 | [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ", |
1211 | = TOMOYO_KEYWORD_INITIALIZE_DOMAIN, | 1530 | [TOMOYO_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ", |
1212 | [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = TOMOYO_KEYWORD_NO_KEEP_DOMAIN, | 1531 | [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ", |
1213 | [TOMOYO_TRANSITION_CONTROL_KEEP] = TOMOYO_KEYWORD_KEEP_DOMAIN | 1532 | [TOMOYO_TRANSITION_CONTROL_KEEP] = "keep_domain ", |
1214 | }; | 1533 | }; |
1215 | 1534 | ||
1535 | /* String table for grouping keywords. */ | ||
1216 | static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { | 1536 | static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { |
1217 | [TOMOYO_PATH_GROUP] = TOMOYO_KEYWORD_PATH_GROUP, | 1537 | [TOMOYO_PATH_GROUP] = "path_group ", |
1218 | [TOMOYO_NUMBER_GROUP] = TOMOYO_KEYWORD_NUMBER_GROUP | 1538 | [TOMOYO_NUMBER_GROUP] = "number_group ", |
1219 | }; | 1539 | }; |
1220 | 1540 | ||
1221 | /** | 1541 | /** |
@@ -1229,29 +1549,30 @@ static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { | |||
1229 | */ | 1549 | */ |
1230 | static int tomoyo_write_exception(struct tomoyo_io_buffer *head) | 1550 | static int tomoyo_write_exception(struct tomoyo_io_buffer *head) |
1231 | { | 1551 | { |
1232 | char *data = head->write_buf; | 1552 | const bool is_delete = head->w.is_delete; |
1233 | bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE); | 1553 | struct tomoyo_acl_param param = { |
1234 | u8 i; | 1554 | .ns = head->w.ns, |
1235 | static const struct { | 1555 | .is_delete = is_delete, |
1236 | const char *keyword; | 1556 | .data = head->write_buf, |
1237 | int (*write) (char *, const bool); | ||
1238 | } tomoyo_callback[4] = { | ||
1239 | { TOMOYO_KEYWORD_AGGREGATOR, tomoyo_write_aggregator }, | ||
1240 | { TOMOYO_KEYWORD_FILE_PATTERN, tomoyo_write_pattern }, | ||
1241 | { TOMOYO_KEYWORD_DENY_REWRITE, tomoyo_write_no_rewrite }, | ||
1242 | { TOMOYO_KEYWORD_ALLOW_READ, tomoyo_write_globally_readable }, | ||
1243 | }; | 1557 | }; |
1244 | 1558 | u8 i; | |
1559 | if (tomoyo_str_starts(¶m.data, "aggregator ")) | ||
1560 | return tomoyo_write_aggregator(¶m); | ||
1245 | for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) | 1561 | for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) |
1246 | if (tomoyo_str_starts(&data, tomoyo_transition_type[i])) | 1562 | if (tomoyo_str_starts(¶m.data, tomoyo_transition_type[i])) |
1247 | return tomoyo_write_transition_control(data, is_delete, | 1563 | return tomoyo_write_transition_control(¶m, i); |
1248 | i); | ||
1249 | for (i = 0; i < 4; i++) | ||
1250 | if (tomoyo_str_starts(&data, tomoyo_callback[i].keyword)) | ||
1251 | return tomoyo_callback[i].write(data, is_delete); | ||
1252 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) | 1564 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) |
1253 | if (tomoyo_str_starts(&data, tomoyo_group_name[i])) | 1565 | if (tomoyo_str_starts(¶m.data, tomoyo_group_name[i])) |
1254 | return tomoyo_write_group(data, is_delete, i); | 1566 | return tomoyo_write_group(¶m, i); |
1567 | if (tomoyo_str_starts(¶m.data, "acl_group ")) { | ||
1568 | unsigned int group; | ||
1569 | char *data; | ||
1570 | group = simple_strtoul(param.data, &data, 10); | ||
1571 | if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ') | ||
1572 | return tomoyo_write_domain2 | ||
1573 | (head->w.ns, &head->w.ns->acl_group[group], | ||
1574 | data, is_delete); | ||
1575 | } | ||
1255 | return -EINVAL; | 1576 | return -EINVAL; |
1256 | } | 1577 | } |
1257 | 1578 | ||
@@ -1267,9 +1588,12 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) | |||
1267 | */ | 1588 | */ |
1268 | static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | 1589 | static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) |
1269 | { | 1590 | { |
1270 | list_for_each_cookie(head->r.group, &tomoyo_group_list[idx]) { | 1591 | struct tomoyo_policy_namespace *ns = |
1592 | container_of(head->r.ns, typeof(*ns), namespace_list); | ||
1593 | struct list_head *list = &ns->group_list[idx]; | ||
1594 | list_for_each_cookie(head->r.group, list) { | ||
1271 | struct tomoyo_group *group = | 1595 | struct tomoyo_group *group = |
1272 | list_entry(head->r.group, typeof(*group), list); | 1596 | list_entry(head->r.group, typeof(*group), head.list); |
1273 | list_for_each_cookie(head->r.acl, &group->member_list) { | 1597 | list_for_each_cookie(head->r.acl, &group->member_list) { |
1274 | struct tomoyo_acl_head *ptr = | 1598 | struct tomoyo_acl_head *ptr = |
1275 | list_entry(head->r.acl, typeof(*ptr), list); | 1599 | list_entry(head->r.acl, typeof(*ptr), list); |
@@ -1277,6 +1601,7 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | |||
1277 | continue; | 1601 | continue; |
1278 | if (!tomoyo_flush(head)) | 1602 | if (!tomoyo_flush(head)) |
1279 | return false; | 1603 | return false; |
1604 | tomoyo_print_namespace(head); | ||
1280 | tomoyo_set_string(head, tomoyo_group_name[idx]); | 1605 | tomoyo_set_string(head, tomoyo_group_name[idx]); |
1281 | tomoyo_set_string(head, group->group_name->name); | 1606 | tomoyo_set_string(head, group->group_name->name); |
1282 | if (idx == TOMOYO_PATH_GROUP) { | 1607 | if (idx == TOMOYO_PATH_GROUP) { |
@@ -1310,7 +1635,10 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | |||
1310 | */ | 1635 | */ |
1311 | static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | 1636 | static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) |
1312 | { | 1637 | { |
1313 | list_for_each_cookie(head->r.acl, &tomoyo_policy_list[idx]) { | 1638 | struct tomoyo_policy_namespace *ns = |
1639 | container_of(head->r.ns, typeof(*ns), namespace_list); | ||
1640 | struct list_head *list = &ns->policy_list[idx]; | ||
1641 | list_for_each_cookie(head->r.acl, list) { | ||
1314 | struct tomoyo_acl_head *acl = | 1642 | struct tomoyo_acl_head *acl = |
1315 | container_of(head->r.acl, typeof(*acl), list); | 1643 | container_of(head->r.acl, typeof(*acl), list); |
1316 | if (acl->is_deleted) | 1644 | if (acl->is_deleted) |
@@ -1322,35 +1650,23 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | |||
1322 | { | 1650 | { |
1323 | struct tomoyo_transition_control *ptr = | 1651 | struct tomoyo_transition_control *ptr = |
1324 | container_of(acl, typeof(*ptr), head); | 1652 | container_of(acl, typeof(*ptr), head); |
1325 | tomoyo_set_string(head, | 1653 | tomoyo_print_namespace(head); |
1326 | tomoyo_transition_type | 1654 | tomoyo_set_string(head, tomoyo_transition_type |
1327 | [ptr->type]); | 1655 | [ptr->type]); |
1328 | if (ptr->program) | 1656 | tomoyo_set_string(head, ptr->program ? |
1329 | tomoyo_set_string(head, | 1657 | ptr->program->name : "any"); |
1330 | ptr->program->name); | 1658 | tomoyo_set_string(head, " from "); |
1331 | if (ptr->program && ptr->domainname) | 1659 | tomoyo_set_string(head, ptr->domainname ? |
1332 | tomoyo_set_string(head, " from "); | 1660 | ptr->domainname->name : |
1333 | if (ptr->domainname) | 1661 | "any"); |
1334 | tomoyo_set_string(head, | ||
1335 | ptr->domainname-> | ||
1336 | name); | ||
1337 | } | ||
1338 | break; | ||
1339 | case TOMOYO_ID_GLOBALLY_READABLE: | ||
1340 | { | ||
1341 | struct tomoyo_readable_file *ptr = | ||
1342 | container_of(acl, typeof(*ptr), head); | ||
1343 | tomoyo_set_string(head, | ||
1344 | TOMOYO_KEYWORD_ALLOW_READ); | ||
1345 | tomoyo_set_string(head, ptr->filename->name); | ||
1346 | } | 1662 | } |
1347 | break; | 1663 | break; |
1348 | case TOMOYO_ID_AGGREGATOR: | 1664 | case TOMOYO_ID_AGGREGATOR: |
1349 | { | 1665 | { |
1350 | struct tomoyo_aggregator *ptr = | 1666 | struct tomoyo_aggregator *ptr = |
1351 | container_of(acl, typeof(*ptr), head); | 1667 | container_of(acl, typeof(*ptr), head); |
1352 | tomoyo_set_string(head, | 1668 | tomoyo_print_namespace(head); |
1353 | TOMOYO_KEYWORD_AGGREGATOR); | 1669 | tomoyo_set_string(head, "aggregator "); |
1354 | tomoyo_set_string(head, | 1670 | tomoyo_set_string(head, |
1355 | ptr->original_name->name); | 1671 | ptr->original_name->name); |
1356 | tomoyo_set_space(head); | 1672 | tomoyo_set_space(head); |
@@ -1358,24 +1674,6 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | |||
1358 | ptr->aggregated_name->name); | 1674 | ptr->aggregated_name->name); |
1359 | } | 1675 | } |
1360 | break; | 1676 | break; |
1361 | case TOMOYO_ID_PATTERN: | ||
1362 | { | ||
1363 | struct tomoyo_no_pattern *ptr = | ||
1364 | container_of(acl, typeof(*ptr), head); | ||
1365 | tomoyo_set_string(head, | ||
1366 | TOMOYO_KEYWORD_FILE_PATTERN); | ||
1367 | tomoyo_set_string(head, ptr->pattern->name); | ||
1368 | } | ||
1369 | break; | ||
1370 | case TOMOYO_ID_NO_REWRITE: | ||
1371 | { | ||
1372 | struct tomoyo_no_rewrite *ptr = | ||
1373 | container_of(acl, typeof(*ptr), head); | ||
1374 | tomoyo_set_string(head, | ||
1375 | TOMOYO_KEYWORD_DENY_REWRITE); | ||
1376 | tomoyo_set_string(head, ptr->pattern->name); | ||
1377 | } | ||
1378 | break; | ||
1379 | default: | 1677 | default: |
1380 | continue; | 1678 | continue; |
1381 | } | 1679 | } |
@@ -1394,6 +1692,8 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | |||
1394 | */ | 1692 | */ |
1395 | static void tomoyo_read_exception(struct tomoyo_io_buffer *head) | 1693 | static void tomoyo_read_exception(struct tomoyo_io_buffer *head) |
1396 | { | 1694 | { |
1695 | struct tomoyo_policy_namespace *ns = | ||
1696 | container_of(head->r.ns, typeof(*ns), namespace_list); | ||
1397 | if (head->r.eof) | 1697 | if (head->r.eof) |
1398 | return; | 1698 | return; |
1399 | while (head->r.step < TOMOYO_MAX_POLICY && | 1699 | while (head->r.step < TOMOYO_MAX_POLICY && |
@@ -1406,95 +1706,40 @@ static void tomoyo_read_exception(struct tomoyo_io_buffer *head) | |||
1406 | head->r.step++; | 1706 | head->r.step++; |
1407 | if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP) | 1707 | if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP) |
1408 | return; | 1708 | return; |
1709 | while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP | ||
1710 | + TOMOYO_MAX_ACL_GROUPS) { | ||
1711 | head->r.acl_group_index = head->r.step - TOMOYO_MAX_POLICY | ||
1712 | - TOMOYO_MAX_GROUP; | ||
1713 | if (!tomoyo_read_domain2(head, &ns->acl_group | ||
1714 | [head->r.acl_group_index])) | ||
1715 | return; | ||
1716 | head->r.step++; | ||
1717 | } | ||
1409 | head->r.eof = true; | 1718 | head->r.eof = true; |
1410 | } | 1719 | } |
1411 | 1720 | ||
1412 | /** | 1721 | /* Wait queue for kernel -> userspace notification. */ |
1413 | * tomoyo_print_header - Get header line of audit log. | ||
1414 | * | ||
1415 | * @r: Pointer to "struct tomoyo_request_info". | ||
1416 | * | ||
1417 | * Returns string representation. | ||
1418 | * | ||
1419 | * This function uses kmalloc(), so caller must kfree() if this function | ||
1420 | * didn't return NULL. | ||
1421 | */ | ||
1422 | static char *tomoyo_print_header(struct tomoyo_request_info *r) | ||
1423 | { | ||
1424 | struct timeval tv; | ||
1425 | const pid_t gpid = task_pid_nr(current); | ||
1426 | static const int tomoyo_buffer_len = 4096; | ||
1427 | char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); | ||
1428 | pid_t ppid; | ||
1429 | if (!buffer) | ||
1430 | return NULL; | ||
1431 | do_gettimeofday(&tv); | ||
1432 | rcu_read_lock(); | ||
1433 | ppid = task_tgid_vnr(current->real_parent); | ||
1434 | rcu_read_unlock(); | ||
1435 | snprintf(buffer, tomoyo_buffer_len - 1, | ||
1436 | "#timestamp=%lu profile=%u mode=%s (global-pid=%u)" | ||
1437 | " task={ pid=%u ppid=%u uid=%u gid=%u euid=%u" | ||
1438 | " egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }", | ||
1439 | tv.tv_sec, r->profile, tomoyo_mode[r->mode], gpid, | ||
1440 | task_tgid_vnr(current), ppid, | ||
1441 | current_uid(), current_gid(), current_euid(), | ||
1442 | current_egid(), current_suid(), current_sgid(), | ||
1443 | current_fsuid(), current_fsgid()); | ||
1444 | return buffer; | ||
1445 | } | ||
1446 | |||
1447 | /** | ||
1448 | * tomoyo_init_audit_log - Allocate buffer for audit logs. | ||
1449 | * | ||
1450 | * @len: Required size. | ||
1451 | * @r: Pointer to "struct tomoyo_request_info". | ||
1452 | * | ||
1453 | * Returns pointer to allocated memory. | ||
1454 | * | ||
1455 | * The @len is updated to add the header lines' size on success. | ||
1456 | * | ||
1457 | * This function uses kzalloc(), so caller must kfree() if this function | ||
1458 | * didn't return NULL. | ||
1459 | */ | ||
1460 | static char *tomoyo_init_audit_log(int *len, struct tomoyo_request_info *r) | ||
1461 | { | ||
1462 | char *buf = NULL; | ||
1463 | const char *header; | ||
1464 | const char *domainname; | ||
1465 | if (!r->domain) | ||
1466 | r->domain = tomoyo_domain(); | ||
1467 | domainname = r->domain->domainname->name; | ||
1468 | header = tomoyo_print_header(r); | ||
1469 | if (!header) | ||
1470 | return NULL; | ||
1471 | *len += strlen(domainname) + strlen(header) + 10; | ||
1472 | buf = kzalloc(*len, GFP_NOFS); | ||
1473 | if (buf) | ||
1474 | snprintf(buf, (*len) - 1, "%s\n%s\n", header, domainname); | ||
1475 | kfree(header); | ||
1476 | return buf; | ||
1477 | } | ||
1478 | |||
1479 | /* Wait queue for tomoyo_query_list. */ | ||
1480 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait); | 1722 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait); |
1481 | 1723 | /* Wait queue for userspace -> kernel notification. */ | |
1482 | /* Lock for manipulating tomoyo_query_list. */ | 1724 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_answer_wait); |
1483 | static DEFINE_SPINLOCK(tomoyo_query_list_lock); | ||
1484 | 1725 | ||
1485 | /* Structure for query. */ | 1726 | /* Structure for query. */ |
1486 | struct tomoyo_query { | 1727 | struct tomoyo_query { |
1487 | struct list_head list; | 1728 | struct list_head list; |
1488 | char *query; | 1729 | char *query; |
1489 | int query_len; | 1730 | size_t query_len; |
1490 | unsigned int serial; | 1731 | unsigned int serial; |
1491 | int timer; | 1732 | u8 timer; |
1492 | int answer; | 1733 | u8 answer; |
1734 | u8 retry; | ||
1493 | }; | 1735 | }; |
1494 | 1736 | ||
1495 | /* The list for "struct tomoyo_query". */ | 1737 | /* The list for "struct tomoyo_query". */ |
1496 | static LIST_HEAD(tomoyo_query_list); | 1738 | static LIST_HEAD(tomoyo_query_list); |
1497 | 1739 | ||
1740 | /* Lock for manipulating tomoyo_query_list. */ | ||
1741 | static DEFINE_SPINLOCK(tomoyo_query_list_lock); | ||
1742 | |||
1498 | /* | 1743 | /* |
1499 | * Number of "struct file" referring /sys/kernel/security/tomoyo/query | 1744 | * Number of "struct file" referring /sys/kernel/security/tomoyo/query |
1500 | * interface. | 1745 | * interface. |
@@ -1502,10 +1747,82 @@ static LIST_HEAD(tomoyo_query_list); | |||
1502 | static atomic_t tomoyo_query_observers = ATOMIC_INIT(0); | 1747 | static atomic_t tomoyo_query_observers = ATOMIC_INIT(0); |
1503 | 1748 | ||
1504 | /** | 1749 | /** |
1750 | * tomoyo_truncate - Truncate a line. | ||
1751 | * | ||
1752 | * @str: String to truncate. | ||
1753 | * | ||
1754 | * Returns length of truncated @str. | ||
1755 | */ | ||
1756 | static int tomoyo_truncate(char *str) | ||
1757 | { | ||
1758 | char *start = str; | ||
1759 | while (*(unsigned char *) str > (unsigned char) ' ') | ||
1760 | str++; | ||
1761 | *str = '\0'; | ||
1762 | return strlen(start) + 1; | ||
1763 | } | ||
1764 | |||
1765 | /** | ||
1766 | * tomoyo_add_entry - Add an ACL to current thread's domain. Used by learning mode. | ||
1767 | * | ||
1768 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1769 | * @header: Lines containing ACL. | ||
1770 | * | ||
1771 | * Returns nothing. | ||
1772 | */ | ||
1773 | static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header) | ||
1774 | { | ||
1775 | char *buffer; | ||
1776 | char *realpath = NULL; | ||
1777 | char *argv0 = NULL; | ||
1778 | char *symlink = NULL; | ||
1779 | char *cp = strchr(header, '\n'); | ||
1780 | int len; | ||
1781 | if (!cp) | ||
1782 | return; | ||
1783 | cp = strchr(cp + 1, '\n'); | ||
1784 | if (!cp) | ||
1785 | return; | ||
1786 | *cp++ = '\0'; | ||
1787 | len = strlen(cp) + 1; | ||
1788 | /* strstr() will return NULL if ordering is wrong. */ | ||
1789 | if (*cp == 'f') { | ||
1790 | argv0 = strstr(header, " argv[]={ \""); | ||
1791 | if (argv0) { | ||
1792 | argv0 += 10; | ||
1793 | len += tomoyo_truncate(argv0) + 14; | ||
1794 | } | ||
1795 | realpath = strstr(header, " exec={ realpath=\""); | ||
1796 | if (realpath) { | ||
1797 | realpath += 8; | ||
1798 | len += tomoyo_truncate(realpath) + 6; | ||
1799 | } | ||
1800 | symlink = strstr(header, " symlink.target=\""); | ||
1801 | if (symlink) | ||
1802 | len += tomoyo_truncate(symlink + 1) + 1; | ||
1803 | } | ||
1804 | buffer = kmalloc(len, GFP_NOFS); | ||
1805 | if (!buffer) | ||
1806 | return; | ||
1807 | snprintf(buffer, len - 1, "%s", cp); | ||
1808 | if (realpath) | ||
1809 | tomoyo_addprintf(buffer, len, " exec.%s", realpath); | ||
1810 | if (argv0) | ||
1811 | tomoyo_addprintf(buffer, len, " exec.argv[0]=%s", argv0); | ||
1812 | if (symlink) | ||
1813 | tomoyo_addprintf(buffer, len, "%s", symlink); | ||
1814 | tomoyo_normalize_line(buffer); | ||
1815 | if (!tomoyo_write_domain2(domain->ns, &domain->acl_info_list, buffer, | ||
1816 | false)) | ||
1817 | tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); | ||
1818 | kfree(buffer); | ||
1819 | } | ||
1820 | |||
1821 | /** | ||
1505 | * tomoyo_supervisor - Ask for the supervisor's decision. | 1822 | * tomoyo_supervisor - Ask for the supervisor's decision. |
1506 | * | 1823 | * |
1507 | * @r: Pointer to "struct tomoyo_request_info". | 1824 | * @r: Pointer to "struct tomoyo_request_info". |
1508 | * @fmt: The printf()'s format string, followed by parameters. | 1825 | * @fmt: The printf()'s format string, followed by parameters. |
1509 | * | 1826 | * |
1510 | * Returns 0 if the supervisor decided to permit the access request which | 1827 | * Returns 0 if the supervisor decided to permit the access request which |
1511 | * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the | 1828 | * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the |
@@ -1515,88 +1832,79 @@ static atomic_t tomoyo_query_observers = ATOMIC_INIT(0); | |||
1515 | int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) | 1832 | int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) |
1516 | { | 1833 | { |
1517 | va_list args; | 1834 | va_list args; |
1518 | int error = -EPERM; | 1835 | int error; |
1519 | int pos; | ||
1520 | int len; | 1836 | int len; |
1521 | static unsigned int tomoyo_serial; | 1837 | static unsigned int tomoyo_serial; |
1522 | struct tomoyo_query *entry = NULL; | 1838 | struct tomoyo_query entry = { }; |
1523 | bool quota_exceeded = false; | 1839 | bool quota_exceeded = false; |
1524 | char *header; | 1840 | va_start(args, fmt); |
1841 | len = vsnprintf((char *) &len, 1, fmt, args) + 1; | ||
1842 | va_end(args); | ||
1843 | /* Write /sys/kernel/security/tomoyo/audit. */ | ||
1844 | va_start(args, fmt); | ||
1845 | tomoyo_write_log2(r, len, fmt, args); | ||
1846 | va_end(args); | ||
1847 | /* Nothing more to do if granted. */ | ||
1848 | if (r->granted) | ||
1849 | return 0; | ||
1850 | if (r->mode) | ||
1851 | tomoyo_update_stat(r->mode); | ||
1525 | switch (r->mode) { | 1852 | switch (r->mode) { |
1526 | char *buffer; | 1853 | case TOMOYO_CONFIG_ENFORCING: |
1854 | error = -EPERM; | ||
1855 | if (atomic_read(&tomoyo_query_observers)) | ||
1856 | break; | ||
1857 | goto out; | ||
1527 | case TOMOYO_CONFIG_LEARNING: | 1858 | case TOMOYO_CONFIG_LEARNING: |
1528 | if (!tomoyo_domain_quota_is_ok(r)) | 1859 | error = 0; |
1529 | return 0; | 1860 | /* Check max_learning_entry parameter. */ |
1530 | va_start(args, fmt); | 1861 | if (tomoyo_domain_quota_is_ok(r)) |
1531 | len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 4; | 1862 | break; |
1532 | va_end(args); | ||
1533 | buffer = kmalloc(len, GFP_NOFS); | ||
1534 | if (!buffer) | ||
1535 | return 0; | ||
1536 | va_start(args, fmt); | ||
1537 | vsnprintf(buffer, len - 1, fmt, args); | ||
1538 | va_end(args); | ||
1539 | tomoyo_normalize_line(buffer); | ||
1540 | tomoyo_write_domain2(buffer, r->domain, false); | ||
1541 | kfree(buffer); | ||
1542 | /* fall through */ | 1863 | /* fall through */ |
1543 | case TOMOYO_CONFIG_PERMISSIVE: | 1864 | default: |
1544 | return 0; | 1865 | return 0; |
1545 | } | 1866 | } |
1546 | if (!r->domain) | 1867 | /* Get message. */ |
1547 | r->domain = tomoyo_domain(); | ||
1548 | if (!atomic_read(&tomoyo_query_observers)) | ||
1549 | return -EPERM; | ||
1550 | va_start(args, fmt); | 1868 | va_start(args, fmt); |
1551 | len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32; | 1869 | entry.query = tomoyo_init_log(r, len, fmt, args); |
1552 | va_end(args); | 1870 | va_end(args); |
1553 | header = tomoyo_init_audit_log(&len, r); | 1871 | if (!entry.query) |
1554 | if (!header) | ||
1555 | goto out; | 1872 | goto out; |
1556 | entry = kzalloc(sizeof(*entry), GFP_NOFS); | 1873 | entry.query_len = strlen(entry.query) + 1; |
1557 | if (!entry) | 1874 | if (!error) { |
1875 | tomoyo_add_entry(r->domain, entry.query); | ||
1558 | goto out; | 1876 | goto out; |
1559 | entry->query = kzalloc(len, GFP_NOFS); | 1877 | } |
1560 | if (!entry->query) | 1878 | len = tomoyo_round2(entry.query_len); |
1561 | goto out; | ||
1562 | len = ksize(entry->query); | ||
1563 | spin_lock(&tomoyo_query_list_lock); | 1879 | spin_lock(&tomoyo_query_list_lock); |
1564 | if (tomoyo_quota_for_query && tomoyo_query_memory_size + len + | 1880 | if (tomoyo_memory_quota[TOMOYO_MEMORY_QUERY] && |
1565 | sizeof(*entry) >= tomoyo_quota_for_query) { | 1881 | tomoyo_memory_used[TOMOYO_MEMORY_QUERY] + len |
1882 | >= tomoyo_memory_quota[TOMOYO_MEMORY_QUERY]) { | ||
1566 | quota_exceeded = true; | 1883 | quota_exceeded = true; |
1567 | } else { | 1884 | } else { |
1568 | tomoyo_query_memory_size += len + sizeof(*entry); | 1885 | entry.serial = tomoyo_serial++; |
1569 | entry->serial = tomoyo_serial++; | 1886 | entry.retry = r->retry; |
1887 | tomoyo_memory_used[TOMOYO_MEMORY_QUERY] += len; | ||
1888 | list_add_tail(&entry.list, &tomoyo_query_list); | ||
1570 | } | 1889 | } |
1571 | spin_unlock(&tomoyo_query_list_lock); | 1890 | spin_unlock(&tomoyo_query_list_lock); |
1572 | if (quota_exceeded) | 1891 | if (quota_exceeded) |
1573 | goto out; | 1892 | goto out; |
1574 | pos = snprintf(entry->query, len - 1, "Q%u-%hu\n%s", | ||
1575 | entry->serial, r->retry, header); | ||
1576 | kfree(header); | ||
1577 | header = NULL; | ||
1578 | va_start(args, fmt); | ||
1579 | vsnprintf(entry->query + pos, len - 1 - pos, fmt, args); | ||
1580 | entry->query_len = strlen(entry->query) + 1; | ||
1581 | va_end(args); | ||
1582 | spin_lock(&tomoyo_query_list_lock); | ||
1583 | list_add_tail(&entry->list, &tomoyo_query_list); | ||
1584 | spin_unlock(&tomoyo_query_list_lock); | ||
1585 | /* Give 10 seconds for supervisor's opinion. */ | 1893 | /* Give 10 seconds for supervisor's opinion. */ |
1586 | for (entry->timer = 0; | 1894 | while (entry.timer < 10) { |
1587 | atomic_read(&tomoyo_query_observers) && entry->timer < 100; | 1895 | wake_up_all(&tomoyo_query_wait); |
1588 | entry->timer++) { | 1896 | if (wait_event_interruptible_timeout |
1589 | wake_up(&tomoyo_query_wait); | 1897 | (tomoyo_answer_wait, entry.answer || |
1590 | set_current_state(TASK_INTERRUPTIBLE); | 1898 | !atomic_read(&tomoyo_query_observers), HZ)) |
1591 | schedule_timeout(HZ / 10); | ||
1592 | if (entry->answer) | ||
1593 | break; | 1899 | break; |
1900 | else | ||
1901 | entry.timer++; | ||
1594 | } | 1902 | } |
1595 | spin_lock(&tomoyo_query_list_lock); | 1903 | spin_lock(&tomoyo_query_list_lock); |
1596 | list_del(&entry->list); | 1904 | list_del(&entry.list); |
1597 | tomoyo_query_memory_size -= len + sizeof(*entry); | 1905 | tomoyo_memory_used[TOMOYO_MEMORY_QUERY] -= len; |
1598 | spin_unlock(&tomoyo_query_list_lock); | 1906 | spin_unlock(&tomoyo_query_list_lock); |
1599 | switch (entry->answer) { | 1907 | switch (entry.answer) { |
1600 | case 3: /* Asked to retry by administrator. */ | 1908 | case 3: /* Asked to retry by administrator. */ |
1601 | error = TOMOYO_RETRY_REQUEST; | 1909 | error = TOMOYO_RETRY_REQUEST; |
1602 | r->retry++; | 1910 | r->retry++; |
@@ -1605,18 +1913,12 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) | |||
1605 | /* Granted by administrator. */ | 1913 | /* Granted by administrator. */ |
1606 | error = 0; | 1914 | error = 0; |
1607 | break; | 1915 | break; |
1608 | case 0: | ||
1609 | /* Timed out. */ | ||
1610 | break; | ||
1611 | default: | 1916 | default: |
1612 | /* Rejected by administrator. */ | 1917 | /* Timed out or rejected by administrator. */ |
1613 | break; | 1918 | break; |
1614 | } | 1919 | } |
1615 | out: | 1920 | out: |
1616 | if (entry) | 1921 | kfree(entry.query); |
1617 | kfree(entry->query); | ||
1618 | kfree(entry); | ||
1619 | kfree(header); | ||
1620 | return error; | 1922 | return error; |
1621 | } | 1923 | } |
1622 | 1924 | ||
@@ -1663,8 +1965,8 @@ static int tomoyo_poll_query(struct file *file, poll_table *wait) | |||
1663 | static void tomoyo_read_query(struct tomoyo_io_buffer *head) | 1965 | static void tomoyo_read_query(struct tomoyo_io_buffer *head) |
1664 | { | 1966 | { |
1665 | struct list_head *tmp; | 1967 | struct list_head *tmp; |
1666 | int pos = 0; | 1968 | unsigned int pos = 0; |
1667 | int len = 0; | 1969 | size_t len = 0; |
1668 | char *buf; | 1970 | char *buf; |
1669 | if (head->r.w_pos) | 1971 | if (head->r.w_pos) |
1670 | return; | 1972 | return; |
@@ -1687,7 +1989,7 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head) | |||
1687 | head->r.query_index = 0; | 1989 | head->r.query_index = 0; |
1688 | return; | 1990 | return; |
1689 | } | 1991 | } |
1690 | buf = kzalloc(len, GFP_NOFS); | 1992 | buf = kzalloc(len + 32, GFP_NOFS); |
1691 | if (!buf) | 1993 | if (!buf) |
1692 | return; | 1994 | return; |
1693 | pos = 0; | 1995 | pos = 0; |
@@ -1703,7 +2005,8 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head) | |||
1703 | * can change, but I don't care. | 2005 | * can change, but I don't care. |
1704 | */ | 2006 | */ |
1705 | if (len == ptr->query_len) | 2007 | if (len == ptr->query_len) |
1706 | memmove(buf, ptr->query, len); | 2008 | snprintf(buf, len + 31, "Q%u-%hu\n%s", ptr->serial, |
2009 | ptr->retry, ptr->query); | ||
1707 | break; | 2010 | break; |
1708 | } | 2011 | } |
1709 | spin_unlock(&tomoyo_query_list_lock); | 2012 | spin_unlock(&tomoyo_query_list_lock); |
@@ -1760,7 +2063,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head) | |||
1760 | static void tomoyo_read_version(struct tomoyo_io_buffer *head) | 2063 | static void tomoyo_read_version(struct tomoyo_io_buffer *head) |
1761 | { | 2064 | { |
1762 | if (!head->r.eof) { | 2065 | if (!head->r.eof) { |
1763 | tomoyo_io_printf(head, "2.3.0"); | 2066 | tomoyo_io_printf(head, "2.4.0"); |
1764 | head->r.eof = true; | 2067 | head->r.eof = true; |
1765 | } | 2068 | } |
1766 | } | 2069 | } |
@@ -1785,15 +2088,111 @@ static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head) | |||
1785 | } | 2088 | } |
1786 | } | 2089 | } |
1787 | 2090 | ||
2091 | /* String table for /sys/kernel/security/tomoyo/stat interface. */ | ||
2092 | static const char * const tomoyo_policy_headers[TOMOYO_MAX_POLICY_STAT] = { | ||
2093 | [TOMOYO_STAT_POLICY_UPDATES] = "update:", | ||
2094 | [TOMOYO_STAT_POLICY_LEARNING] = "violation in learning mode:", | ||
2095 | [TOMOYO_STAT_POLICY_PERMISSIVE] = "violation in permissive mode:", | ||
2096 | [TOMOYO_STAT_POLICY_ENFORCING] = "violation in enforcing mode:", | ||
2097 | }; | ||
2098 | |||
2099 | /* String table for /sys/kernel/security/tomoyo/stat interface. */ | ||
2100 | static const char * const tomoyo_memory_headers[TOMOYO_MAX_MEMORY_STAT] = { | ||
2101 | [TOMOYO_MEMORY_POLICY] = "policy:", | ||
2102 | [TOMOYO_MEMORY_AUDIT] = "audit log:", | ||
2103 | [TOMOYO_MEMORY_QUERY] = "query message:", | ||
2104 | }; | ||
2105 | |||
2106 | /* Timestamp counter for last updated. */ | ||
2107 | static unsigned int tomoyo_stat_updated[TOMOYO_MAX_POLICY_STAT]; | ||
2108 | /* Counter for number of updates. */ | ||
2109 | static unsigned int tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT]; | ||
2110 | |||
2111 | /** | ||
2112 | * tomoyo_update_stat - Update statistic counters. | ||
2113 | * | ||
2114 | * @index: Index for policy type. | ||
2115 | * | ||
2116 | * Returns nothing. | ||
2117 | */ | ||
2118 | void tomoyo_update_stat(const u8 index) | ||
2119 | { | ||
2120 | struct timeval tv; | ||
2121 | do_gettimeofday(&tv); | ||
2122 | /* | ||
2123 | * I don't use atomic operations because race condition is not fatal. | ||
2124 | */ | ||
2125 | tomoyo_stat_updated[index]++; | ||
2126 | tomoyo_stat_modified[index] = tv.tv_sec; | ||
2127 | } | ||
2128 | |||
2129 | /** | ||
2130 | * tomoyo_read_stat - Read statistic data. | ||
2131 | * | ||
2132 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
2133 | * | ||
2134 | * Returns nothing. | ||
2135 | */ | ||
2136 | static void tomoyo_read_stat(struct tomoyo_io_buffer *head) | ||
2137 | { | ||
2138 | u8 i; | ||
2139 | unsigned int total = 0; | ||
2140 | if (head->r.eof) | ||
2141 | return; | ||
2142 | for (i = 0; i < TOMOYO_MAX_POLICY_STAT; i++) { | ||
2143 | tomoyo_io_printf(head, "Policy %-30s %10u", | ||
2144 | tomoyo_policy_headers[i], | ||
2145 | tomoyo_stat_updated[i]); | ||
2146 | if (tomoyo_stat_modified[i]) { | ||
2147 | struct tomoyo_time stamp; | ||
2148 | tomoyo_convert_time(tomoyo_stat_modified[i], &stamp); | ||
2149 | tomoyo_io_printf(head, " (Last: %04u/%02u/%02u " | ||
2150 | "%02u:%02u:%02u)", | ||
2151 | stamp.year, stamp.month, stamp.day, | ||
2152 | stamp.hour, stamp.min, stamp.sec); | ||
2153 | } | ||
2154 | tomoyo_set_lf(head); | ||
2155 | } | ||
2156 | for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) { | ||
2157 | unsigned int used = tomoyo_memory_used[i]; | ||
2158 | total += used; | ||
2159 | tomoyo_io_printf(head, "Memory used by %-22s %10u", | ||
2160 | tomoyo_memory_headers[i], used); | ||
2161 | used = tomoyo_memory_quota[i]; | ||
2162 | if (used) | ||
2163 | tomoyo_io_printf(head, " (Quota: %10u)", used); | ||
2164 | tomoyo_set_lf(head); | ||
2165 | } | ||
2166 | tomoyo_io_printf(head, "Total memory used: %10u\n", | ||
2167 | total); | ||
2168 | head->r.eof = true; | ||
2169 | } | ||
2170 | |||
2171 | /** | ||
2172 | * tomoyo_write_stat - Set memory quota. | ||
2173 | * | ||
2174 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
2175 | * | ||
2176 | * Returns 0. | ||
2177 | */ | ||
2178 | static int tomoyo_write_stat(struct tomoyo_io_buffer *head) | ||
2179 | { | ||
2180 | char *data = head->write_buf; | ||
2181 | u8 i; | ||
2182 | if (tomoyo_str_starts(&data, "Memory used by ")) | ||
2183 | for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) | ||
2184 | if (tomoyo_str_starts(&data, tomoyo_memory_headers[i])) | ||
2185 | sscanf(data, "%u", &tomoyo_memory_quota[i]); | ||
2186 | return 0; | ||
2187 | } | ||
2188 | |||
1788 | /** | 2189 | /** |
1789 | * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface. | 2190 | * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface. |
1790 | * | 2191 | * |
1791 | * @type: Type of interface. | 2192 | * @type: Type of interface. |
1792 | * @file: Pointer to "struct file". | 2193 | * @file: Pointer to "struct file". |
1793 | * | 2194 | * |
1794 | * Associates policy handler and returns 0 on success, -ENOMEM otherwise. | 2195 | * Returns 0 on success, negative value otherwise. |
1795 | * | ||
1796 | * Caller acquires tomoyo_read_lock(). | ||
1797 | */ | 2196 | */ |
1798 | int tomoyo_open_control(const u8 type, struct file *file) | 2197 | int tomoyo_open_control(const u8 type, struct file *file) |
1799 | { | 2198 | { |
@@ -1814,15 +2213,15 @@ int tomoyo_open_control(const u8 type, struct file *file) | |||
1814 | head->write = tomoyo_write_exception; | 2213 | head->write = tomoyo_write_exception; |
1815 | head->read = tomoyo_read_exception; | 2214 | head->read = tomoyo_read_exception; |
1816 | break; | 2215 | break; |
2216 | case TOMOYO_AUDIT: | ||
2217 | /* /sys/kernel/security/tomoyo/audit */ | ||
2218 | head->poll = tomoyo_poll_log; | ||
2219 | head->read = tomoyo_read_log; | ||
2220 | break; | ||
1817 | case TOMOYO_SELFDOMAIN: | 2221 | case TOMOYO_SELFDOMAIN: |
1818 | /* /sys/kernel/security/tomoyo/self_domain */ | 2222 | /* /sys/kernel/security/tomoyo/self_domain */ |
1819 | head->read = tomoyo_read_self_domain; | 2223 | head->read = tomoyo_read_self_domain; |
1820 | break; | 2224 | break; |
1821 | case TOMOYO_DOMAIN_STATUS: | ||
1822 | /* /sys/kernel/security/tomoyo/.domain_status */ | ||
1823 | head->write = tomoyo_write_domain_profile; | ||
1824 | head->read = tomoyo_read_domain_profile; | ||
1825 | break; | ||
1826 | case TOMOYO_PROCESS_STATUS: | 2225 | case TOMOYO_PROCESS_STATUS: |
1827 | /* /sys/kernel/security/tomoyo/.process_status */ | 2226 | /* /sys/kernel/security/tomoyo/.process_status */ |
1828 | head->write = tomoyo_write_pid; | 2227 | head->write = tomoyo_write_pid; |
@@ -1833,11 +2232,11 @@ int tomoyo_open_control(const u8 type, struct file *file) | |||
1833 | head->read = tomoyo_read_version; | 2232 | head->read = tomoyo_read_version; |
1834 | head->readbuf_size = 128; | 2233 | head->readbuf_size = 128; |
1835 | break; | 2234 | break; |
1836 | case TOMOYO_MEMINFO: | 2235 | case TOMOYO_STAT: |
1837 | /* /sys/kernel/security/tomoyo/meminfo */ | 2236 | /* /sys/kernel/security/tomoyo/stat */ |
1838 | head->write = tomoyo_write_memory_quota; | 2237 | head->write = tomoyo_write_stat; |
1839 | head->read = tomoyo_read_memory_counter; | 2238 | head->read = tomoyo_read_stat; |
1840 | head->readbuf_size = 512; | 2239 | head->readbuf_size = 1024; |
1841 | break; | 2240 | break; |
1842 | case TOMOYO_PROFILE: | 2241 | case TOMOYO_PROFILE: |
1843 | /* /sys/kernel/security/tomoyo/profile */ | 2242 | /* /sys/kernel/security/tomoyo/profile */ |
@@ -1887,26 +2286,16 @@ int tomoyo_open_control(const u8 type, struct file *file) | |||
1887 | return -ENOMEM; | 2286 | return -ENOMEM; |
1888 | } | 2287 | } |
1889 | } | 2288 | } |
1890 | if (type != TOMOYO_QUERY) | ||
1891 | head->reader_idx = tomoyo_read_lock(); | ||
1892 | file->private_data = head; | ||
1893 | /* | ||
1894 | * Call the handler now if the file is | ||
1895 | * /sys/kernel/security/tomoyo/self_domain | ||
1896 | * so that the user can use | ||
1897 | * cat < /sys/kernel/security/tomoyo/self_domain" | ||
1898 | * to know the current process's domainname. | ||
1899 | */ | ||
1900 | if (type == TOMOYO_SELFDOMAIN) | ||
1901 | tomoyo_read_control(file, NULL, 0); | ||
1902 | /* | 2289 | /* |
1903 | * If the file is /sys/kernel/security/tomoyo/query , increment the | 2290 | * If the file is /sys/kernel/security/tomoyo/query , increment the |
1904 | * observer counter. | 2291 | * observer counter. |
1905 | * The obserber counter is used by tomoyo_supervisor() to see if | 2292 | * The obserber counter is used by tomoyo_supervisor() to see if |
1906 | * there is some process monitoring /sys/kernel/security/tomoyo/query. | 2293 | * there is some process monitoring /sys/kernel/security/tomoyo/query. |
1907 | */ | 2294 | */ |
1908 | else if (type == TOMOYO_QUERY) | 2295 | if (type == TOMOYO_QUERY) |
1909 | atomic_inc(&tomoyo_query_observers); | 2296 | atomic_inc(&tomoyo_query_observers); |
2297 | file->private_data = head; | ||
2298 | tomoyo_notify_gc(head, true); | ||
1910 | return 0; | 2299 | return 0; |
1911 | } | 2300 | } |
1912 | 2301 | ||
@@ -1917,7 +2306,8 @@ int tomoyo_open_control(const u8 type, struct file *file) | |||
1917 | * @wait: Pointer to "poll_table". | 2306 | * @wait: Pointer to "poll_table". |
1918 | * | 2307 | * |
1919 | * Waits for read readiness. | 2308 | * Waits for read readiness. |
1920 | * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd . | 2309 | * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd and |
2310 | * /sys/kernel/security/tomoyo/audit is handled by /usr/sbin/tomoyo-auditd. | ||
1921 | */ | 2311 | */ |
1922 | int tomoyo_poll_control(struct file *file, poll_table *wait) | 2312 | int tomoyo_poll_control(struct file *file, poll_table *wait) |
1923 | { | 2313 | { |
@@ -1928,21 +2318,58 @@ int tomoyo_poll_control(struct file *file, poll_table *wait) | |||
1928 | } | 2318 | } |
1929 | 2319 | ||
1930 | /** | 2320 | /** |
2321 | * tomoyo_set_namespace_cursor - Set namespace to read. | ||
2322 | * | ||
2323 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
2324 | * | ||
2325 | * Returns nothing. | ||
2326 | */ | ||
2327 | static inline void tomoyo_set_namespace_cursor(struct tomoyo_io_buffer *head) | ||
2328 | { | ||
2329 | struct list_head *ns; | ||
2330 | if (head->type != TOMOYO_EXCEPTIONPOLICY && | ||
2331 | head->type != TOMOYO_PROFILE) | ||
2332 | return; | ||
2333 | /* | ||
2334 | * If this is the first read, or reading previous namespace finished | ||
2335 | * and has more namespaces to read, update the namespace cursor. | ||
2336 | */ | ||
2337 | ns = head->r.ns; | ||
2338 | if (!ns || (head->r.eof && ns->next != &tomoyo_namespace_list)) { | ||
2339 | /* Clearing is OK because tomoyo_flush() returned true. */ | ||
2340 | memset(&head->r, 0, sizeof(head->r)); | ||
2341 | head->r.ns = ns ? ns->next : tomoyo_namespace_list.next; | ||
2342 | } | ||
2343 | } | ||
2344 | |||
2345 | /** | ||
2346 | * tomoyo_has_more_namespace - Check for unread namespaces. | ||
2347 | * | ||
2348 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
2349 | * | ||
2350 | * Returns true if we have more entries to print, false otherwise. | ||
2351 | */ | ||
2352 | static inline bool tomoyo_has_more_namespace(struct tomoyo_io_buffer *head) | ||
2353 | { | ||
2354 | return (head->type == TOMOYO_EXCEPTIONPOLICY || | ||
2355 | head->type == TOMOYO_PROFILE) && head->r.eof && | ||
2356 | head->r.ns->next != &tomoyo_namespace_list; | ||
2357 | } | ||
2358 | |||
2359 | /** | ||
1931 | * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. | 2360 | * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. |
1932 | * | 2361 | * |
1933 | * @file: Pointer to "struct file". | 2362 | * @head: Pointer to "struct tomoyo_io_buffer". |
1934 | * @buffer: Poiner to buffer to write to. | 2363 | * @buffer: Poiner to buffer to write to. |
1935 | * @buffer_len: Size of @buffer. | 2364 | * @buffer_len: Size of @buffer. |
1936 | * | 2365 | * |
1937 | * Returns bytes read on success, negative value otherwise. | 2366 | * Returns bytes read on success, negative value otherwise. |
1938 | * | ||
1939 | * Caller holds tomoyo_read_lock(). | ||
1940 | */ | 2367 | */ |
1941 | int tomoyo_read_control(struct file *file, char __user *buffer, | 2368 | ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer, |
1942 | const int buffer_len) | 2369 | const int buffer_len) |
1943 | { | 2370 | { |
1944 | int len; | 2371 | int len; |
1945 | struct tomoyo_io_buffer *head = file->private_data; | 2372 | int idx; |
1946 | 2373 | ||
1947 | if (!head->read) | 2374 | if (!head->read) |
1948 | return -ENOSYS; | 2375 | return -ENOSYS; |
@@ -1950,64 +2377,156 @@ int tomoyo_read_control(struct file *file, char __user *buffer, | |||
1950 | return -EINTR; | 2377 | return -EINTR; |
1951 | head->read_user_buf = buffer; | 2378 | head->read_user_buf = buffer; |
1952 | head->read_user_buf_avail = buffer_len; | 2379 | head->read_user_buf_avail = buffer_len; |
2380 | idx = tomoyo_read_lock(); | ||
1953 | if (tomoyo_flush(head)) | 2381 | if (tomoyo_flush(head)) |
1954 | /* Call the policy handler. */ | 2382 | /* Call the policy handler. */ |
1955 | head->read(head); | 2383 | do { |
1956 | tomoyo_flush(head); | 2384 | tomoyo_set_namespace_cursor(head); |
2385 | head->read(head); | ||
2386 | } while (tomoyo_flush(head) && | ||
2387 | tomoyo_has_more_namespace(head)); | ||
2388 | tomoyo_read_unlock(idx); | ||
1957 | len = head->read_user_buf - buffer; | 2389 | len = head->read_user_buf - buffer; |
1958 | mutex_unlock(&head->io_sem); | 2390 | mutex_unlock(&head->io_sem); |
1959 | return len; | 2391 | return len; |
1960 | } | 2392 | } |
1961 | 2393 | ||
1962 | /** | 2394 | /** |
2395 | * tomoyo_parse_policy - Parse a policy line. | ||
2396 | * | ||
2397 | * @head: Poiter to "struct tomoyo_io_buffer". | ||
2398 | * @line: Line to parse. | ||
2399 | * | ||
2400 | * Returns 0 on success, negative value otherwise. | ||
2401 | * | ||
2402 | * Caller holds tomoyo_read_lock(). | ||
2403 | */ | ||
2404 | static int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line) | ||
2405 | { | ||
2406 | /* Delete request? */ | ||
2407 | head->w.is_delete = !strncmp(line, "delete ", 7); | ||
2408 | if (head->w.is_delete) | ||
2409 | memmove(line, line + 7, strlen(line + 7) + 1); | ||
2410 | /* Selecting namespace to update. */ | ||
2411 | if (head->type == TOMOYO_EXCEPTIONPOLICY || | ||
2412 | head->type == TOMOYO_PROFILE) { | ||
2413 | if (*line == '<') { | ||
2414 | char *cp = strchr(line, ' '); | ||
2415 | if (cp) { | ||
2416 | *cp++ = '\0'; | ||
2417 | head->w.ns = tomoyo_assign_namespace(line); | ||
2418 | memmove(line, cp, strlen(cp) + 1); | ||
2419 | } else | ||
2420 | head->w.ns = NULL; | ||
2421 | } else | ||
2422 | head->w.ns = &tomoyo_kernel_namespace; | ||
2423 | /* Don't allow updating if namespace is invalid. */ | ||
2424 | if (!head->w.ns) | ||
2425 | return -ENOENT; | ||
2426 | } | ||
2427 | /* Do the update. */ | ||
2428 | return head->write(head); | ||
2429 | } | ||
2430 | |||
2431 | /** | ||
1963 | * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface. | 2432 | * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface. |
1964 | * | 2433 | * |
1965 | * @file: Pointer to "struct file". | 2434 | * @head: Pointer to "struct tomoyo_io_buffer". |
1966 | * @buffer: Pointer to buffer to read from. | 2435 | * @buffer: Pointer to buffer to read from. |
1967 | * @buffer_len: Size of @buffer. | 2436 | * @buffer_len: Size of @buffer. |
1968 | * | 2437 | * |
1969 | * Returns @buffer_len on success, negative value otherwise. | 2438 | * Returns @buffer_len on success, negative value otherwise. |
1970 | * | ||
1971 | * Caller holds tomoyo_read_lock(). | ||
1972 | */ | 2439 | */ |
1973 | int tomoyo_write_control(struct file *file, const char __user *buffer, | 2440 | ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, |
1974 | const int buffer_len) | 2441 | const char __user *buffer, const int buffer_len) |
1975 | { | 2442 | { |
1976 | struct tomoyo_io_buffer *head = file->private_data; | ||
1977 | int error = buffer_len; | 2443 | int error = buffer_len; |
1978 | int avail_len = buffer_len; | 2444 | size_t avail_len = buffer_len; |
1979 | char *cp0 = head->write_buf; | 2445 | char *cp0 = head->write_buf; |
1980 | 2446 | int idx; | |
1981 | if (!head->write) | 2447 | if (!head->write) |
1982 | return -ENOSYS; | 2448 | return -ENOSYS; |
1983 | if (!access_ok(VERIFY_READ, buffer, buffer_len)) | 2449 | if (!access_ok(VERIFY_READ, buffer, buffer_len)) |
1984 | return -EFAULT; | 2450 | return -EFAULT; |
1985 | /* Don't allow updating policies by non manager programs. */ | ||
1986 | if (head->write != tomoyo_write_pid && | ||
1987 | head->write != tomoyo_write_domain && !tomoyo_manager()) | ||
1988 | return -EPERM; | ||
1989 | if (mutex_lock_interruptible(&head->io_sem)) | 2451 | if (mutex_lock_interruptible(&head->io_sem)) |
1990 | return -EINTR; | 2452 | return -EINTR; |
2453 | idx = tomoyo_read_lock(); | ||
1991 | /* Read a line and dispatch it to the policy handler. */ | 2454 | /* Read a line and dispatch it to the policy handler. */ |
1992 | while (avail_len > 0) { | 2455 | while (avail_len > 0) { |
1993 | char c; | 2456 | char c; |
1994 | if (head->write_avail >= head->writebuf_size - 1) { | 2457 | if (head->w.avail >= head->writebuf_size - 1) { |
1995 | error = -ENOMEM; | 2458 | const int len = head->writebuf_size * 2; |
1996 | break; | 2459 | char *cp = kzalloc(len, GFP_NOFS); |
1997 | } else if (get_user(c, buffer)) { | 2460 | if (!cp) { |
2461 | error = -ENOMEM; | ||
2462 | break; | ||
2463 | } | ||
2464 | memmove(cp, cp0, head->w.avail); | ||
2465 | kfree(cp0); | ||
2466 | head->write_buf = cp; | ||
2467 | cp0 = cp; | ||
2468 | head->writebuf_size = len; | ||
2469 | } | ||
2470 | if (get_user(c, buffer)) { | ||
1998 | error = -EFAULT; | 2471 | error = -EFAULT; |
1999 | break; | 2472 | break; |
2000 | } | 2473 | } |
2001 | buffer++; | 2474 | buffer++; |
2002 | avail_len--; | 2475 | avail_len--; |
2003 | cp0[head->write_avail++] = c; | 2476 | cp0[head->w.avail++] = c; |
2004 | if (c != '\n') | 2477 | if (c != '\n') |
2005 | continue; | 2478 | continue; |
2006 | cp0[head->write_avail - 1] = '\0'; | 2479 | cp0[head->w.avail - 1] = '\0'; |
2007 | head->write_avail = 0; | 2480 | head->w.avail = 0; |
2008 | tomoyo_normalize_line(cp0); | 2481 | tomoyo_normalize_line(cp0); |
2009 | head->write(head); | 2482 | if (!strcmp(cp0, "reset")) { |
2483 | head->w.ns = &tomoyo_kernel_namespace; | ||
2484 | head->w.domain = NULL; | ||
2485 | memset(&head->r, 0, sizeof(head->r)); | ||
2486 | continue; | ||
2487 | } | ||
2488 | /* Don't allow updating policies by non manager programs. */ | ||
2489 | switch (head->type) { | ||
2490 | case TOMOYO_PROCESS_STATUS: | ||
2491 | /* This does not write anything. */ | ||
2492 | break; | ||
2493 | case TOMOYO_DOMAINPOLICY: | ||
2494 | if (tomoyo_select_domain(head, cp0)) | ||
2495 | continue; | ||
2496 | /* fall through */ | ||
2497 | case TOMOYO_EXCEPTIONPOLICY: | ||
2498 | if (!strcmp(cp0, "select transition_only")) { | ||
2499 | head->r.print_transition_related_only = true; | ||
2500 | continue; | ||
2501 | } | ||
2502 | /* fall through */ | ||
2503 | default: | ||
2504 | if (!tomoyo_manager()) { | ||
2505 | error = -EPERM; | ||
2506 | goto out; | ||
2507 | } | ||
2508 | } | ||
2509 | switch (tomoyo_parse_policy(head, cp0)) { | ||
2510 | case -EPERM: | ||
2511 | error = -EPERM; | ||
2512 | goto out; | ||
2513 | case 0: | ||
2514 | switch (head->type) { | ||
2515 | case TOMOYO_DOMAINPOLICY: | ||
2516 | case TOMOYO_EXCEPTIONPOLICY: | ||
2517 | case TOMOYO_STAT: | ||
2518 | case TOMOYO_PROFILE: | ||
2519 | case TOMOYO_MANAGER: | ||
2520 | tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); | ||
2521 | break; | ||
2522 | default: | ||
2523 | break; | ||
2524 | } | ||
2525 | break; | ||
2526 | } | ||
2010 | } | 2527 | } |
2528 | out: | ||
2529 | tomoyo_read_unlock(idx); | ||
2011 | mutex_unlock(&head->io_sem); | 2530 | mutex_unlock(&head->io_sem); |
2012 | return error; | 2531 | return error; |
2013 | } | 2532 | } |
@@ -2015,35 +2534,20 @@ int tomoyo_write_control(struct file *file, const char __user *buffer, | |||
2015 | /** | 2534 | /** |
2016 | * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface. | 2535 | * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface. |
2017 | * | 2536 | * |
2018 | * @file: Pointer to "struct file". | 2537 | * @head: Pointer to "struct tomoyo_io_buffer". |
2019 | * | ||
2020 | * Releases memory and returns 0. | ||
2021 | * | 2538 | * |
2022 | * Caller looses tomoyo_read_lock(). | 2539 | * Returns 0. |
2023 | */ | 2540 | */ |
2024 | int tomoyo_close_control(struct file *file) | 2541 | int tomoyo_close_control(struct tomoyo_io_buffer *head) |
2025 | { | 2542 | { |
2026 | struct tomoyo_io_buffer *head = file->private_data; | ||
2027 | const bool is_write = !!head->write_buf; | ||
2028 | |||
2029 | /* | 2543 | /* |
2030 | * If the file is /sys/kernel/security/tomoyo/query , decrement the | 2544 | * If the file is /sys/kernel/security/tomoyo/query , decrement the |
2031 | * observer counter. | 2545 | * observer counter. |
2032 | */ | 2546 | */ |
2033 | if (head->type == TOMOYO_QUERY) | 2547 | if (head->type == TOMOYO_QUERY && |
2034 | atomic_dec(&tomoyo_query_observers); | 2548 | atomic_dec_and_test(&tomoyo_query_observers)) |
2035 | else | 2549 | wake_up_all(&tomoyo_answer_wait); |
2036 | tomoyo_read_unlock(head->reader_idx); | 2550 | tomoyo_notify_gc(head, false); |
2037 | /* Release memory used for policy I/O. */ | ||
2038 | kfree(head->read_buf); | ||
2039 | head->read_buf = NULL; | ||
2040 | kfree(head->write_buf); | ||
2041 | head->write_buf = NULL; | ||
2042 | kfree(head); | ||
2043 | head = NULL; | ||
2044 | file->private_data = NULL; | ||
2045 | if (is_write) | ||
2046 | tomoyo_run_gc(); | ||
2047 | return 0; | 2551 | return 0; |
2048 | } | 2552 | } |
2049 | 2553 | ||
@@ -2055,27 +2559,90 @@ void tomoyo_check_profile(void) | |||
2055 | struct tomoyo_domain_info *domain; | 2559 | struct tomoyo_domain_info *domain; |
2056 | const int idx = tomoyo_read_lock(); | 2560 | const int idx = tomoyo_read_lock(); |
2057 | tomoyo_policy_loaded = true; | 2561 | tomoyo_policy_loaded = true; |
2058 | /* Check all profiles currently assigned to domains are defined. */ | 2562 | printk(KERN_INFO "TOMOYO: 2.4.0\n"); |
2059 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 2563 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
2060 | const u8 profile = domain->profile; | 2564 | const u8 profile = domain->profile; |
2061 | if (tomoyo_profile_ptr[profile]) | 2565 | const struct tomoyo_policy_namespace *ns = domain->ns; |
2566 | if (ns->profile_version != 20100903) | ||
2567 | printk(KERN_ERR | ||
2568 | "Profile version %u is not supported.\n", | ||
2569 | ns->profile_version); | ||
2570 | else if (!ns->profile_ptr[profile]) | ||
2571 | printk(KERN_ERR | ||
2572 | "Profile %u (used by '%s') is not defined.\n", | ||
2573 | profile, domain->domainname->name); | ||
2574 | else | ||
2062 | continue; | 2575 | continue; |
2063 | printk(KERN_ERR "You need to define profile %u before using it.\n", | 2576 | printk(KERN_ERR |
2064 | profile); | 2577 | "Userland tools for TOMOYO 2.4 must be installed and " |
2065 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ " | 2578 | "policy must be initialized.\n"); |
2579 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.4/ " | ||
2066 | "for more information.\n"); | 2580 | "for more information.\n"); |
2067 | panic("Profile %u (used by '%s') not defined.\n", | 2581 | panic("STOP!"); |
2068 | profile, domain->domainname->name); | ||
2069 | } | 2582 | } |
2070 | tomoyo_read_unlock(idx); | 2583 | tomoyo_read_unlock(idx); |
2071 | if (tomoyo_profile_version != 20090903) { | ||
2072 | printk(KERN_ERR "You need to install userland programs for " | ||
2073 | "TOMOYO 2.3 and initialize policy configuration.\n"); | ||
2074 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ " | ||
2075 | "for more information.\n"); | ||
2076 | panic("Profile version %u is not supported.\n", | ||
2077 | tomoyo_profile_version); | ||
2078 | } | ||
2079 | printk(KERN_INFO "TOMOYO: 2.3.0\n"); | ||
2080 | printk(KERN_INFO "Mandatory Access Control activated.\n"); | 2584 | printk(KERN_INFO "Mandatory Access Control activated.\n"); |
2081 | } | 2585 | } |
2586 | |||
2587 | /** | ||
2588 | * tomoyo_load_builtin_policy - Load built-in policy. | ||
2589 | * | ||
2590 | * Returns nothing. | ||
2591 | */ | ||
2592 | void __init tomoyo_load_builtin_policy(void) | ||
2593 | { | ||
2594 | /* | ||
2595 | * This include file is manually created and contains built-in policy | ||
2596 | * named "tomoyo_builtin_profile", "tomoyo_builtin_exception_policy", | ||
2597 | * "tomoyo_builtin_domain_policy", "tomoyo_builtin_manager", | ||
2598 | * "tomoyo_builtin_stat" in the form of "static char [] __initdata". | ||
2599 | */ | ||
2600 | #include "builtin-policy.h" | ||
2601 | u8 i; | ||
2602 | const int idx = tomoyo_read_lock(); | ||
2603 | for (i = 0; i < 5; i++) { | ||
2604 | struct tomoyo_io_buffer head = { }; | ||
2605 | char *start = ""; | ||
2606 | switch (i) { | ||
2607 | case 0: | ||
2608 | start = tomoyo_builtin_profile; | ||
2609 | head.type = TOMOYO_PROFILE; | ||
2610 | head.write = tomoyo_write_profile; | ||
2611 | break; | ||
2612 | case 1: | ||
2613 | start = tomoyo_builtin_exception_policy; | ||
2614 | head.type = TOMOYO_EXCEPTIONPOLICY; | ||
2615 | head.write = tomoyo_write_exception; | ||
2616 | break; | ||
2617 | case 2: | ||
2618 | start = tomoyo_builtin_domain_policy; | ||
2619 | head.type = TOMOYO_DOMAINPOLICY; | ||
2620 | head.write = tomoyo_write_domain; | ||
2621 | break; | ||
2622 | case 3: | ||
2623 | start = tomoyo_builtin_manager; | ||
2624 | head.type = TOMOYO_MANAGER; | ||
2625 | head.write = tomoyo_write_manager; | ||
2626 | break; | ||
2627 | case 4: | ||
2628 | start = tomoyo_builtin_stat; | ||
2629 | head.type = TOMOYO_STAT; | ||
2630 | head.write = tomoyo_write_stat; | ||
2631 | break; | ||
2632 | } | ||
2633 | while (1) { | ||
2634 | char *end = strchr(start, '\n'); | ||
2635 | if (!end) | ||
2636 | break; | ||
2637 | *end = '\0'; | ||
2638 | tomoyo_normalize_line(start); | ||
2639 | head.write_buf = start; | ||
2640 | tomoyo_parse_policy(&head, start); | ||
2641 | start = end + 1; | ||
2642 | } | ||
2643 | } | ||
2644 | tomoyo_read_unlock(idx); | ||
2645 | #ifdef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER | ||
2646 | tomoyo_check_profile(); | ||
2647 | #endif | ||
2648 | } | ||