diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-25 03:45:31 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-25 03:45:31 -0400 |
commit | 36b8d186e6cc8e32cb5227f5645a58e1bc0af190 (patch) | |
tree | 1000ad26e189e6ff2c53fb7eeff605f59c7ad94e /security/tomoyo | |
parent | cd85b557414fe4cd44ea6608825e96612a5fe2b2 (diff) | |
parent | c45ed235abf1b0b6666417e3c394f18717976acd (diff) |
Merge branch 'next' of git://selinuxproject.org/~jmorris/linux-security
* 'next' of git://selinuxproject.org/~jmorris/linux-security: (95 commits)
TOMOYO: Fix incomplete read after seek.
Smack: allow to access /smack/access as normal user
TOMOYO: Fix unused kernel config option.
Smack: fix: invalid length set for the result of /smack/access
Smack: compilation fix
Smack: fix for /smack/access output, use string instead of byte
Smack: domain transition protections (v3)
Smack: Provide information for UDS getsockopt(SO_PEERCRED)
Smack: Clean up comments
Smack: Repair processing of fcntl
Smack: Rule list lookup performance
Smack: check permissions from user space (v2)
TOMOYO: Fix quota and garbage collector.
TOMOYO: Remove redundant tasklist_lock.
TOMOYO: Fix domain transition failure warning.
TOMOYO: Remove tomoyo_policy_memory_lock spinlock.
TOMOYO: Simplify garbage collector.
TOMOYO: Fix make namespacecheck warnings.
target: check hex2bin result
encrypted-keys: check hex2bin result
...
Diffstat (limited to 'security/tomoyo')
-rw-r--r-- | security/tomoyo/Kconfig | 2 | ||||
-rw-r--r-- | security/tomoyo/Makefile | 4 | ||||
-rw-r--r-- | security/tomoyo/audit.c | 7 | ||||
-rw-r--r-- | security/tomoyo/common.c | 228 | ||||
-rw-r--r-- | security/tomoyo/common.h | 189 | ||||
-rw-r--r-- | security/tomoyo/condition.c | 71 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 209 | ||||
-rw-r--r-- | security/tomoyo/environ.c | 122 | ||||
-rw-r--r-- | security/tomoyo/file.c | 42 | ||||
-rw-r--r-- | security/tomoyo/gc.c | 540 | ||||
-rw-r--r-- | security/tomoyo/group.c | 61 | ||||
-rw-r--r-- | security/tomoyo/memory.c | 39 | ||||
-rw-r--r-- | security/tomoyo/network.c | 771 | ||||
-rw-r--r-- | security/tomoyo/realpath.c | 32 | ||||
-rw-r--r-- | security/tomoyo/securityfs_if.c | 123 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.c | 62 | ||||
-rw-r--r-- | security/tomoyo/util.c | 80 |
17 files changed, 2128 insertions, 454 deletions
diff --git a/security/tomoyo/Kconfig b/security/tomoyo/Kconfig index 7c7f8c16c10f..8eb779b9d77f 100644 --- a/security/tomoyo/Kconfig +++ b/security/tomoyo/Kconfig | |||
@@ -1,8 +1,10 @@ | |||
1 | config SECURITY_TOMOYO | 1 | config SECURITY_TOMOYO |
2 | bool "TOMOYO Linux Support" | 2 | bool "TOMOYO Linux Support" |
3 | depends on SECURITY | 3 | depends on SECURITY |
4 | depends on NET | ||
4 | select SECURITYFS | 5 | select SECURITYFS |
5 | select SECURITY_PATH | 6 | select SECURITY_PATH |
7 | select SECURITY_NETWORK | ||
6 | default n | 8 | default n |
7 | help | 9 | help |
8 | This selects TOMOYO Linux, pathname-based access control. | 10 | This selects TOMOYO Linux, pathname-based access control. |
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index 95278b71fc21..56a0c7be409e 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-y = audit.o common.o condition.o domain.o file.o gc.o group.o load_policy.o memory.o mount.o realpath.o securityfs_if.o tomoyo.o util.o | 1 | obj-y = audit.o common.o condition.o domain.o environ.o file.o gc.o group.o load_policy.o memory.o mount.o network.o realpath.o securityfs_if.o tomoyo.o util.o |
2 | 2 | ||
3 | $(obj)/policy/profile.conf: | 3 | $(obj)/policy/profile.conf: |
4 | @mkdir -p $(obj)/policy/ | 4 | @mkdir -p $(obj)/policy/ |
@@ -27,7 +27,7 @@ $(obj)/policy/stat.conf: | |||
27 | @touch $@ | 27 | @touch $@ |
28 | 28 | ||
29 | $(obj)/builtin-policy.h: $(obj)/policy/profile.conf $(obj)/policy/exception_policy.conf $(obj)/policy/domain_policy.conf $(obj)/policy/manager.conf $(obj)/policy/stat.conf | 29 | $(obj)/builtin-policy.h: $(obj)/policy/profile.conf $(obj)/policy/exception_policy.conf $(obj)/policy/domain_policy.conf $(obj)/policy/manager.conf $(obj)/policy/stat.conf |
30 | @echo Generating built-in policy for TOMOYO 2.4.x. | 30 | @echo Generating built-in policy for TOMOYO 2.5.x. |
31 | @echo "static char tomoyo_builtin_profile[] __initdata =" > $@.tmp | 31 | @echo "static char tomoyo_builtin_profile[] __initdata =" > $@.tmp |
32 | @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/profile.conf >> $@.tmp | 32 | @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/profile.conf >> $@.tmp |
33 | @echo "\"\";" >> $@.tmp | 33 | @echo "\"\";" >> $@.tmp |
diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c index 5dbb1f7617c0..075c3a6d1649 100644 --- a/security/tomoyo/audit.c +++ b/security/tomoyo/audit.c | |||
@@ -313,6 +313,7 @@ static unsigned int tomoyo_log_count; | |||
313 | */ | 313 | */ |
314 | static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns, | 314 | static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns, |
315 | const u8 profile, const u8 index, | 315 | const u8 profile, const u8 index, |
316 | const struct tomoyo_acl_info *matched_acl, | ||
316 | const bool is_granted) | 317 | const bool is_granted) |
317 | { | 318 | { |
318 | u8 mode; | 319 | u8 mode; |
@@ -324,6 +325,9 @@ static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns, | |||
324 | p = tomoyo_profile(ns, profile); | 325 | p = tomoyo_profile(ns, profile); |
325 | if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG]) | 326 | if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG]) |
326 | return false; | 327 | return false; |
328 | if (is_granted && matched_acl && matched_acl->cond && | ||
329 | matched_acl->cond->grant_log != TOMOYO_GRANTLOG_AUTO) | ||
330 | return matched_acl->cond->grant_log == TOMOYO_GRANTLOG_YES; | ||
327 | mode = p->config[index]; | 331 | mode = p->config[index]; |
328 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) | 332 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) |
329 | mode = p->config[category]; | 333 | mode = p->config[category]; |
@@ -350,7 +354,8 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, | |||
350 | char *buf; | 354 | char *buf; |
351 | struct tomoyo_log *entry; | 355 | struct tomoyo_log *entry; |
352 | bool quota_exceeded = false; | 356 | bool quota_exceeded = false; |
353 | if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, r->granted)) | 357 | if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, |
358 | r->matched_acl, r->granted)) | ||
354 | goto out; | 359 | goto out; |
355 | buf = tomoyo_init_log(r, len, fmt, args); | 360 | buf = tomoyo_init_log(r, len, fmt, args); |
356 | if (!buf) | 361 | if (!buf) |
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 2e43aec1c36b..150911c7ff08 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -20,6 +20,7 @@ const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = { | |||
20 | /* String table for /sys/kernel/security/tomoyo/profile */ | 20 | /* String table for /sys/kernel/security/tomoyo/profile */ |
21 | const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX | 21 | const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX |
22 | + TOMOYO_MAX_MAC_CATEGORY_INDEX] = { | 22 | + TOMOYO_MAX_MAC_CATEGORY_INDEX] = { |
23 | /* CONFIG::file group */ | ||
23 | [TOMOYO_MAC_FILE_EXECUTE] = "execute", | 24 | [TOMOYO_MAC_FILE_EXECUTE] = "execute", |
24 | [TOMOYO_MAC_FILE_OPEN] = "open", | 25 | [TOMOYO_MAC_FILE_OPEN] = "open", |
25 | [TOMOYO_MAC_FILE_CREATE] = "create", | 26 | [TOMOYO_MAC_FILE_CREATE] = "create", |
@@ -43,7 +44,28 @@ const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX | |||
43 | [TOMOYO_MAC_FILE_MOUNT] = "mount", | 44 | [TOMOYO_MAC_FILE_MOUNT] = "mount", |
44 | [TOMOYO_MAC_FILE_UMOUNT] = "unmount", | 45 | [TOMOYO_MAC_FILE_UMOUNT] = "unmount", |
45 | [TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root", | 46 | [TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root", |
47 | /* CONFIG::network group */ | ||
48 | [TOMOYO_MAC_NETWORK_INET_STREAM_BIND] = "inet_stream_bind", | ||
49 | [TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN] = "inet_stream_listen", | ||
50 | [TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT] = "inet_stream_connect", | ||
51 | [TOMOYO_MAC_NETWORK_INET_DGRAM_BIND] = "inet_dgram_bind", | ||
52 | [TOMOYO_MAC_NETWORK_INET_DGRAM_SEND] = "inet_dgram_send", | ||
53 | [TOMOYO_MAC_NETWORK_INET_RAW_BIND] = "inet_raw_bind", | ||
54 | [TOMOYO_MAC_NETWORK_INET_RAW_SEND] = "inet_raw_send", | ||
55 | [TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND] = "unix_stream_bind", | ||
56 | [TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN] = "unix_stream_listen", | ||
57 | [TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT] = "unix_stream_connect", | ||
58 | [TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND] = "unix_dgram_bind", | ||
59 | [TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND] = "unix_dgram_send", | ||
60 | [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND] = "unix_seqpacket_bind", | ||
61 | [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = "unix_seqpacket_listen", | ||
62 | [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect", | ||
63 | /* CONFIG::misc group */ | ||
64 | [TOMOYO_MAC_ENVIRON] = "env", | ||
65 | /* CONFIG group */ | ||
46 | [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file", | 66 | [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file", |
67 | [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_NETWORK] = "network", | ||
68 | [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_MISC] = "misc", | ||
47 | }; | 69 | }; |
48 | 70 | ||
49 | /* String table for conditions. */ | 71 | /* String table for conditions. */ |
@@ -130,10 +152,20 @@ const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { | |||
130 | [TOMOYO_TYPE_UMOUNT] = "unmount", | 152 | [TOMOYO_TYPE_UMOUNT] = "unmount", |
131 | }; | 153 | }; |
132 | 154 | ||
155 | /* String table for socket's operation. */ | ||
156 | const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION] = { | ||
157 | [TOMOYO_NETWORK_BIND] = "bind", | ||
158 | [TOMOYO_NETWORK_LISTEN] = "listen", | ||
159 | [TOMOYO_NETWORK_CONNECT] = "connect", | ||
160 | [TOMOYO_NETWORK_SEND] = "send", | ||
161 | }; | ||
162 | |||
133 | /* String table for categories. */ | 163 | /* String table for categories. */ |
134 | static const char * const tomoyo_category_keywords | 164 | static const char * const tomoyo_category_keywords |
135 | [TOMOYO_MAX_MAC_CATEGORY_INDEX] = { | 165 | [TOMOYO_MAX_MAC_CATEGORY_INDEX] = { |
136 | [TOMOYO_MAC_CATEGORY_FILE] = "file", | 166 | [TOMOYO_MAC_CATEGORY_FILE] = "file", |
167 | [TOMOYO_MAC_CATEGORY_NETWORK] = "network", | ||
168 | [TOMOYO_MAC_CATEGORY_MISC] = "misc", | ||
137 | }; | 169 | }; |
138 | 170 | ||
139 | /* Permit policy management by non-root user? */ | 171 | /* Permit policy management by non-root user? */ |
@@ -230,13 +262,17 @@ static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string) | |||
230 | WARN_ON(1); | 262 | WARN_ON(1); |
231 | } | 263 | } |
232 | 264 | ||
265 | static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, | ||
266 | ...) __printf(2, 3); | ||
267 | |||
233 | /** | 268 | /** |
234 | * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure. | 269 | * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure. |
235 | * | 270 | * |
236 | * @head: Pointer to "struct tomoyo_io_buffer". | 271 | * @head: Pointer to "struct tomoyo_io_buffer". |
237 | * @fmt: The printf()'s format string, followed by parameters. | 272 | * @fmt: The printf()'s format string, followed by parameters. |
238 | */ | 273 | */ |
239 | void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | 274 | static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, |
275 | ...) | ||
240 | { | 276 | { |
241 | va_list args; | 277 | va_list args; |
242 | size_t len; | 278 | size_t len; |
@@ -313,7 +349,7 @@ void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns) | |||
313 | INIT_LIST_HEAD(&ns->group_list[idx]); | 349 | INIT_LIST_HEAD(&ns->group_list[idx]); |
314 | for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++) | 350 | for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++) |
315 | INIT_LIST_HEAD(&ns->policy_list[idx]); | 351 | INIT_LIST_HEAD(&ns->policy_list[idx]); |
316 | ns->profile_version = 20100903; | 352 | ns->profile_version = 20110903; |
317 | tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list); | 353 | tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list); |
318 | list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list); | 354 | list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list); |
319 | } | 355 | } |
@@ -466,8 +502,10 @@ static struct tomoyo_profile *tomoyo_assign_profile | |||
466 | TOMOYO_CONFIG_WANT_REJECT_LOG; | 502 | TOMOYO_CONFIG_WANT_REJECT_LOG; |
467 | memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT, | 503 | memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT, |
468 | sizeof(ptr->config)); | 504 | sizeof(ptr->config)); |
469 | ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 1024; | 505 | ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = |
470 | ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048; | 506 | CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG; |
507 | ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = | ||
508 | CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY; | ||
471 | mb(); /* Avoid out-of-order execution. */ | 509 | mb(); /* Avoid out-of-order execution. */ |
472 | ns->profile_ptr[profile] = ptr; | 510 | ns->profile_ptr[profile] = ptr; |
473 | entry = NULL; | 511 | entry = NULL; |
@@ -951,14 +989,12 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head, | |||
951 | (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { | 989 | (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { |
952 | struct task_struct *p; | 990 | struct task_struct *p; |
953 | rcu_read_lock(); | 991 | rcu_read_lock(); |
954 | read_lock(&tasklist_lock); | ||
955 | if (global_pid) | 992 | if (global_pid) |
956 | p = find_task_by_pid_ns(pid, &init_pid_ns); | 993 | p = find_task_by_pid_ns(pid, &init_pid_ns); |
957 | else | 994 | else |
958 | p = find_task_by_vpid(pid); | 995 | p = find_task_by_vpid(pid); |
959 | if (p) | 996 | if (p) |
960 | domain = tomoyo_real_domain(p); | 997 | domain = tomoyo_real_domain(p); |
961 | read_unlock(&tasklist_lock); | ||
962 | rcu_read_unlock(); | 998 | rcu_read_unlock(); |
963 | } else if (!strncmp(data, "domain=", 7)) { | 999 | } else if (!strncmp(data, "domain=", 7)) { |
964 | if (tomoyo_domain_def(data + 7)) | 1000 | if (tomoyo_domain_def(data + 7)) |
@@ -982,6 +1018,48 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head, | |||
982 | } | 1018 | } |
983 | 1019 | ||
984 | /** | 1020 | /** |
1021 | * tomoyo_same_task_acl - Check for duplicated "struct tomoyo_task_acl" entry. | ||
1022 | * | ||
1023 | * @a: Pointer to "struct tomoyo_acl_info". | ||
1024 | * @b: Pointer to "struct tomoyo_acl_info". | ||
1025 | * | ||
1026 | * Returns true if @a == @b, false otherwise. | ||
1027 | */ | ||
1028 | static bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a, | ||
1029 | const struct tomoyo_acl_info *b) | ||
1030 | { | ||
1031 | const struct tomoyo_task_acl *p1 = container_of(a, typeof(*p1), head); | ||
1032 | const struct tomoyo_task_acl *p2 = container_of(b, typeof(*p2), head); | ||
1033 | return p1->domainname == p2->domainname; | ||
1034 | } | ||
1035 | |||
1036 | /** | ||
1037 | * tomoyo_write_task - Update task related list. | ||
1038 | * | ||
1039 | * @param: Pointer to "struct tomoyo_acl_param". | ||
1040 | * | ||
1041 | * Returns 0 on success, negative value otherwise. | ||
1042 | * | ||
1043 | * Caller holds tomoyo_read_lock(). | ||
1044 | */ | ||
1045 | static int tomoyo_write_task(struct tomoyo_acl_param *param) | ||
1046 | { | ||
1047 | int error = -EINVAL; | ||
1048 | if (tomoyo_str_starts(¶m->data, "manual_domain_transition ")) { | ||
1049 | struct tomoyo_task_acl e = { | ||
1050 | .head.type = TOMOYO_TYPE_MANUAL_TASK_ACL, | ||
1051 | .domainname = tomoyo_get_domainname(param), | ||
1052 | }; | ||
1053 | if (e.domainname) | ||
1054 | error = tomoyo_update_domain(&e.head, sizeof(e), param, | ||
1055 | tomoyo_same_task_acl, | ||
1056 | NULL); | ||
1057 | tomoyo_put_name(e.domainname); | ||
1058 | } | ||
1059 | return error; | ||
1060 | } | ||
1061 | |||
1062 | /** | ||
985 | * tomoyo_delete_domain - Delete a domain. | 1063 | * tomoyo_delete_domain - Delete a domain. |
986 | * | 1064 | * |
987 | * @domainname: The name of domain. | 1065 | * @domainname: The name of domain. |
@@ -1039,11 +1117,16 @@ static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns, | |||
1039 | static const struct { | 1117 | static const struct { |
1040 | const char *keyword; | 1118 | const char *keyword; |
1041 | int (*write) (struct tomoyo_acl_param *); | 1119 | int (*write) (struct tomoyo_acl_param *); |
1042 | } tomoyo_callback[1] = { | 1120 | } tomoyo_callback[5] = { |
1043 | { "file ", tomoyo_write_file }, | 1121 | { "file ", tomoyo_write_file }, |
1122 | { "network inet ", tomoyo_write_inet_network }, | ||
1123 | { "network unix ", tomoyo_write_unix_network }, | ||
1124 | { "misc ", tomoyo_write_misc }, | ||
1125 | { "task ", tomoyo_write_task }, | ||
1044 | }; | 1126 | }; |
1045 | u8 i; | 1127 | u8 i; |
1046 | for (i = 0; i < 1; i++) { | 1128 | |
1129 | for (i = 0; i < ARRAY_SIZE(tomoyo_callback); i++) { | ||
1047 | if (!tomoyo_str_starts(¶m.data, | 1130 | if (!tomoyo_str_starts(¶m.data, |
1048 | tomoyo_callback[i].keyword)) | 1131 | tomoyo_callback[i].keyword)) |
1049 | continue; | 1132 | continue; |
@@ -1127,6 +1210,10 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head, | |||
1127 | case 0: | 1210 | case 0: |
1128 | head->r.cond_index = 0; | 1211 | head->r.cond_index = 0; |
1129 | head->r.cond_step++; | 1212 | head->r.cond_step++; |
1213 | if (cond->transit) { | ||
1214 | tomoyo_set_space(head); | ||
1215 | tomoyo_set_string(head, cond->transit->name); | ||
1216 | } | ||
1130 | /* fall through */ | 1217 | /* fall through */ |
1131 | case 1: | 1218 | case 1: |
1132 | { | 1219 | { |
@@ -1239,6 +1326,10 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head, | |||
1239 | head->r.cond_step++; | 1326 | head->r.cond_step++; |
1240 | /* fall through */ | 1327 | /* fall through */ |
1241 | case 3: | 1328 | case 3: |
1329 | if (cond->grant_log != TOMOYO_GRANTLOG_AUTO) | ||
1330 | tomoyo_io_printf(head, " grant_log=%s", | ||
1331 | tomoyo_yesno(cond->grant_log == | ||
1332 | TOMOYO_GRANTLOG_YES)); | ||
1242 | tomoyo_set_lf(head); | 1333 | tomoyo_set_lf(head); |
1243 | return true; | 1334 | return true; |
1244 | } | 1335 | } |
@@ -1306,6 +1397,12 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
1306 | if (first) | 1397 | if (first) |
1307 | return true; | 1398 | return true; |
1308 | tomoyo_print_name_union(head, &ptr->name); | 1399 | tomoyo_print_name_union(head, &ptr->name); |
1400 | } else if (acl_type == TOMOYO_TYPE_MANUAL_TASK_ACL) { | ||
1401 | struct tomoyo_task_acl *ptr = | ||
1402 | container_of(acl, typeof(*ptr), head); | ||
1403 | tomoyo_set_group(head, "task "); | ||
1404 | tomoyo_set_string(head, "manual_domain_transition "); | ||
1405 | tomoyo_set_string(head, ptr->domainname->name); | ||
1309 | } else if (head->r.print_transition_related_only) { | 1406 | } else if (head->r.print_transition_related_only) { |
1310 | return true; | 1407 | return true; |
1311 | } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { | 1408 | } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { |
@@ -1370,6 +1467,60 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
1370 | tomoyo_print_number_union(head, &ptr->mode); | 1467 | tomoyo_print_number_union(head, &ptr->mode); |
1371 | tomoyo_print_number_union(head, &ptr->major); | 1468 | tomoyo_print_number_union(head, &ptr->major); |
1372 | tomoyo_print_number_union(head, &ptr->minor); | 1469 | tomoyo_print_number_union(head, &ptr->minor); |
1470 | } else if (acl_type == TOMOYO_TYPE_INET_ACL) { | ||
1471 | struct tomoyo_inet_acl *ptr = | ||
1472 | container_of(acl, typeof(*ptr), head); | ||
1473 | const u8 perm = ptr->perm; | ||
1474 | |||
1475 | for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) { | ||
1476 | if (!(perm & (1 << bit))) | ||
1477 | continue; | ||
1478 | if (first) { | ||
1479 | tomoyo_set_group(head, "network inet "); | ||
1480 | tomoyo_set_string(head, tomoyo_proto_keyword | ||
1481 | [ptr->protocol]); | ||
1482 | tomoyo_set_space(head); | ||
1483 | first = false; | ||
1484 | } else { | ||
1485 | tomoyo_set_slash(head); | ||
1486 | } | ||
1487 | tomoyo_set_string(head, tomoyo_socket_keyword[bit]); | ||
1488 | } | ||
1489 | if (first) | ||
1490 | return true; | ||
1491 | tomoyo_set_space(head); | ||
1492 | if (ptr->address.group) { | ||
1493 | tomoyo_set_string(head, "@"); | ||
1494 | tomoyo_set_string(head, ptr->address.group->group_name | ||
1495 | ->name); | ||
1496 | } else { | ||
1497 | char buf[128]; | ||
1498 | tomoyo_print_ip(buf, sizeof(buf), &ptr->address); | ||
1499 | tomoyo_io_printf(head, "%s", buf); | ||
1500 | } | ||
1501 | tomoyo_print_number_union(head, &ptr->port); | ||
1502 | } else if (acl_type == TOMOYO_TYPE_UNIX_ACL) { | ||
1503 | struct tomoyo_unix_acl *ptr = | ||
1504 | container_of(acl, typeof(*ptr), head); | ||
1505 | const u8 perm = ptr->perm; | ||
1506 | |||
1507 | for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) { | ||
1508 | if (!(perm & (1 << bit))) | ||
1509 | continue; | ||
1510 | if (first) { | ||
1511 | tomoyo_set_group(head, "network unix "); | ||
1512 | tomoyo_set_string(head, tomoyo_proto_keyword | ||
1513 | [ptr->protocol]); | ||
1514 | tomoyo_set_space(head); | ||
1515 | first = false; | ||
1516 | } else { | ||
1517 | tomoyo_set_slash(head); | ||
1518 | } | ||
1519 | tomoyo_set_string(head, tomoyo_socket_keyword[bit]); | ||
1520 | } | ||
1521 | if (first) | ||
1522 | return true; | ||
1523 | tomoyo_print_name_union(head, &ptr->name); | ||
1373 | } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { | 1524 | } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { |
1374 | struct tomoyo_mount_acl *ptr = | 1525 | struct tomoyo_mount_acl *ptr = |
1375 | container_of(acl, typeof(*ptr), head); | 1526 | container_of(acl, typeof(*ptr), head); |
@@ -1378,6 +1529,12 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
1378 | tomoyo_print_name_union(head, &ptr->dir_name); | 1529 | tomoyo_print_name_union(head, &ptr->dir_name); |
1379 | tomoyo_print_name_union(head, &ptr->fs_type); | 1530 | tomoyo_print_name_union(head, &ptr->fs_type); |
1380 | tomoyo_print_number_union(head, &ptr->flags); | 1531 | tomoyo_print_number_union(head, &ptr->flags); |
1532 | } else if (acl_type == TOMOYO_TYPE_ENV_ACL) { | ||
1533 | struct tomoyo_env_acl *ptr = | ||
1534 | container_of(acl, typeof(*ptr), head); | ||
1535 | |||
1536 | tomoyo_set_group(head, "misc env "); | ||
1537 | tomoyo_set_string(head, ptr->env->name); | ||
1381 | } | 1538 | } |
1382 | if (acl->cond) { | 1539 | if (acl->cond) { |
1383 | head->r.print_cond_part = true; | 1540 | head->r.print_cond_part = true; |
@@ -1510,14 +1667,12 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head) | |||
1510 | global_pid = true; | 1667 | global_pid = true; |
1511 | pid = (unsigned int) simple_strtoul(buf, NULL, 10); | 1668 | pid = (unsigned int) simple_strtoul(buf, NULL, 10); |
1512 | rcu_read_lock(); | 1669 | rcu_read_lock(); |
1513 | read_lock(&tasklist_lock); | ||
1514 | if (global_pid) | 1670 | if (global_pid) |
1515 | p = find_task_by_pid_ns(pid, &init_pid_ns); | 1671 | p = find_task_by_pid_ns(pid, &init_pid_ns); |
1516 | else | 1672 | else |
1517 | p = find_task_by_vpid(pid); | 1673 | p = find_task_by_vpid(pid); |
1518 | if (p) | 1674 | if (p) |
1519 | domain = tomoyo_real_domain(p); | 1675 | domain = tomoyo_real_domain(p); |
1520 | read_unlock(&tasklist_lock); | ||
1521 | rcu_read_unlock(); | 1676 | rcu_read_unlock(); |
1522 | if (!domain) | 1677 | if (!domain) |
1523 | return; | 1678 | return; |
@@ -1537,8 +1692,9 @@ static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { | |||
1537 | 1692 | ||
1538 | /* String table for grouping keywords. */ | 1693 | /* String table for grouping keywords. */ |
1539 | static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { | 1694 | static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { |
1540 | [TOMOYO_PATH_GROUP] = "path_group ", | 1695 | [TOMOYO_PATH_GROUP] = "path_group ", |
1541 | [TOMOYO_NUMBER_GROUP] = "number_group ", | 1696 | [TOMOYO_NUMBER_GROUP] = "number_group ", |
1697 | [TOMOYO_ADDRESS_GROUP] = "address_group ", | ||
1542 | }; | 1698 | }; |
1543 | 1699 | ||
1544 | /** | 1700 | /** |
@@ -1580,7 +1736,7 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) | |||
1580 | } | 1736 | } |
1581 | 1737 | ||
1582 | /** | 1738 | /** |
1583 | * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group" list. | 1739 | * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" list. |
1584 | * | 1740 | * |
1585 | * @head: Pointer to "struct tomoyo_io_buffer". | 1741 | * @head: Pointer to "struct tomoyo_io_buffer". |
1586 | * @idx: Index number. | 1742 | * @idx: Index number. |
@@ -1617,6 +1773,15 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | |||
1617 | (ptr, | 1773 | (ptr, |
1618 | struct tomoyo_number_group, | 1774 | struct tomoyo_number_group, |
1619 | head)->number); | 1775 | head)->number); |
1776 | } else if (idx == TOMOYO_ADDRESS_GROUP) { | ||
1777 | char buffer[128]; | ||
1778 | |||
1779 | struct tomoyo_address_group *member = | ||
1780 | container_of(ptr, typeof(*member), | ||
1781 | head); | ||
1782 | tomoyo_print_ip(buffer, sizeof(buffer), | ||
1783 | &member->address); | ||
1784 | tomoyo_io_printf(head, " %s", buffer); | ||
1620 | } | 1785 | } |
1621 | tomoyo_set_lf(head); | 1786 | tomoyo_set_lf(head); |
1622 | } | 1787 | } |
@@ -2066,27 +2231,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head) | |||
2066 | static void tomoyo_read_version(struct tomoyo_io_buffer *head) | 2231 | static void tomoyo_read_version(struct tomoyo_io_buffer *head) |
2067 | { | 2232 | { |
2068 | if (!head->r.eof) { | 2233 | if (!head->r.eof) { |
2069 | tomoyo_io_printf(head, "2.4.0"); | 2234 | tomoyo_io_printf(head, "2.5.0"); |
2070 | head->r.eof = true; | ||
2071 | } | ||
2072 | } | ||
2073 | |||
2074 | /** | ||
2075 | * tomoyo_read_self_domain - Get the current process's domainname. | ||
2076 | * | ||
2077 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
2078 | * | ||
2079 | * Returns the current process's domainname. | ||
2080 | */ | ||
2081 | static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head) | ||
2082 | { | ||
2083 | if (!head->r.eof) { | ||
2084 | /* | ||
2085 | * tomoyo_domain()->domainname != NULL | ||
2086 | * because every process belongs to a domain and | ||
2087 | * the domain's name cannot be NULL. | ||
2088 | */ | ||
2089 | tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name); | ||
2090 | head->r.eof = true; | 2235 | head->r.eof = true; |
2091 | } | 2236 | } |
2092 | } | 2237 | } |
@@ -2221,10 +2366,6 @@ int tomoyo_open_control(const u8 type, struct file *file) | |||
2221 | head->poll = tomoyo_poll_log; | 2366 | head->poll = tomoyo_poll_log; |
2222 | head->read = tomoyo_read_log; | 2367 | head->read = tomoyo_read_log; |
2223 | break; | 2368 | break; |
2224 | case TOMOYO_SELFDOMAIN: | ||
2225 | /* /sys/kernel/security/tomoyo/self_domain */ | ||
2226 | head->read = tomoyo_read_self_domain; | ||
2227 | break; | ||
2228 | case TOMOYO_PROCESS_STATUS: | 2369 | case TOMOYO_PROCESS_STATUS: |
2229 | /* /sys/kernel/security/tomoyo/.process_status */ | 2370 | /* /sys/kernel/security/tomoyo/.process_status */ |
2230 | head->write = tomoyo_write_pid; | 2371 | head->write = tomoyo_write_pid; |
@@ -2453,6 +2594,7 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, | |||
2453 | return -EFAULT; | 2594 | return -EFAULT; |
2454 | if (mutex_lock_interruptible(&head->io_sem)) | 2595 | if (mutex_lock_interruptible(&head->io_sem)) |
2455 | return -EINTR; | 2596 | return -EINTR; |
2597 | head->read_user_buf_avail = 0; | ||
2456 | idx = tomoyo_read_lock(); | 2598 | idx = tomoyo_read_lock(); |
2457 | /* Read a line and dispatch it to the policy handler. */ | 2599 | /* Read a line and dispatch it to the policy handler. */ |
2458 | while (avail_len > 0) { | 2600 | while (avail_len > 0) { |
@@ -2562,11 +2704,11 @@ void tomoyo_check_profile(void) | |||
2562 | struct tomoyo_domain_info *domain; | 2704 | struct tomoyo_domain_info *domain; |
2563 | const int idx = tomoyo_read_lock(); | 2705 | const int idx = tomoyo_read_lock(); |
2564 | tomoyo_policy_loaded = true; | 2706 | tomoyo_policy_loaded = true; |
2565 | printk(KERN_INFO "TOMOYO: 2.4.0\n"); | 2707 | printk(KERN_INFO "TOMOYO: 2.5.0\n"); |
2566 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 2708 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
2567 | const u8 profile = domain->profile; | 2709 | const u8 profile = domain->profile; |
2568 | const struct tomoyo_policy_namespace *ns = domain->ns; | 2710 | const struct tomoyo_policy_namespace *ns = domain->ns; |
2569 | if (ns->profile_version != 20100903) | 2711 | if (ns->profile_version != 20110903) |
2570 | printk(KERN_ERR | 2712 | printk(KERN_ERR |
2571 | "Profile version %u is not supported.\n", | 2713 | "Profile version %u is not supported.\n", |
2572 | ns->profile_version); | 2714 | ns->profile_version); |
@@ -2577,9 +2719,9 @@ void tomoyo_check_profile(void) | |||
2577 | else | 2719 | else |
2578 | continue; | 2720 | continue; |
2579 | printk(KERN_ERR | 2721 | printk(KERN_ERR |
2580 | "Userland tools for TOMOYO 2.4 must be installed and " | 2722 | "Userland tools for TOMOYO 2.5 must be installed and " |
2581 | "policy must be initialized.\n"); | 2723 | "policy must be initialized.\n"); |
2582 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.4/ " | 2724 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.5/ " |
2583 | "for more information.\n"); | 2725 | "for more information.\n"); |
2584 | panic("STOP!"); | 2726 | panic("STOP!"); |
2585 | } | 2727 | } |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index f7fbaa66e443..ed311d7a8ce0 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Header file for TOMOYO. | 4 | * Header file for TOMOYO. |
5 | * | 5 | * |
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | 6 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #ifndef _SECURITY_TOMOYO_COMMON_H | 9 | #ifndef _SECURITY_TOMOYO_COMMON_H |
@@ -23,6 +23,16 @@ | |||
23 | #include <linux/poll.h> | 23 | #include <linux/poll.h> |
24 | #include <linux/binfmts.h> | 24 | #include <linux/binfmts.h> |
25 | #include <linux/highmem.h> | 25 | #include <linux/highmem.h> |
26 | #include <linux/net.h> | ||
27 | #include <linux/inet.h> | ||
28 | #include <linux/in.h> | ||
29 | #include <linux/in6.h> | ||
30 | #include <linux/un.h> | ||
31 | #include <net/sock.h> | ||
32 | #include <net/af_unix.h> | ||
33 | #include <net/ip.h> | ||
34 | #include <net/ipv6.h> | ||
35 | #include <net/udp.h> | ||
26 | 36 | ||
27 | /********** Constants definitions. **********/ | 37 | /********** Constants definitions. **********/ |
28 | 38 | ||
@@ -34,8 +44,17 @@ | |||
34 | #define TOMOYO_HASH_BITS 8 | 44 | #define TOMOYO_HASH_BITS 8 |
35 | #define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS) | 45 | #define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS) |
36 | 46 | ||
47 | /* | ||
48 | * TOMOYO checks only SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET. | ||
49 | * Therefore, we don't need SOCK_MAX. | ||
50 | */ | ||
51 | #define TOMOYO_SOCK_MAX 6 | ||
52 | |||
37 | #define TOMOYO_EXEC_TMPSIZE 4096 | 53 | #define TOMOYO_EXEC_TMPSIZE 4096 |
38 | 54 | ||
55 | /* Garbage collector is trying to kfree() this element. */ | ||
56 | #define TOMOYO_GC_IN_PROGRESS -1 | ||
57 | |||
39 | /* Profile number is an integer between 0 and 255. */ | 58 | /* Profile number is an integer between 0 and 255. */ |
40 | #define TOMOYO_MAX_PROFILES 256 | 59 | #define TOMOYO_MAX_PROFILES 256 |
41 | 60 | ||
@@ -136,6 +155,7 @@ enum tomoyo_mode_index { | |||
136 | /* Index numbers for entry type. */ | 155 | /* Index numbers for entry type. */ |
137 | enum tomoyo_policy_id { | 156 | enum tomoyo_policy_id { |
138 | TOMOYO_ID_GROUP, | 157 | TOMOYO_ID_GROUP, |
158 | TOMOYO_ID_ADDRESS_GROUP, | ||
139 | TOMOYO_ID_PATH_GROUP, | 159 | TOMOYO_ID_PATH_GROUP, |
140 | TOMOYO_ID_NUMBER_GROUP, | 160 | TOMOYO_ID_NUMBER_GROUP, |
141 | TOMOYO_ID_TRANSITION_CONTROL, | 161 | TOMOYO_ID_TRANSITION_CONTROL, |
@@ -162,10 +182,21 @@ enum tomoyo_domain_info_flags_index { | |||
162 | TOMOYO_MAX_DOMAIN_INFO_FLAGS | 182 | TOMOYO_MAX_DOMAIN_INFO_FLAGS |
163 | }; | 183 | }; |
164 | 184 | ||
185 | /* Index numbers for audit type. */ | ||
186 | enum tomoyo_grant_log { | ||
187 | /* Follow profile's configuration. */ | ||
188 | TOMOYO_GRANTLOG_AUTO, | ||
189 | /* Do not generate grant log. */ | ||
190 | TOMOYO_GRANTLOG_NO, | ||
191 | /* Generate grant_log. */ | ||
192 | TOMOYO_GRANTLOG_YES, | ||
193 | }; | ||
194 | |||
165 | /* Index numbers for group entries. */ | 195 | /* Index numbers for group entries. */ |
166 | enum tomoyo_group_id { | 196 | enum tomoyo_group_id { |
167 | TOMOYO_PATH_GROUP, | 197 | TOMOYO_PATH_GROUP, |
168 | TOMOYO_NUMBER_GROUP, | 198 | TOMOYO_NUMBER_GROUP, |
199 | TOMOYO_ADDRESS_GROUP, | ||
169 | TOMOYO_MAX_GROUP | 200 | TOMOYO_MAX_GROUP |
170 | }; | 201 | }; |
171 | 202 | ||
@@ -196,6 +227,10 @@ enum tomoyo_acl_entry_type_index { | |||
196 | TOMOYO_TYPE_PATH_NUMBER_ACL, | 227 | TOMOYO_TYPE_PATH_NUMBER_ACL, |
197 | TOMOYO_TYPE_MKDEV_ACL, | 228 | TOMOYO_TYPE_MKDEV_ACL, |
198 | TOMOYO_TYPE_MOUNT_ACL, | 229 | TOMOYO_TYPE_MOUNT_ACL, |
230 | TOMOYO_TYPE_INET_ACL, | ||
231 | TOMOYO_TYPE_UNIX_ACL, | ||
232 | TOMOYO_TYPE_ENV_ACL, | ||
233 | TOMOYO_TYPE_MANUAL_TASK_ACL, | ||
199 | }; | 234 | }; |
200 | 235 | ||
201 | /* Index numbers for access controls with one pathname. */ | 236 | /* Index numbers for access controls with one pathname. */ |
@@ -228,6 +263,15 @@ enum tomoyo_mkdev_acl_index { | |||
228 | TOMOYO_MAX_MKDEV_OPERATION | 263 | TOMOYO_MAX_MKDEV_OPERATION |
229 | }; | 264 | }; |
230 | 265 | ||
266 | /* Index numbers for socket operations. */ | ||
267 | enum tomoyo_network_acl_index { | ||
268 | TOMOYO_NETWORK_BIND, /* bind() operation. */ | ||
269 | TOMOYO_NETWORK_LISTEN, /* listen() operation. */ | ||
270 | TOMOYO_NETWORK_CONNECT, /* connect() operation. */ | ||
271 | TOMOYO_NETWORK_SEND, /* send() operation. */ | ||
272 | TOMOYO_MAX_NETWORK_OPERATION | ||
273 | }; | ||
274 | |||
231 | /* Index numbers for access controls with two pathnames. */ | 275 | /* Index numbers for access controls with two pathnames. */ |
232 | enum tomoyo_path2_acl_index { | 276 | enum tomoyo_path2_acl_index { |
233 | TOMOYO_TYPE_LINK, | 277 | TOMOYO_TYPE_LINK, |
@@ -255,7 +299,6 @@ enum tomoyo_securityfs_interface_index { | |||
255 | TOMOYO_EXCEPTIONPOLICY, | 299 | TOMOYO_EXCEPTIONPOLICY, |
256 | TOMOYO_PROCESS_STATUS, | 300 | TOMOYO_PROCESS_STATUS, |
257 | TOMOYO_STAT, | 301 | TOMOYO_STAT, |
258 | TOMOYO_SELFDOMAIN, | ||
259 | TOMOYO_AUDIT, | 302 | TOMOYO_AUDIT, |
260 | TOMOYO_VERSION, | 303 | TOMOYO_VERSION, |
261 | TOMOYO_PROFILE, | 304 | TOMOYO_PROFILE, |
@@ -300,12 +343,30 @@ enum tomoyo_mac_index { | |||
300 | TOMOYO_MAC_FILE_MOUNT, | 343 | TOMOYO_MAC_FILE_MOUNT, |
301 | TOMOYO_MAC_FILE_UMOUNT, | 344 | TOMOYO_MAC_FILE_UMOUNT, |
302 | TOMOYO_MAC_FILE_PIVOT_ROOT, | 345 | TOMOYO_MAC_FILE_PIVOT_ROOT, |
346 | TOMOYO_MAC_NETWORK_INET_STREAM_BIND, | ||
347 | TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN, | ||
348 | TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT, | ||
349 | TOMOYO_MAC_NETWORK_INET_DGRAM_BIND, | ||
350 | TOMOYO_MAC_NETWORK_INET_DGRAM_SEND, | ||
351 | TOMOYO_MAC_NETWORK_INET_RAW_BIND, | ||
352 | TOMOYO_MAC_NETWORK_INET_RAW_SEND, | ||
353 | TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND, | ||
354 | TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN, | ||
355 | TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT, | ||
356 | TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND, | ||
357 | TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND, | ||
358 | TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND, | ||
359 | TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN, | ||
360 | TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT, | ||
361 | TOMOYO_MAC_ENVIRON, | ||
303 | TOMOYO_MAX_MAC_INDEX | 362 | TOMOYO_MAX_MAC_INDEX |
304 | }; | 363 | }; |
305 | 364 | ||
306 | /* Index numbers for category of functionality. */ | 365 | /* Index numbers for category of functionality. */ |
307 | enum tomoyo_mac_category_index { | 366 | enum tomoyo_mac_category_index { |
308 | TOMOYO_MAC_CATEGORY_FILE, | 367 | TOMOYO_MAC_CATEGORY_FILE, |
368 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
369 | TOMOYO_MAC_CATEGORY_MISC, | ||
309 | TOMOYO_MAX_MAC_CATEGORY_INDEX | 370 | TOMOYO_MAX_MAC_CATEGORY_INDEX |
310 | }; | 371 | }; |
311 | 372 | ||
@@ -340,7 +401,7 @@ enum tomoyo_pref_index { | |||
340 | /* Common header for holding ACL entries. */ | 401 | /* Common header for holding ACL entries. */ |
341 | struct tomoyo_acl_head { | 402 | struct tomoyo_acl_head { |
342 | struct list_head list; | 403 | struct list_head list; |
343 | bool is_deleted; | 404 | s8 is_deleted; /* true or false or TOMOYO_GC_IN_PROGRESS */ |
344 | } __packed; | 405 | } __packed; |
345 | 406 | ||
346 | /* Common header for shared entries. */ | 407 | /* Common header for shared entries. */ |
@@ -397,13 +458,36 @@ struct tomoyo_request_info { | |||
397 | u8 operation; | 458 | u8 operation; |
398 | } path_number; | 459 | } path_number; |
399 | struct { | 460 | struct { |
461 | const struct tomoyo_path_info *name; | ||
462 | } environ; | ||
463 | struct { | ||
464 | const __be32 *address; | ||
465 | u16 port; | ||
466 | /* One of values smaller than TOMOYO_SOCK_MAX. */ | ||
467 | u8 protocol; | ||
468 | /* One of values in "enum tomoyo_network_acl_index". */ | ||
469 | u8 operation; | ||
470 | bool is_ipv6; | ||
471 | } inet_network; | ||
472 | struct { | ||
473 | const struct tomoyo_path_info *address; | ||
474 | /* One of values smaller than TOMOYO_SOCK_MAX. */ | ||
475 | u8 protocol; | ||
476 | /* One of values in "enum tomoyo_network_acl_index". */ | ||
477 | u8 operation; | ||
478 | } unix_network; | ||
479 | struct { | ||
400 | const struct tomoyo_path_info *type; | 480 | const struct tomoyo_path_info *type; |
401 | const struct tomoyo_path_info *dir; | 481 | const struct tomoyo_path_info *dir; |
402 | const struct tomoyo_path_info *dev; | 482 | const struct tomoyo_path_info *dev; |
403 | unsigned long flags; | 483 | unsigned long flags; |
404 | int need_dev; | 484 | int need_dev; |
405 | } mount; | 485 | } mount; |
486 | struct { | ||
487 | const struct tomoyo_path_info *domainname; | ||
488 | } task; | ||
406 | } param; | 489 | } param; |
490 | struct tomoyo_acl_info *matched_acl; | ||
407 | u8 param_type; | 491 | u8 param_type; |
408 | bool granted; | 492 | bool granted; |
409 | u8 retry; | 493 | u8 retry; |
@@ -442,7 +526,14 @@ struct tomoyo_number_union { | |||
442 | u8 value_type[2]; | 526 | u8 value_type[2]; |
443 | }; | 527 | }; |
444 | 528 | ||
445 | /* Structure for "path_group"/"number_group" directive. */ | 529 | /* Structure for holding an IP address. */ |
530 | struct tomoyo_ipaddr_union { | ||
531 | struct in6_addr ip[2]; /* Big endian. */ | ||
532 | struct tomoyo_group *group; /* Pointer to address group. */ | ||
533 | bool is_ipv6; /* Valid only if @group == NULL. */ | ||
534 | }; | ||
535 | |||
536 | /* Structure for "path_group"/"number_group"/"address_group" directive. */ | ||
446 | struct tomoyo_group { | 537 | struct tomoyo_group { |
447 | struct tomoyo_shared_acl_head head; | 538 | struct tomoyo_shared_acl_head head; |
448 | const struct tomoyo_path_info *group_name; | 539 | const struct tomoyo_path_info *group_name; |
@@ -461,6 +552,13 @@ struct tomoyo_number_group { | |||
461 | struct tomoyo_number_union number; | 552 | struct tomoyo_number_union number; |
462 | }; | 553 | }; |
463 | 554 | ||
555 | /* Structure for "address_group" directive. */ | ||
556 | struct tomoyo_address_group { | ||
557 | struct tomoyo_acl_head head; | ||
558 | /* Structure for holding an IP address. */ | ||
559 | struct tomoyo_ipaddr_union address; | ||
560 | }; | ||
561 | |||
464 | /* Subset of "struct stat". Used by conditional ACL and audit logs. */ | 562 | /* Subset of "struct stat". Used by conditional ACL and audit logs. */ |
465 | struct tomoyo_mini_stat { | 563 | struct tomoyo_mini_stat { |
466 | uid_t uid; | 564 | uid_t uid; |
@@ -520,6 +618,7 @@ struct tomoyo_execve { | |||
520 | struct tomoyo_request_info r; | 618 | struct tomoyo_request_info r; |
521 | struct tomoyo_obj_info obj; | 619 | struct tomoyo_obj_info obj; |
522 | struct linux_binprm *bprm; | 620 | struct linux_binprm *bprm; |
621 | const struct tomoyo_path_info *transition; | ||
523 | /* For dumping argv[] and envp[]. */ | 622 | /* For dumping argv[] and envp[]. */ |
524 | struct tomoyo_page_dump dump; | 623 | struct tomoyo_page_dump dump; |
525 | /* For temporary use. */ | 624 | /* For temporary use. */ |
@@ -554,6 +653,8 @@ struct tomoyo_condition { | |||
554 | u16 names_count; /* Number of "struct tomoyo_name_union names". */ | 653 | u16 names_count; /* Number of "struct tomoyo_name_union names". */ |
555 | u16 argc; /* Number of "struct tomoyo_argv". */ | 654 | u16 argc; /* Number of "struct tomoyo_argv". */ |
556 | u16 envc; /* Number of "struct tomoyo_envp". */ | 655 | u16 envc; /* Number of "struct tomoyo_envp". */ |
656 | u8 grant_log; /* One of values in "enum tomoyo_grant_log". */ | ||
657 | const struct tomoyo_path_info *transit; /* Maybe NULL. */ | ||
557 | /* | 658 | /* |
558 | * struct tomoyo_condition_element condition[condc]; | 659 | * struct tomoyo_condition_element condition[condc]; |
559 | * struct tomoyo_number_union values[numbers_count]; | 660 | * struct tomoyo_number_union values[numbers_count]; |
@@ -567,7 +668,7 @@ struct tomoyo_condition { | |||
567 | struct tomoyo_acl_info { | 668 | struct tomoyo_acl_info { |
568 | struct list_head list; | 669 | struct list_head list; |
569 | struct tomoyo_condition *cond; /* Maybe NULL. */ | 670 | struct tomoyo_condition *cond; /* Maybe NULL. */ |
570 | bool is_deleted; | 671 | s8 is_deleted; /* true or false or TOMOYO_GC_IN_PROGRESS */ |
571 | u8 type; /* One of values in "enum tomoyo_acl_entry_type_index". */ | 672 | u8 type; /* One of values in "enum tomoyo_acl_entry_type_index". */ |
572 | } __packed; | 673 | } __packed; |
573 | 674 | ||
@@ -587,6 +688,15 @@ struct tomoyo_domain_info { | |||
587 | }; | 688 | }; |
588 | 689 | ||
589 | /* | 690 | /* |
691 | * Structure for "task manual_domain_transition" directive. | ||
692 | */ | ||
693 | struct tomoyo_task_acl { | ||
694 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MANUAL_TASK_ACL */ | ||
695 | /* Pointer to domainname. */ | ||
696 | const struct tomoyo_path_info *domainname; | ||
697 | }; | ||
698 | |||
699 | /* | ||
590 | * Structure for "file execute", "file read", "file write", "file append", | 700 | * Structure for "file execute", "file read", "file write", "file append", |
591 | * "file unlink", "file getattr", "file rmdir", "file truncate", | 701 | * "file unlink", "file getattr", "file rmdir", "file truncate", |
592 | * "file symlink", "file chroot" and "file unmount" directive. | 702 | * "file symlink", "file chroot" and "file unmount" directive. |
@@ -638,6 +748,29 @@ struct tomoyo_mount_acl { | |||
638 | struct tomoyo_number_union flags; | 748 | struct tomoyo_number_union flags; |
639 | }; | 749 | }; |
640 | 750 | ||
751 | /* Structure for "misc env" directive in domain policy. */ | ||
752 | struct tomoyo_env_acl { | ||
753 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_ENV_ACL */ | ||
754 | const struct tomoyo_path_info *env; /* environment variable */ | ||
755 | }; | ||
756 | |||
757 | /* Structure for "network inet" directive. */ | ||
758 | struct tomoyo_inet_acl { | ||
759 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_INET_ACL */ | ||
760 | u8 protocol; | ||
761 | u8 perm; /* Bitmask of values in "enum tomoyo_network_acl_index" */ | ||
762 | struct tomoyo_ipaddr_union address; | ||
763 | struct tomoyo_number_union port; | ||
764 | }; | ||
765 | |||
766 | /* Structure for "network unix" directive. */ | ||
767 | struct tomoyo_unix_acl { | ||
768 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_UNIX_ACL */ | ||
769 | u8 protocol; | ||
770 | u8 perm; /* Bitmask of values in "enum tomoyo_network_acl_index" */ | ||
771 | struct tomoyo_name_union name; | ||
772 | }; | ||
773 | |||
641 | /* Structure for holding a line from /sys/kernel/security/tomoyo/ interface. */ | 774 | /* Structure for holding a line from /sys/kernel/security/tomoyo/ interface. */ |
642 | struct tomoyo_acl_param { | 775 | struct tomoyo_acl_param { |
643 | char *data; | 776 | char *data; |
@@ -773,7 +906,7 @@ struct tomoyo_policy_namespace { | |||
773 | struct list_head acl_group[TOMOYO_MAX_ACL_GROUPS]; | 906 | struct list_head acl_group[TOMOYO_MAX_ACL_GROUPS]; |
774 | /* List for connecting to tomoyo_namespace_list list. */ | 907 | /* List for connecting to tomoyo_namespace_list list. */ |
775 | struct list_head namespace_list; | 908 | struct list_head namespace_list; |
776 | /* Profile version. Currently only 20100903 is defined. */ | 909 | /* Profile version. Currently only 20110903 is defined. */ |
777 | unsigned int profile_version; | 910 | unsigned int profile_version; |
778 | /* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */ | 911 | /* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */ |
779 | const char *name; | 912 | const char *name; |
@@ -781,6 +914,8 @@ struct tomoyo_policy_namespace { | |||
781 | 914 | ||
782 | /********** Function prototypes. **********/ | 915 | /********** Function prototypes. **********/ |
783 | 916 | ||
917 | bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address, | ||
918 | const struct tomoyo_group *group); | ||
784 | bool tomoyo_compare_number_union(const unsigned long value, | 919 | bool tomoyo_compare_number_union(const unsigned long value, |
785 | const struct tomoyo_number_union *ptr); | 920 | const struct tomoyo_number_union *ptr); |
786 | bool tomoyo_condition(struct tomoyo_request_info *r, | 921 | bool tomoyo_condition(struct tomoyo_request_info *r, |
@@ -796,6 +931,8 @@ bool tomoyo_memory_ok(void *ptr); | |||
796 | bool tomoyo_number_matches_group(const unsigned long min, | 931 | bool tomoyo_number_matches_group(const unsigned long min, |
797 | const unsigned long max, | 932 | const unsigned long max, |
798 | const struct tomoyo_group *group); | 933 | const struct tomoyo_group *group); |
934 | bool tomoyo_parse_ipaddr_union(struct tomoyo_acl_param *param, | ||
935 | struct tomoyo_ipaddr_union *ptr); | ||
799 | bool tomoyo_parse_name_union(struct tomoyo_acl_param *param, | 936 | bool tomoyo_parse_name_union(struct tomoyo_acl_param *param, |
800 | struct tomoyo_name_union *ptr); | 937 | struct tomoyo_name_union *ptr); |
801 | bool tomoyo_parse_number_union(struct tomoyo_acl_param *param, | 938 | bool tomoyo_parse_number_union(struct tomoyo_acl_param *param, |
@@ -805,6 +942,7 @@ bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, | |||
805 | bool tomoyo_permstr(const char *string, const char *keyword); | 942 | bool tomoyo_permstr(const char *string, const char *keyword); |
806 | bool tomoyo_str_starts(char **src, const char *find); | 943 | bool tomoyo_str_starts(char **src, const char *find); |
807 | char *tomoyo_encode(const char *str); | 944 | char *tomoyo_encode(const char *str); |
945 | char *tomoyo_encode2(const char *str, int str_len); | ||
808 | char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt, | 946 | char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt, |
809 | va_list args); | 947 | va_list args); |
810 | char *tomoyo_read_token(struct tomoyo_acl_param *param); | 948 | char *tomoyo_read_token(struct tomoyo_acl_param *param); |
@@ -814,12 +952,17 @@ const char *tomoyo_get_exe(void); | |||
814 | const char *tomoyo_yesno(const unsigned int value); | 952 | const char *tomoyo_yesno(const unsigned int value); |
815 | const struct tomoyo_path_info *tomoyo_compare_name_union | 953 | const struct tomoyo_path_info *tomoyo_compare_name_union |
816 | (const struct tomoyo_path_info *name, const struct tomoyo_name_union *ptr); | 954 | (const struct tomoyo_path_info *name, const struct tomoyo_name_union *ptr); |
955 | const struct tomoyo_path_info *tomoyo_get_domainname | ||
956 | (struct tomoyo_acl_param *param); | ||
817 | const struct tomoyo_path_info *tomoyo_get_name(const char *name); | 957 | const struct tomoyo_path_info *tomoyo_get_name(const char *name); |
818 | const struct tomoyo_path_info *tomoyo_path_matches_group | 958 | const struct tomoyo_path_info *tomoyo_path_matches_group |
819 | (const struct tomoyo_path_info *pathname, const struct tomoyo_group *group); | 959 | (const struct tomoyo_path_info *pathname, const struct tomoyo_group *group); |
820 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | 960 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, |
821 | struct path *path, const int flag); | 961 | struct path *path, const int flag); |
822 | int tomoyo_close_control(struct tomoyo_io_buffer *head); | 962 | int tomoyo_close_control(struct tomoyo_io_buffer *head); |
963 | int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env); | ||
964 | int tomoyo_execute_permission(struct tomoyo_request_info *r, | ||
965 | const struct tomoyo_path_info *filename); | ||
823 | int tomoyo_find_next_domain(struct linux_binprm *bprm); | 966 | int tomoyo_find_next_domain(struct linux_binprm *bprm); |
824 | int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, | 967 | int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, |
825 | const u8 index); | 968 | const u8 index); |
@@ -838,10 +981,15 @@ int tomoyo_path_number_perm(const u8 operation, struct path *path, | |||
838 | unsigned long number); | 981 | unsigned long number); |
839 | int tomoyo_path_perm(const u8 operation, struct path *path, | 982 | int tomoyo_path_perm(const u8 operation, struct path *path, |
840 | const char *target); | 983 | const char *target); |
841 | int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | ||
842 | const struct tomoyo_path_info *filename); | ||
843 | int tomoyo_poll_control(struct file *file, poll_table *wait); | 984 | int tomoyo_poll_control(struct file *file, poll_table *wait); |
844 | int tomoyo_poll_log(struct file *file, poll_table *wait); | 985 | int tomoyo_poll_log(struct file *file, poll_table *wait); |
986 | int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr, | ||
987 | int addr_len); | ||
988 | int tomoyo_socket_connect_permission(struct socket *sock, | ||
989 | struct sockaddr *addr, int addr_len); | ||
990 | int tomoyo_socket_listen_permission(struct socket *sock); | ||
991 | int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg, | ||
992 | int size); | ||
845 | int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) | 993 | int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) |
846 | __printf(2, 3); | 994 | __printf(2, 3); |
847 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | 995 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, |
@@ -860,8 +1008,11 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, | |||
860 | int tomoyo_write_aggregator(struct tomoyo_acl_param *param); | 1008 | int tomoyo_write_aggregator(struct tomoyo_acl_param *param); |
861 | int tomoyo_write_file(struct tomoyo_acl_param *param); | 1009 | int tomoyo_write_file(struct tomoyo_acl_param *param); |
862 | int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type); | 1010 | int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type); |
1011 | int tomoyo_write_misc(struct tomoyo_acl_param *param); | ||
1012 | int tomoyo_write_inet_network(struct tomoyo_acl_param *param); | ||
863 | int tomoyo_write_transition_control(struct tomoyo_acl_param *param, | 1013 | int tomoyo_write_transition_control(struct tomoyo_acl_param *param, |
864 | const u8 type); | 1014 | const u8 type); |
1015 | int tomoyo_write_unix_network(struct tomoyo_acl_param *param); | ||
865 | ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer, | 1016 | ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer, |
866 | const int buffer_len); | 1017 | const int buffer_len); |
867 | ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, | 1018 | ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, |
@@ -891,12 +1042,11 @@ void tomoyo_del_condition(struct list_head *element); | |||
891 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); | 1042 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); |
892 | void tomoyo_get_attributes(struct tomoyo_obj_info *obj); | 1043 | void tomoyo_get_attributes(struct tomoyo_obj_info *obj); |
893 | void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns); | 1044 | void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns); |
894 | void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | ||
895 | __printf(2, 3); | ||
896 | void tomoyo_load_policy(const char *filename); | 1045 | void tomoyo_load_policy(const char *filename); |
897 | void tomoyo_memory_free(void *ptr); | ||
898 | void tomoyo_normalize_line(unsigned char *buffer); | 1046 | void tomoyo_normalize_line(unsigned char *buffer); |
899 | void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register); | 1047 | void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register); |
1048 | void tomoyo_print_ip(char *buf, const unsigned int size, | ||
1049 | const struct tomoyo_ipaddr_union *ptr); | ||
900 | void tomoyo_print_ulong(char *buffer, const int buffer_len, | 1050 | void tomoyo_print_ulong(char *buffer, const int buffer_len, |
901 | const unsigned long value, const u8 type); | 1051 | const unsigned long value, const u8 type); |
902 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr); | 1052 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr); |
@@ -919,6 +1069,8 @@ extern const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX | |||
919 | + TOMOYO_MAX_MAC_CATEGORY_INDEX]; | 1069 | + TOMOYO_MAX_MAC_CATEGORY_INDEX]; |
920 | extern const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE]; | 1070 | extern const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE]; |
921 | extern const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION]; | 1071 | extern const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION]; |
1072 | extern const char * const tomoyo_proto_keyword[TOMOYO_SOCK_MAX]; | ||
1073 | extern const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION]; | ||
922 | extern const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX]; | 1074 | extern const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX]; |
923 | extern const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION]; | 1075 | extern const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION]; |
924 | extern const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION]; | 1076 | extern const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION]; |
@@ -1098,6 +1250,21 @@ static inline bool tomoyo_same_number_union | |||
1098 | } | 1250 | } |
1099 | 1251 | ||
1100 | /** | 1252 | /** |
1253 | * tomoyo_same_ipaddr_union - Check for duplicated "struct tomoyo_ipaddr_union" entry. | ||
1254 | * | ||
1255 | * @a: Pointer to "struct tomoyo_ipaddr_union". | ||
1256 | * @b: Pointer to "struct tomoyo_ipaddr_union". | ||
1257 | * | ||
1258 | * Returns true if @a == @b, false otherwise. | ||
1259 | */ | ||
1260 | static inline bool tomoyo_same_ipaddr_union | ||
1261 | (const struct tomoyo_ipaddr_union *a, const struct tomoyo_ipaddr_union *b) | ||
1262 | { | ||
1263 | return !memcmp(a->ip, b->ip, sizeof(a->ip)) && a->group == b->group && | ||
1264 | a->is_ipv6 == b->is_ipv6; | ||
1265 | } | ||
1266 | |||
1267 | /** | ||
1101 | * tomoyo_current_namespace - Get "struct tomoyo_policy_namespace" for current thread. | 1268 | * tomoyo_current_namespace - Get "struct tomoyo_policy_namespace" for current thread. |
1102 | * | 1269 | * |
1103 | * Returns pointer to "struct tomoyo_policy_namespace" for current thread. | 1270 | * Returns pointer to "struct tomoyo_policy_namespace" for current thread. |
diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c index 8a05f71eaf67..986330b8c73e 100644 --- a/security/tomoyo/condition.c +++ b/security/tomoyo/condition.c | |||
@@ -348,6 +348,7 @@ static inline bool tomoyo_same_condition(const struct tomoyo_condition *a, | |||
348 | a->numbers_count == b->numbers_count && | 348 | a->numbers_count == b->numbers_count && |
349 | a->names_count == b->names_count && | 349 | a->names_count == b->names_count && |
350 | a->argc == b->argc && a->envc == b->envc && | 350 | a->argc == b->argc && a->envc == b->envc && |
351 | a->grant_log == b->grant_log && a->transit == b->transit && | ||
351 | !memcmp(a + 1, b + 1, a->size - sizeof(*a)); | 352 | !memcmp(a + 1, b + 1, a->size - sizeof(*a)); |
352 | } | 353 | } |
353 | 354 | ||
@@ -399,8 +400,9 @@ static struct tomoyo_condition *tomoyo_commit_condition | |||
399 | found = true; | 400 | found = true; |
400 | goto out; | 401 | goto out; |
401 | } | 402 | } |
402 | list_for_each_entry_rcu(ptr, &tomoyo_condition_list, head.list) { | 403 | list_for_each_entry(ptr, &tomoyo_condition_list, head.list) { |
403 | if (!tomoyo_same_condition(ptr, entry)) | 404 | if (!tomoyo_same_condition(ptr, entry) || |
405 | atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS) | ||
404 | continue; | 406 | continue; |
405 | /* Same entry found. Share this entry. */ | 407 | /* Same entry found. Share this entry. */ |
406 | atomic_inc(&ptr->head.users); | 408 | atomic_inc(&ptr->head.users); |
@@ -410,8 +412,7 @@ static struct tomoyo_condition *tomoyo_commit_condition | |||
410 | if (!found) { | 412 | if (!found) { |
411 | if (tomoyo_memory_ok(entry)) { | 413 | if (tomoyo_memory_ok(entry)) { |
412 | atomic_set(&entry->head.users, 1); | 414 | atomic_set(&entry->head.users, 1); |
413 | list_add_rcu(&entry->head.list, | 415 | list_add(&entry->head.list, &tomoyo_condition_list); |
414 | &tomoyo_condition_list); | ||
415 | } else { | 416 | } else { |
416 | found = true; | 417 | found = true; |
417 | ptr = NULL; | 418 | ptr = NULL; |
@@ -428,6 +429,46 @@ out: | |||
428 | } | 429 | } |
429 | 430 | ||
430 | /** | 431 | /** |
432 | * tomoyo_get_transit_preference - Parse domain transition preference for execve(). | ||
433 | * | ||
434 | * @param: Pointer to "struct tomoyo_acl_param". | ||
435 | * @e: Pointer to "struct tomoyo_condition". | ||
436 | * | ||
437 | * Returns the condition string part. | ||
438 | */ | ||
439 | static char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param, | ||
440 | struct tomoyo_condition *e) | ||
441 | { | ||
442 | char * const pos = param->data; | ||
443 | bool flag; | ||
444 | if (*pos == '<') { | ||
445 | e->transit = tomoyo_get_domainname(param); | ||
446 | goto done; | ||
447 | } | ||
448 | { | ||
449 | char *cp = strchr(pos, ' '); | ||
450 | if (cp) | ||
451 | *cp = '\0'; | ||
452 | flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") || | ||
453 | !strcmp(pos, "initialize") || !strcmp(pos, "reset") || | ||
454 | !strcmp(pos, "child") || !strcmp(pos, "parent"); | ||
455 | if (cp) | ||
456 | *cp = ' '; | ||
457 | } | ||
458 | if (!flag) | ||
459 | return pos; | ||
460 | e->transit = tomoyo_get_name(tomoyo_read_token(param)); | ||
461 | done: | ||
462 | if (e->transit) | ||
463 | return param->data; | ||
464 | /* | ||
465 | * Return a bad read-only condition string that will let | ||
466 | * tomoyo_get_condition() return NULL. | ||
467 | */ | ||
468 | return "/"; | ||
469 | } | ||
470 | |||
471 | /** | ||
431 | * tomoyo_get_condition - Parse condition part. | 472 | * tomoyo_get_condition - Parse condition part. |
432 | * | 473 | * |
433 | * @param: Pointer to "struct tomoyo_acl_param". | 474 | * @param: Pointer to "struct tomoyo_acl_param". |
@@ -443,7 +484,8 @@ struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param) | |||
443 | struct tomoyo_argv *argv = NULL; | 484 | struct tomoyo_argv *argv = NULL; |
444 | struct tomoyo_envp *envp = NULL; | 485 | struct tomoyo_envp *envp = NULL; |
445 | struct tomoyo_condition e = { }; | 486 | struct tomoyo_condition e = { }; |
446 | char * const start_of_string = param->data; | 487 | char * const start_of_string = |
488 | tomoyo_get_transit_preference(param, &e); | ||
447 | char * const end_of_string = start_of_string + strlen(start_of_string); | 489 | char * const end_of_string = start_of_string + strlen(start_of_string); |
448 | char *pos; | 490 | char *pos; |
449 | rerun: | 491 | rerun: |
@@ -486,6 +528,20 @@ rerun: | |||
486 | goto out; | 528 | goto out; |
487 | dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word, | 529 | dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word, |
488 | is_not ? "!" : "", right_word); | 530 | is_not ? "!" : "", right_word); |
531 | if (!strcmp(left_word, "grant_log")) { | ||
532 | if (entry) { | ||
533 | if (is_not || | ||
534 | entry->grant_log != TOMOYO_GRANTLOG_AUTO) | ||
535 | goto out; | ||
536 | else if (!strcmp(right_word, "yes")) | ||
537 | entry->grant_log = TOMOYO_GRANTLOG_YES; | ||
538 | else if (!strcmp(right_word, "no")) | ||
539 | entry->grant_log = TOMOYO_GRANTLOG_NO; | ||
540 | else | ||
541 | goto out; | ||
542 | } | ||
543 | continue; | ||
544 | } | ||
489 | if (!strncmp(left_word, "exec.argv[", 10)) { | 545 | if (!strncmp(left_word, "exec.argv[", 10)) { |
490 | if (!argv) { | 546 | if (!argv) { |
491 | e.argc++; | 547 | e.argc++; |
@@ -593,8 +649,9 @@ store_value: | |||
593 | + e.envc * sizeof(struct tomoyo_envp); | 649 | + e.envc * sizeof(struct tomoyo_envp); |
594 | entry = kzalloc(e.size, GFP_NOFS); | 650 | entry = kzalloc(e.size, GFP_NOFS); |
595 | if (!entry) | 651 | if (!entry) |
596 | return NULL; | 652 | goto out2; |
597 | *entry = e; | 653 | *entry = e; |
654 | e.transit = NULL; | ||
598 | condp = (struct tomoyo_condition_element *) (entry + 1); | 655 | condp = (struct tomoyo_condition_element *) (entry + 1); |
599 | numbers_p = (struct tomoyo_number_union *) (condp + e.condc); | 656 | numbers_p = (struct tomoyo_number_union *) (condp + e.condc); |
600 | names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count); | 657 | names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count); |
@@ -621,6 +678,8 @@ out: | |||
621 | tomoyo_del_condition(&entry->head.list); | 678 | tomoyo_del_condition(&entry->head.list); |
622 | kfree(entry); | 679 | kfree(entry); |
623 | } | 680 | } |
681 | out2: | ||
682 | tomoyo_put_name(e.transit); | ||
624 | return NULL; | 683 | return NULL; |
625 | } | 684 | } |
626 | 685 | ||
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index cd0f92d88bb4..9027ac1534af 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -39,6 +39,8 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, | |||
39 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 39 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
40 | return -ENOMEM; | 40 | return -ENOMEM; |
41 | list_for_each_entry_rcu(entry, list, list) { | 41 | list_for_each_entry_rcu(entry, list, list) { |
42 | if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS) | ||
43 | continue; | ||
42 | if (!check_duplicate(entry, new_entry)) | 44 | if (!check_duplicate(entry, new_entry)) |
43 | continue; | 45 | continue; |
44 | entry->is_deleted = param->is_delete; | 46 | entry->is_deleted = param->is_delete; |
@@ -102,10 +104,21 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | |||
102 | new_entry->cond = tomoyo_get_condition(param); | 104 | new_entry->cond = tomoyo_get_condition(param); |
103 | if (!new_entry->cond) | 105 | if (!new_entry->cond) |
104 | return -EINVAL; | 106 | return -EINVAL; |
107 | /* | ||
108 | * Domain transition preference is allowed for only | ||
109 | * "file execute" entries. | ||
110 | */ | ||
111 | if (new_entry->cond->transit && | ||
112 | !(new_entry->type == TOMOYO_TYPE_PATH_ACL && | ||
113 | container_of(new_entry, struct tomoyo_path_acl, head) | ||
114 | ->perm == 1 << TOMOYO_TYPE_EXECUTE)) | ||
115 | goto out; | ||
105 | } | 116 | } |
106 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 117 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
107 | goto out; | 118 | goto out; |
108 | list_for_each_entry_rcu(entry, list, list) { | 119 | list_for_each_entry_rcu(entry, list, list) { |
120 | if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS) | ||
121 | continue; | ||
109 | if (!tomoyo_same_acl_head(entry, new_entry) || | 122 | if (!tomoyo_same_acl_head(entry, new_entry) || |
110 | !check_duplicate(entry, new_entry)) | 123 | !check_duplicate(entry, new_entry)) |
111 | continue; | 124 | continue; |
@@ -157,6 +170,7 @@ retry: | |||
157 | continue; | 170 | continue; |
158 | if (!tomoyo_condition(r, ptr->cond)) | 171 | if (!tomoyo_condition(r, ptr->cond)) |
159 | continue; | 172 | continue; |
173 | r->matched_acl = ptr; | ||
160 | r->granted = true; | 174 | r->granted = true; |
161 | return; | 175 | return; |
162 | } | 176 | } |
@@ -501,7 +515,8 @@ struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, | |||
501 | * that domain. Do not perform domain transition if | 515 | * that domain. Do not perform domain transition if |
502 | * profile for that domain is not yet created. | 516 | * profile for that domain is not yet created. |
503 | */ | 517 | */ |
504 | if (!entry->ns->profile_ptr[entry->profile]) | 518 | if (tomoyo_policy_loaded && |
519 | !entry->ns->profile_ptr[entry->profile]) | ||
505 | return NULL; | 520 | return NULL; |
506 | } | 521 | } |
507 | return entry; | 522 | return entry; |
@@ -557,12 +572,99 @@ out: | |||
557 | tomoyo_write_log(&r, "use_profile %u\n", | 572 | tomoyo_write_log(&r, "use_profile %u\n", |
558 | entry->profile); | 573 | entry->profile); |
559 | tomoyo_write_log(&r, "use_group %u\n", entry->group); | 574 | tomoyo_write_log(&r, "use_group %u\n", entry->group); |
575 | tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); | ||
560 | } | 576 | } |
561 | } | 577 | } |
562 | return entry; | 578 | return entry; |
563 | } | 579 | } |
564 | 580 | ||
565 | /** | 581 | /** |
582 | * tomoyo_environ - Check permission for environment variable names. | ||
583 | * | ||
584 | * @ee: Pointer to "struct tomoyo_execve". | ||
585 | * | ||
586 | * Returns 0 on success, negative value otherwise. | ||
587 | */ | ||
588 | static int tomoyo_environ(struct tomoyo_execve *ee) | ||
589 | { | ||
590 | struct tomoyo_request_info *r = &ee->r; | ||
591 | struct linux_binprm *bprm = ee->bprm; | ||
592 | /* env_page.data is allocated by tomoyo_dump_page(). */ | ||
593 | struct tomoyo_page_dump env_page = { }; | ||
594 | char *arg_ptr; /* Size is TOMOYO_EXEC_TMPSIZE bytes */ | ||
595 | int arg_len = 0; | ||
596 | unsigned long pos = bprm->p; | ||
597 | int offset = pos % PAGE_SIZE; | ||
598 | int argv_count = bprm->argc; | ||
599 | int envp_count = bprm->envc; | ||
600 | int error = -ENOMEM; | ||
601 | |||
602 | ee->r.type = TOMOYO_MAC_ENVIRON; | ||
603 | ee->r.profile = r->domain->profile; | ||
604 | ee->r.mode = tomoyo_get_mode(r->domain->ns, ee->r.profile, | ||
605 | TOMOYO_MAC_ENVIRON); | ||
606 | if (!r->mode || !envp_count) | ||
607 | return 0; | ||
608 | arg_ptr = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); | ||
609 | if (!arg_ptr) | ||
610 | goto out; | ||
611 | while (error == -ENOMEM) { | ||
612 | if (!tomoyo_dump_page(bprm, pos, &env_page)) | ||
613 | goto out; | ||
614 | pos += PAGE_SIZE - offset; | ||
615 | /* Read. */ | ||
616 | while (argv_count && offset < PAGE_SIZE) { | ||
617 | if (!env_page.data[offset++]) | ||
618 | argv_count--; | ||
619 | } | ||
620 | if (argv_count) { | ||
621 | offset = 0; | ||
622 | continue; | ||
623 | } | ||
624 | while (offset < PAGE_SIZE) { | ||
625 | const unsigned char c = env_page.data[offset++]; | ||
626 | |||
627 | if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) { | ||
628 | if (c == '=') { | ||
629 | arg_ptr[arg_len++] = '\0'; | ||
630 | } else if (c == '\\') { | ||
631 | arg_ptr[arg_len++] = '\\'; | ||
632 | arg_ptr[arg_len++] = '\\'; | ||
633 | } else if (c > ' ' && c < 127) { | ||
634 | arg_ptr[arg_len++] = c; | ||
635 | } else { | ||
636 | arg_ptr[arg_len++] = '\\'; | ||
637 | arg_ptr[arg_len++] = (c >> 6) + '0'; | ||
638 | arg_ptr[arg_len++] | ||
639 | = ((c >> 3) & 7) + '0'; | ||
640 | arg_ptr[arg_len++] = (c & 7) + '0'; | ||
641 | } | ||
642 | } else { | ||
643 | arg_ptr[arg_len] = '\0'; | ||
644 | } | ||
645 | if (c) | ||
646 | continue; | ||
647 | if (tomoyo_env_perm(r, arg_ptr)) { | ||
648 | error = -EPERM; | ||
649 | break; | ||
650 | } | ||
651 | if (!--envp_count) { | ||
652 | error = 0; | ||
653 | break; | ||
654 | } | ||
655 | arg_len = 0; | ||
656 | } | ||
657 | offset = 0; | ||
658 | } | ||
659 | out: | ||
660 | if (r->mode != TOMOYO_CONFIG_ENFORCING) | ||
661 | error = 0; | ||
662 | kfree(env_page.data); | ||
663 | kfree(arg_ptr); | ||
664 | return error; | ||
665 | } | ||
666 | |||
667 | /** | ||
566 | * tomoyo_find_next_domain - Find a domain. | 668 | * tomoyo_find_next_domain - Find a domain. |
567 | * | 669 | * |
568 | * @bprm: Pointer to "struct linux_binprm". | 670 | * @bprm: Pointer to "struct linux_binprm". |
@@ -577,10 +679,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
577 | struct tomoyo_domain_info *domain = NULL; | 679 | struct tomoyo_domain_info *domain = NULL; |
578 | const char *original_name = bprm->filename; | 680 | const char *original_name = bprm->filename; |
579 | int retval = -ENOMEM; | 681 | int retval = -ENOMEM; |
580 | bool need_kfree = false; | ||
581 | bool reject_on_transition_failure = false; | 682 | bool reject_on_transition_failure = false; |
582 | struct tomoyo_path_info rn = { }; /* real name */ | 683 | const struct tomoyo_path_info *candidate; |
684 | struct tomoyo_path_info exename; | ||
583 | struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS); | 685 | struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS); |
686 | |||
584 | if (!ee) | 687 | if (!ee) |
585 | return -ENOMEM; | 688 | return -ENOMEM; |
586 | ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); | 689 | ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); |
@@ -594,40 +697,32 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
594 | ee->bprm = bprm; | 697 | ee->bprm = bprm; |
595 | ee->r.obj = &ee->obj; | 698 | ee->r.obj = &ee->obj; |
596 | ee->obj.path1 = bprm->file->f_path; | 699 | ee->obj.path1 = bprm->file->f_path; |
597 | retry: | ||
598 | if (need_kfree) { | ||
599 | kfree(rn.name); | ||
600 | need_kfree = false; | ||
601 | } | ||
602 | /* Get symlink's pathname of program. */ | 700 | /* Get symlink's pathname of program. */ |
603 | retval = -ENOENT; | 701 | retval = -ENOENT; |
604 | rn.name = tomoyo_realpath_nofollow(original_name); | 702 | exename.name = tomoyo_realpath_nofollow(original_name); |
605 | if (!rn.name) | 703 | if (!exename.name) |
606 | goto out; | 704 | goto out; |
607 | tomoyo_fill_path_info(&rn); | 705 | tomoyo_fill_path_info(&exename); |
608 | need_kfree = true; | 706 | retry: |
609 | |||
610 | /* Check 'aggregator' directive. */ | 707 | /* Check 'aggregator' directive. */ |
611 | { | 708 | { |
612 | struct tomoyo_aggregator *ptr; | 709 | struct tomoyo_aggregator *ptr; |
613 | struct list_head *list = | 710 | struct list_head *list = |
614 | &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR]; | 711 | &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR]; |
615 | /* Check 'aggregator' directive. */ | 712 | /* Check 'aggregator' directive. */ |
713 | candidate = &exename; | ||
616 | list_for_each_entry_rcu(ptr, list, head.list) { | 714 | list_for_each_entry_rcu(ptr, list, head.list) { |
617 | if (ptr->head.is_deleted || | 715 | if (ptr->head.is_deleted || |
618 | !tomoyo_path_matches_pattern(&rn, | 716 | !tomoyo_path_matches_pattern(&exename, |
619 | ptr->original_name)) | 717 | ptr->original_name)) |
620 | continue; | 718 | continue; |
621 | kfree(rn.name); | 719 | candidate = ptr->aggregated_name; |
622 | need_kfree = false; | ||
623 | /* This is OK because it is read only. */ | ||
624 | rn = *ptr->aggregated_name; | ||
625 | break; | 720 | break; |
626 | } | 721 | } |
627 | } | 722 | } |
628 | 723 | ||
629 | /* Check execute permission. */ | 724 | /* Check execute permission. */ |
630 | retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE, &rn); | 725 | retval = tomoyo_execute_permission(&ee->r, candidate); |
631 | if (retval == TOMOYO_RETRY_REQUEST) | 726 | if (retval == TOMOYO_RETRY_REQUEST) |
632 | goto retry; | 727 | goto retry; |
633 | if (retval < 0) | 728 | if (retval < 0) |
@@ -638,20 +733,51 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
638 | * wildcard) rather than the pathname passed to execve() | 733 | * wildcard) rather than the pathname passed to execve() |
639 | * (which never contains wildcard). | 734 | * (which never contains wildcard). |
640 | */ | 735 | */ |
641 | if (ee->r.param.path.matched_path) { | 736 | if (ee->r.param.path.matched_path) |
642 | if (need_kfree) | 737 | candidate = ee->r.param.path.matched_path; |
643 | kfree(rn.name); | ||
644 | need_kfree = false; | ||
645 | /* This is OK because it is read only. */ | ||
646 | rn = *ee->r.param.path.matched_path; | ||
647 | } | ||
648 | 738 | ||
649 | /* Calculate domain to transit to. */ | 739 | /* |
740 | * Check for domain transition preference if "file execute" matched. | ||
741 | * If preference is given, make do_execve() fail if domain transition | ||
742 | * has failed, for domain transition preference should be used with | ||
743 | * destination domain defined. | ||
744 | */ | ||
745 | if (ee->transition) { | ||
746 | const char *domainname = ee->transition->name; | ||
747 | reject_on_transition_failure = true; | ||
748 | if (!strcmp(domainname, "keep")) | ||
749 | goto force_keep_domain; | ||
750 | if (!strcmp(domainname, "child")) | ||
751 | goto force_child_domain; | ||
752 | if (!strcmp(domainname, "reset")) | ||
753 | goto force_reset_domain; | ||
754 | if (!strcmp(domainname, "initialize")) | ||
755 | goto force_initialize_domain; | ||
756 | if (!strcmp(domainname, "parent")) { | ||
757 | char *cp; | ||
758 | strncpy(ee->tmp, old_domain->domainname->name, | ||
759 | TOMOYO_EXEC_TMPSIZE - 1); | ||
760 | cp = strrchr(ee->tmp, ' '); | ||
761 | if (cp) | ||
762 | *cp = '\0'; | ||
763 | } else if (*domainname == '<') | ||
764 | strncpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE - 1); | ||
765 | else | ||
766 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", | ||
767 | old_domain->domainname->name, domainname); | ||
768 | goto force_jump_domain; | ||
769 | } | ||
770 | /* | ||
771 | * No domain transition preference specified. | ||
772 | * Calculate domain to transit to. | ||
773 | */ | ||
650 | switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname, | 774 | switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname, |
651 | &rn)) { | 775 | candidate)) { |
652 | case TOMOYO_TRANSITION_CONTROL_RESET: | 776 | case TOMOYO_TRANSITION_CONTROL_RESET: |
777 | force_reset_domain: | ||
653 | /* Transit to the root of specified namespace. */ | 778 | /* Transit to the root of specified namespace. */ |
654 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name); | 779 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", |
780 | candidate->name); | ||
655 | /* | 781 | /* |
656 | * Make do_execve() fail if domain transition across namespaces | 782 | * Make do_execve() fail if domain transition across namespaces |
657 | * has failed. | 783 | * has failed. |
@@ -659,11 +785,13 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
659 | reject_on_transition_failure = true; | 785 | reject_on_transition_failure = true; |
660 | break; | 786 | break; |
661 | case TOMOYO_TRANSITION_CONTROL_INITIALIZE: | 787 | case TOMOYO_TRANSITION_CONTROL_INITIALIZE: |
788 | force_initialize_domain: | ||
662 | /* Transit to the child of current namespace's root. */ | 789 | /* Transit to the child of current namespace's root. */ |
663 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", | 790 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", |
664 | old_domain->ns->name, rn.name); | 791 | old_domain->ns->name, candidate->name); |
665 | break; | 792 | break; |
666 | case TOMOYO_TRANSITION_CONTROL_KEEP: | 793 | case TOMOYO_TRANSITION_CONTROL_KEEP: |
794 | force_keep_domain: | ||
667 | /* Keep current domain. */ | 795 | /* Keep current domain. */ |
668 | domain = old_domain; | 796 | domain = old_domain; |
669 | break; | 797 | break; |
@@ -677,13 +805,15 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
677 | * before /sbin/init. | 805 | * before /sbin/init. |
678 | */ | 806 | */ |
679 | domain = old_domain; | 807 | domain = old_domain; |
680 | } else { | 808 | break; |
681 | /* Normal domain transition. */ | ||
682 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", | ||
683 | old_domain->domainname->name, rn.name); | ||
684 | } | 809 | } |
810 | force_child_domain: | ||
811 | /* Normal domain transition. */ | ||
812 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", | ||
813 | old_domain->domainname->name, candidate->name); | ||
685 | break; | 814 | break; |
686 | } | 815 | } |
816 | force_jump_domain: | ||
687 | if (!domain) | 817 | if (!domain) |
688 | domain = tomoyo_assign_domain(ee->tmp, true); | 818 | domain = tomoyo_assign_domain(ee->tmp, true); |
689 | if (domain) | 819 | if (domain) |
@@ -711,8 +841,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
711 | /* Update reference count on "struct tomoyo_domain_info". */ | 841 | /* Update reference count on "struct tomoyo_domain_info". */ |
712 | atomic_inc(&domain->users); | 842 | atomic_inc(&domain->users); |
713 | bprm->cred->security = domain; | 843 | bprm->cred->security = domain; |
714 | if (need_kfree) | 844 | kfree(exename.name); |
715 | kfree(rn.name); | 845 | if (!retval) { |
846 | ee->r.domain = domain; | ||
847 | retval = tomoyo_environ(ee); | ||
848 | } | ||
716 | kfree(ee->tmp); | 849 | kfree(ee->tmp); |
717 | kfree(ee->dump.data); | 850 | kfree(ee->dump.data); |
718 | kfree(ee); | 851 | kfree(ee); |
@@ -732,7 +865,8 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos, | |||
732 | struct tomoyo_page_dump *dump) | 865 | struct tomoyo_page_dump *dump) |
733 | { | 866 | { |
734 | struct page *page; | 867 | struct page *page; |
735 | /* dump->data is released by tomoyo_finish_execve(). */ | 868 | |
869 | /* dump->data is released by tomoyo_find_next_domain(). */ | ||
736 | if (!dump->data) { | 870 | if (!dump->data) { |
737 | dump->data = kzalloc(PAGE_SIZE, GFP_NOFS); | 871 | dump->data = kzalloc(PAGE_SIZE, GFP_NOFS); |
738 | if (!dump->data) | 872 | if (!dump->data) |
@@ -753,6 +887,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos, | |||
753 | * So do I. | 887 | * So do I. |
754 | */ | 888 | */ |
755 | char *kaddr = kmap_atomic(page, KM_USER0); | 889 | char *kaddr = kmap_atomic(page, KM_USER0); |
890 | |||
756 | dump->page = page; | 891 | dump->page = page; |
757 | memcpy(dump->data + offset, kaddr + offset, | 892 | memcpy(dump->data + offset, kaddr + offset, |
758 | PAGE_SIZE - offset); | 893 | PAGE_SIZE - offset); |
diff --git a/security/tomoyo/environ.c b/security/tomoyo/environ.c new file mode 100644 index 000000000000..ad4c6e18a437 --- /dev/null +++ b/security/tomoyo/environ.c | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * security/tomoyo/environ.c | ||
3 | * | ||
4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION | ||
5 | */ | ||
6 | |||
7 | #include "common.h" | ||
8 | |||
9 | /** | ||
10 | * tomoyo_check_env_acl - Check permission for environment variable's name. | ||
11 | * | ||
12 | * @r: Pointer to "struct tomoyo_request_info". | ||
13 | * @ptr: Pointer to "struct tomoyo_acl_info". | ||
14 | * | ||
15 | * Returns true if granted, false otherwise. | ||
16 | */ | ||
17 | static bool tomoyo_check_env_acl(struct tomoyo_request_info *r, | ||
18 | const struct tomoyo_acl_info *ptr) | ||
19 | { | ||
20 | const struct tomoyo_env_acl *acl = | ||
21 | container_of(ptr, typeof(*acl), head); | ||
22 | |||
23 | return tomoyo_path_matches_pattern(r->param.environ.name, acl->env); | ||
24 | } | ||
25 | |||
26 | /** | ||
27 | * tomoyo_audit_env_log - Audit environment variable name log. | ||
28 | * | ||
29 | * @r: Pointer to "struct tomoyo_request_info". | ||
30 | * | ||
31 | * Returns 0 on success, negative value otherwise. | ||
32 | */ | ||
33 | static int tomoyo_audit_env_log(struct tomoyo_request_info *r) | ||
34 | { | ||
35 | return tomoyo_supervisor(r, "misc env %s\n", | ||
36 | r->param.environ.name->name); | ||
37 | } | ||
38 | |||
39 | /** | ||
40 | * tomoyo_env_perm - Check permission for environment variable's name. | ||
41 | * | ||
42 | * @r: Pointer to "struct tomoyo_request_info". | ||
43 | * @env: The name of environment variable. | ||
44 | * | ||
45 | * Returns 0 on success, negative value otherwise. | ||
46 | * | ||
47 | * Caller holds tomoyo_read_lock(). | ||
48 | */ | ||
49 | int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env) | ||
50 | { | ||
51 | struct tomoyo_path_info environ; | ||
52 | int error; | ||
53 | |||
54 | if (!env || !*env) | ||
55 | return 0; | ||
56 | environ.name = env; | ||
57 | tomoyo_fill_path_info(&environ); | ||
58 | r->param_type = TOMOYO_TYPE_ENV_ACL; | ||
59 | r->param.environ.name = &environ; | ||
60 | do { | ||
61 | tomoyo_check_acl(r, tomoyo_check_env_acl); | ||
62 | error = tomoyo_audit_env_log(r); | ||
63 | } while (error == TOMOYO_RETRY_REQUEST); | ||
64 | return error; | ||
65 | } | ||
66 | |||
67 | /** | ||
68 | * tomoyo_same_env_acl - Check for duplicated "struct tomoyo_env_acl" entry. | ||
69 | * | ||
70 | * @a: Pointer to "struct tomoyo_acl_info". | ||
71 | * @b: Pointer to "struct tomoyo_acl_info". | ||
72 | * | ||
73 | * Returns true if @a == @b, false otherwise. | ||
74 | */ | ||
75 | static bool tomoyo_same_env_acl(const struct tomoyo_acl_info *a, | ||
76 | const struct tomoyo_acl_info *b) | ||
77 | { | ||
78 | const struct tomoyo_env_acl *p1 = container_of(a, typeof(*p1), head); | ||
79 | const struct tomoyo_env_acl *p2 = container_of(b, typeof(*p2), head); | ||
80 | |||
81 | return p1->env == p2->env; | ||
82 | } | ||
83 | |||
84 | /** | ||
85 | * tomoyo_write_env - Write "struct tomoyo_env_acl" list. | ||
86 | * | ||
87 | * @param: Pointer to "struct tomoyo_acl_param". | ||
88 | * | ||
89 | * Returns 0 on success, negative value otherwise. | ||
90 | * | ||
91 | * Caller holds tomoyo_read_lock(). | ||
92 | */ | ||
93 | static int tomoyo_write_env(struct tomoyo_acl_param *param) | ||
94 | { | ||
95 | struct tomoyo_env_acl e = { .head.type = TOMOYO_TYPE_ENV_ACL }; | ||
96 | int error = -ENOMEM; | ||
97 | const char *data = tomoyo_read_token(param); | ||
98 | |||
99 | if (!tomoyo_correct_word(data) || strchr(data, '=')) | ||
100 | return -EINVAL; | ||
101 | e.env = tomoyo_get_name(data); | ||
102 | if (!e.env) | ||
103 | return error; | ||
104 | error = tomoyo_update_domain(&e.head, sizeof(e), param, | ||
105 | tomoyo_same_env_acl, NULL); | ||
106 | tomoyo_put_name(e.env); | ||
107 | return error; | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * tomoyo_write_misc - Update environment variable list. | ||
112 | * | ||
113 | * @param: Pointer to "struct tomoyo_acl_param". | ||
114 | * | ||
115 | * Returns 0 on success, negative value otherwise. | ||
116 | */ | ||
117 | int tomoyo_write_misc(struct tomoyo_acl_param *param) | ||
118 | { | ||
119 | if (tomoyo_str_starts(¶m->data, "env ")) | ||
120 | return tomoyo_write_env(param); | ||
121 | return -EINVAL; | ||
122 | } | ||
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 743c35f5084a..400390790745 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -555,8 +555,8 @@ static int tomoyo_update_path2_acl(const u8 perm, | |||
555 | * | 555 | * |
556 | * Caller holds tomoyo_read_lock(). | 556 | * Caller holds tomoyo_read_lock(). |
557 | */ | 557 | */ |
558 | int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | 558 | static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, |
559 | const struct tomoyo_path_info *filename) | 559 | const struct tomoyo_path_info *filename) |
560 | { | 560 | { |
561 | int error; | 561 | int error; |
562 | 562 | ||
@@ -570,16 +570,42 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | |||
570 | do { | 570 | do { |
571 | tomoyo_check_acl(r, tomoyo_check_path_acl); | 571 | tomoyo_check_acl(r, tomoyo_check_path_acl); |
572 | error = tomoyo_audit_path_log(r); | 572 | error = tomoyo_audit_path_log(r); |
573 | /* | 573 | } while (error == TOMOYO_RETRY_REQUEST); |
574 | * Do not retry for execute request, for alias may have | ||
575 | * changed. | ||
576 | */ | ||
577 | } while (error == TOMOYO_RETRY_REQUEST && | ||
578 | operation != TOMOYO_TYPE_EXECUTE); | ||
579 | return error; | 574 | return error; |
580 | } | 575 | } |
581 | 576 | ||
582 | /** | 577 | /** |
578 | * tomoyo_execute_permission - Check permission for execute operation. | ||
579 | * | ||
580 | * @r: Pointer to "struct tomoyo_request_info". | ||
581 | * @filename: Filename to check. | ||
582 | * | ||
583 | * Returns 0 on success, negative value otherwise. | ||
584 | * | ||
585 | * Caller holds tomoyo_read_lock(). | ||
586 | */ | ||
587 | int tomoyo_execute_permission(struct tomoyo_request_info *r, | ||
588 | const struct tomoyo_path_info *filename) | ||
589 | { | ||
590 | /* | ||
591 | * Unlike other permission checks, this check is done regardless of | ||
592 | * profile mode settings in order to check for domain transition | ||
593 | * preference. | ||
594 | */ | ||
595 | r->type = TOMOYO_MAC_FILE_EXECUTE; | ||
596 | r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type); | ||
597 | r->param_type = TOMOYO_TYPE_PATH_ACL; | ||
598 | r->param.path.filename = filename; | ||
599 | r->param.path.operation = TOMOYO_TYPE_EXECUTE; | ||
600 | tomoyo_check_acl(r, tomoyo_check_path_acl); | ||
601 | r->ee->transition = r->matched_acl && r->matched_acl->cond ? | ||
602 | r->matched_acl->cond->transit : NULL; | ||
603 | if (r->mode != TOMOYO_CONFIG_DISABLED) | ||
604 | return tomoyo_audit_path_log(r); | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | /** | ||
583 | * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry. | 609 | * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry. |
584 | * | 610 | * |
585 | * @a: Pointer to "struct tomoyo_acl_info". | 611 | * @a: Pointer to "struct tomoyo_acl_info". |
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index ae135fbbbe95..986a6a756868 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c | |||
@@ -8,36 +8,26 @@ | |||
8 | #include <linux/kthread.h> | 8 | #include <linux/kthread.h> |
9 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
10 | 10 | ||
11 | /** | ||
12 | * tomoyo_memory_free - Free memory for elements. | ||
13 | * | ||
14 | * @ptr: Pointer to allocated memory. | ||
15 | * | ||
16 | * Returns nothing. | ||
17 | * | ||
18 | * Caller holds tomoyo_policy_lock mutex. | ||
19 | */ | ||
20 | static inline void tomoyo_memory_free(void *ptr) | ||
21 | { | ||
22 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= ksize(ptr); | ||
23 | kfree(ptr); | ||
24 | } | ||
25 | |||
11 | /* The list for "struct tomoyo_io_buffer". */ | 26 | /* The list for "struct tomoyo_io_buffer". */ |
12 | static LIST_HEAD(tomoyo_io_buffer_list); | 27 | static LIST_HEAD(tomoyo_io_buffer_list); |
13 | /* Lock for protecting tomoyo_io_buffer_list. */ | 28 | /* Lock for protecting tomoyo_io_buffer_list. */ |
14 | static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock); | 29 | static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock); |
15 | 30 | ||
16 | /* Size of an element. */ | ||
17 | static const u8 tomoyo_element_size[TOMOYO_MAX_POLICY] = { | ||
18 | [TOMOYO_ID_GROUP] = sizeof(struct tomoyo_group), | ||
19 | [TOMOYO_ID_PATH_GROUP] = sizeof(struct tomoyo_path_group), | ||
20 | [TOMOYO_ID_NUMBER_GROUP] = sizeof(struct tomoyo_number_group), | ||
21 | [TOMOYO_ID_AGGREGATOR] = sizeof(struct tomoyo_aggregator), | ||
22 | [TOMOYO_ID_TRANSITION_CONTROL] = | ||
23 | sizeof(struct tomoyo_transition_control), | ||
24 | [TOMOYO_ID_MANAGER] = sizeof(struct tomoyo_manager), | ||
25 | /* [TOMOYO_ID_CONDITION] = "struct tomoyo_condition"->size, */ | ||
26 | /* [TOMOYO_ID_NAME] = "struct tomoyo_name"->size, */ | ||
27 | /* [TOMOYO_ID_ACL] = | ||
28 | tomoyo_acl_size["struct tomoyo_acl_info"->type], */ | ||
29 | [TOMOYO_ID_DOMAIN] = sizeof(struct tomoyo_domain_info), | ||
30 | }; | ||
31 | |||
32 | /* Size of a domain ACL element. */ | ||
33 | static const u8 tomoyo_acl_size[] = { | ||
34 | [TOMOYO_TYPE_PATH_ACL] = sizeof(struct tomoyo_path_acl), | ||
35 | [TOMOYO_TYPE_PATH2_ACL] = sizeof(struct tomoyo_path2_acl), | ||
36 | [TOMOYO_TYPE_PATH_NUMBER_ACL] = sizeof(struct tomoyo_path_number_acl), | ||
37 | [TOMOYO_TYPE_MKDEV_ACL] = sizeof(struct tomoyo_mkdev_acl), | ||
38 | [TOMOYO_TYPE_MOUNT_ACL] = sizeof(struct tomoyo_mount_acl), | ||
39 | }; | ||
40 | |||
41 | /** | 31 | /** |
42 | * tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not. | 32 | * tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not. |
43 | * | 33 | * |
@@ -55,15 +45,11 @@ static bool tomoyo_struct_used_by_io_buffer(const struct list_head *element) | |||
55 | list_for_each_entry(head, &tomoyo_io_buffer_list, list) { | 45 | list_for_each_entry(head, &tomoyo_io_buffer_list, list) { |
56 | head->users++; | 46 | head->users++; |
57 | spin_unlock(&tomoyo_io_buffer_list_lock); | 47 | spin_unlock(&tomoyo_io_buffer_list_lock); |
58 | if (mutex_lock_interruptible(&head->io_sem)) { | 48 | mutex_lock(&head->io_sem); |
59 | in_use = true; | ||
60 | goto out; | ||
61 | } | ||
62 | if (head->r.domain == element || head->r.group == element || | 49 | if (head->r.domain == element || head->r.group == element || |
63 | head->r.acl == element || &head->w.domain->list == element) | 50 | head->r.acl == element || &head->w.domain->list == element) |
64 | in_use = true; | 51 | in_use = true; |
65 | mutex_unlock(&head->io_sem); | 52 | mutex_unlock(&head->io_sem); |
66 | out: | ||
67 | spin_lock(&tomoyo_io_buffer_list_lock); | 53 | spin_lock(&tomoyo_io_buffer_list_lock); |
68 | head->users--; | 54 | head->users--; |
69 | if (in_use) | 55 | if (in_use) |
@@ -77,15 +63,14 @@ out: | |||
77 | * tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not. | 63 | * tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not. |
78 | * | 64 | * |
79 | * @string: String to check. | 65 | * @string: String to check. |
80 | * @size: Memory allocated for @string . | ||
81 | * | 66 | * |
82 | * Returns true if @string is used by /sys/kernel/security/tomoyo/ users, | 67 | * Returns true if @string is used by /sys/kernel/security/tomoyo/ users, |
83 | * false otherwise. | 68 | * false otherwise. |
84 | */ | 69 | */ |
85 | static bool tomoyo_name_used_by_io_buffer(const char *string, | 70 | static bool tomoyo_name_used_by_io_buffer(const char *string) |
86 | const size_t size) | ||
87 | { | 71 | { |
88 | struct tomoyo_io_buffer *head; | 72 | struct tomoyo_io_buffer *head; |
73 | const size_t size = strlen(string) + 1; | ||
89 | bool in_use = false; | 74 | bool in_use = false; |
90 | 75 | ||
91 | spin_lock(&tomoyo_io_buffer_list_lock); | 76 | spin_lock(&tomoyo_io_buffer_list_lock); |
@@ -93,10 +78,7 @@ static bool tomoyo_name_used_by_io_buffer(const char *string, | |||
93 | int i; | 78 | int i; |
94 | head->users++; | 79 | head->users++; |
95 | spin_unlock(&tomoyo_io_buffer_list_lock); | 80 | spin_unlock(&tomoyo_io_buffer_list_lock); |
96 | if (mutex_lock_interruptible(&head->io_sem)) { | 81 | mutex_lock(&head->io_sem); |
97 | in_use = true; | ||
98 | goto out; | ||
99 | } | ||
100 | for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) { | 82 | for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) { |
101 | const char *w = head->r.w[i]; | 83 | const char *w = head->r.w[i]; |
102 | if (w < string || w > string + size) | 84 | if (w < string || w > string + size) |
@@ -105,7 +87,6 @@ static bool tomoyo_name_used_by_io_buffer(const char *string, | |||
105 | break; | 87 | break; |
106 | } | 88 | } |
107 | mutex_unlock(&head->io_sem); | 89 | mutex_unlock(&head->io_sem); |
108 | out: | ||
109 | spin_lock(&tomoyo_io_buffer_list_lock); | 90 | spin_lock(&tomoyo_io_buffer_list_lock); |
110 | head->users--; | 91 | head->users--; |
111 | if (in_use) | 92 | if (in_use) |
@@ -115,84 +96,6 @@ out: | |||
115 | return in_use; | 96 | return in_use; |
116 | } | 97 | } |
117 | 98 | ||
118 | /* Structure for garbage collection. */ | ||
119 | struct tomoyo_gc { | ||
120 | struct list_head list; | ||
121 | enum tomoyo_policy_id type; | ||
122 | size_t size; | ||
123 | struct list_head *element; | ||
124 | }; | ||
125 | /* List of entries to be deleted. */ | ||
126 | static LIST_HEAD(tomoyo_gc_list); | ||
127 | /* Length of tomoyo_gc_list. */ | ||
128 | static int tomoyo_gc_list_len; | ||
129 | |||
130 | /** | ||
131 | * tomoyo_add_to_gc - Add an entry to to be deleted list. | ||
132 | * | ||
133 | * @type: One of values in "enum tomoyo_policy_id". | ||
134 | * @element: Pointer to "struct list_head". | ||
135 | * | ||
136 | * Returns true on success, false otherwise. | ||
137 | * | ||
138 | * Caller holds tomoyo_policy_lock mutex. | ||
139 | * | ||
140 | * Adding an entry needs kmalloc(). Thus, if we try to add thousands of | ||
141 | * entries at once, it will take too long time. Thus, do not add more than 128 | ||
142 | * entries per a scan. But to be able to handle worst case where all entries | ||
143 | * are in-use, we accept one more entry per a scan. | ||
144 | * | ||
145 | * If we use singly linked list using "struct list_head"->prev (which is | ||
146 | * LIST_POISON2), we can avoid kmalloc(). | ||
147 | */ | ||
148 | static bool tomoyo_add_to_gc(const int type, struct list_head *element) | ||
149 | { | ||
150 | struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | ||
151 | if (!entry) | ||
152 | return false; | ||
153 | entry->type = type; | ||
154 | if (type == TOMOYO_ID_ACL) | ||
155 | entry->size = tomoyo_acl_size[ | ||
156 | container_of(element, | ||
157 | typeof(struct tomoyo_acl_info), | ||
158 | list)->type]; | ||
159 | else if (type == TOMOYO_ID_NAME) | ||
160 | entry->size = strlen(container_of(element, | ||
161 | typeof(struct tomoyo_name), | ||
162 | head.list)->entry.name) + 1; | ||
163 | else if (type == TOMOYO_ID_CONDITION) | ||
164 | entry->size = | ||
165 | container_of(element, typeof(struct tomoyo_condition), | ||
166 | head.list)->size; | ||
167 | else | ||
168 | entry->size = tomoyo_element_size[type]; | ||
169 | entry->element = element; | ||
170 | list_add(&entry->list, &tomoyo_gc_list); | ||
171 | list_del_rcu(element); | ||
172 | return tomoyo_gc_list_len++ < 128; | ||
173 | } | ||
174 | |||
175 | /** | ||
176 | * tomoyo_element_linked_by_gc - Validate next element of an entry. | ||
177 | * | ||
178 | * @element: Pointer to an element. | ||
179 | * @size: Size of @element in byte. | ||
180 | * | ||
181 | * Returns true if @element is linked by other elements in the garbage | ||
182 | * collector's queue, false otherwise. | ||
183 | */ | ||
184 | static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size) | ||
185 | { | ||
186 | struct tomoyo_gc *p; | ||
187 | list_for_each_entry(p, &tomoyo_gc_list, list) { | ||
188 | const u8 *ptr = (const u8 *) p->element->next; | ||
189 | if (ptr < element || element + size < ptr) | ||
190 | continue; | ||
191 | return true; | ||
192 | } | ||
193 | return false; | ||
194 | } | ||
195 | |||
196 | /** | 99 | /** |
197 | * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control". | 100 | * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control". |
198 | * | 101 | * |
@@ -200,7 +103,7 @@ static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size) | |||
200 | * | 103 | * |
201 | * Returns nothing. | 104 | * Returns nothing. |
202 | */ | 105 | */ |
203 | static void tomoyo_del_transition_control(struct list_head *element) | 106 | static inline void tomoyo_del_transition_control(struct list_head *element) |
204 | { | 107 | { |
205 | struct tomoyo_transition_control *ptr = | 108 | struct tomoyo_transition_control *ptr = |
206 | container_of(element, typeof(*ptr), head.list); | 109 | container_of(element, typeof(*ptr), head.list); |
@@ -215,7 +118,7 @@ static void tomoyo_del_transition_control(struct list_head *element) | |||
215 | * | 118 | * |
216 | * Returns nothing. | 119 | * Returns nothing. |
217 | */ | 120 | */ |
218 | static void tomoyo_del_aggregator(struct list_head *element) | 121 | static inline void tomoyo_del_aggregator(struct list_head *element) |
219 | { | 122 | { |
220 | struct tomoyo_aggregator *ptr = | 123 | struct tomoyo_aggregator *ptr = |
221 | container_of(element, typeof(*ptr), head.list); | 124 | container_of(element, typeof(*ptr), head.list); |
@@ -230,7 +133,7 @@ static void tomoyo_del_aggregator(struct list_head *element) | |||
230 | * | 133 | * |
231 | * Returns nothing. | 134 | * Returns nothing. |
232 | */ | 135 | */ |
233 | static void tomoyo_del_manager(struct list_head *element) | 136 | static inline void tomoyo_del_manager(struct list_head *element) |
234 | { | 137 | { |
235 | struct tomoyo_manager *ptr = | 138 | struct tomoyo_manager *ptr = |
236 | container_of(element, typeof(*ptr), head.list); | 139 | container_of(element, typeof(*ptr), head.list); |
@@ -293,6 +196,38 @@ static void tomoyo_del_acl(struct list_head *element) | |||
293 | tomoyo_put_number_union(&entry->flags); | 196 | tomoyo_put_number_union(&entry->flags); |
294 | } | 197 | } |
295 | break; | 198 | break; |
199 | case TOMOYO_TYPE_ENV_ACL: | ||
200 | { | ||
201 | struct tomoyo_env_acl *entry = | ||
202 | container_of(acl, typeof(*entry), head); | ||
203 | |||
204 | tomoyo_put_name(entry->env); | ||
205 | } | ||
206 | break; | ||
207 | case TOMOYO_TYPE_INET_ACL: | ||
208 | { | ||
209 | struct tomoyo_inet_acl *entry = | ||
210 | container_of(acl, typeof(*entry), head); | ||
211 | |||
212 | tomoyo_put_group(entry->address.group); | ||
213 | tomoyo_put_number_union(&entry->port); | ||
214 | } | ||
215 | break; | ||
216 | case TOMOYO_TYPE_UNIX_ACL: | ||
217 | { | ||
218 | struct tomoyo_unix_acl *entry = | ||
219 | container_of(acl, typeof(*entry), head); | ||
220 | |||
221 | tomoyo_put_name_union(&entry->name); | ||
222 | } | ||
223 | break; | ||
224 | case TOMOYO_TYPE_MANUAL_TASK_ACL: | ||
225 | { | ||
226 | struct tomoyo_task_acl *entry = | ||
227 | container_of(acl, typeof(*entry), head); | ||
228 | tomoyo_put_name(entry->domainname); | ||
229 | } | ||
230 | break; | ||
296 | } | 231 | } |
297 | } | 232 | } |
298 | 233 | ||
@@ -301,44 +236,26 @@ static void tomoyo_del_acl(struct list_head *element) | |||
301 | * | 236 | * |
302 | * @element: Pointer to "struct list_head". | 237 | * @element: Pointer to "struct list_head". |
303 | * | 238 | * |
304 | * Returns true if deleted, false otherwise. | 239 | * Returns nothing. |
240 | * | ||
241 | * Caller holds tomoyo_policy_lock mutex. | ||
305 | */ | 242 | */ |
306 | static bool tomoyo_del_domain(struct list_head *element) | 243 | static inline void tomoyo_del_domain(struct list_head *element) |
307 | { | 244 | { |
308 | struct tomoyo_domain_info *domain = | 245 | struct tomoyo_domain_info *domain = |
309 | container_of(element, typeof(*domain), list); | 246 | container_of(element, typeof(*domain), list); |
310 | struct tomoyo_acl_info *acl; | 247 | struct tomoyo_acl_info *acl; |
311 | struct tomoyo_acl_info *tmp; | 248 | struct tomoyo_acl_info *tmp; |
312 | /* | 249 | /* |
313 | * Since we don't protect whole execve() operation using SRCU, | 250 | * Since this domain is referenced from neither |
314 | * we need to recheck domain->users at this point. | 251 | * "struct tomoyo_io_buffer" nor "struct cred"->security, we can delete |
315 | * | 252 | * elements without checking for is_deleted flag. |
316 | * (1) Reader starts SRCU section upon execve(). | ||
317 | * (2) Reader traverses tomoyo_domain_list and finds this domain. | ||
318 | * (3) Writer marks this domain as deleted. | ||
319 | * (4) Garbage collector removes this domain from tomoyo_domain_list | ||
320 | * because this domain is marked as deleted and used by nobody. | ||
321 | * (5) Reader saves reference to this domain into | ||
322 | * "struct linux_binprm"->cred->security . | ||
323 | * (6) Reader finishes SRCU section, although execve() operation has | ||
324 | * not finished yet. | ||
325 | * (7) Garbage collector waits for SRCU synchronization. | ||
326 | * (8) Garbage collector kfree() this domain because this domain is | ||
327 | * used by nobody. | ||
328 | * (9) Reader finishes execve() operation and restores this domain from | ||
329 | * "struct linux_binprm"->cred->security. | ||
330 | * | ||
331 | * By updating domain->users at (5), we can solve this race problem | ||
332 | * by rechecking domain->users at (8). | ||
333 | */ | 253 | */ |
334 | if (atomic_read(&domain->users)) | ||
335 | return false; | ||
336 | list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { | 254 | list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { |
337 | tomoyo_del_acl(&acl->list); | 255 | tomoyo_del_acl(&acl->list); |
338 | tomoyo_memory_free(acl); | 256 | tomoyo_memory_free(acl); |
339 | } | 257 | } |
340 | tomoyo_put_name(domain->domainname); | 258 | tomoyo_put_name(domain->domainname); |
341 | return true; | ||
342 | } | 259 | } |
343 | 260 | ||
344 | /** | 261 | /** |
@@ -387,10 +304,9 @@ void tomoyo_del_condition(struct list_head *element) | |||
387 | * | 304 | * |
388 | * Returns nothing. | 305 | * Returns nothing. |
389 | */ | 306 | */ |
390 | static void tomoyo_del_name(struct list_head *element) | 307 | static inline void tomoyo_del_name(struct list_head *element) |
391 | { | 308 | { |
392 | const struct tomoyo_name *ptr = | 309 | /* Nothing to do. */ |
393 | container_of(element, typeof(*ptr), head.list); | ||
394 | } | 310 | } |
395 | 311 | ||
396 | /** | 312 | /** |
@@ -400,7 +316,7 @@ static void tomoyo_del_name(struct list_head *element) | |||
400 | * | 316 | * |
401 | * Returns nothing. | 317 | * Returns nothing. |
402 | */ | 318 | */ |
403 | static void tomoyo_del_path_group(struct list_head *element) | 319 | static inline void tomoyo_del_path_group(struct list_head *element) |
404 | { | 320 | { |
405 | struct tomoyo_path_group *member = | 321 | struct tomoyo_path_group *member = |
406 | container_of(element, typeof(*member), head.list); | 322 | container_of(element, typeof(*member), head.list); |
@@ -414,7 +330,7 @@ static void tomoyo_del_path_group(struct list_head *element) | |||
414 | * | 330 | * |
415 | * Returns nothing. | 331 | * Returns nothing. |
416 | */ | 332 | */ |
417 | static void tomoyo_del_group(struct list_head *element) | 333 | static inline void tomoyo_del_group(struct list_head *element) |
418 | { | 334 | { |
419 | struct tomoyo_group *group = | 335 | struct tomoyo_group *group = |
420 | container_of(element, typeof(*group), head.list); | 336 | container_of(element, typeof(*group), head.list); |
@@ -422,16 +338,128 @@ static void tomoyo_del_group(struct list_head *element) | |||
422 | } | 338 | } |
423 | 339 | ||
424 | /** | 340 | /** |
341 | * tomoyo_del_address_group - Delete members in "struct tomoyo_address_group". | ||
342 | * | ||
343 | * @element: Pointer to "struct list_head". | ||
344 | * | ||
345 | * Returns nothing. | ||
346 | */ | ||
347 | static inline void tomoyo_del_address_group(struct list_head *element) | ||
348 | { | ||
349 | /* Nothing to do. */ | ||
350 | } | ||
351 | |||
352 | /** | ||
425 | * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group". | 353 | * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group". |
426 | * | 354 | * |
427 | * @element: Pointer to "struct list_head". | 355 | * @element: Pointer to "struct list_head". |
428 | * | 356 | * |
429 | * Returns nothing. | 357 | * Returns nothing. |
430 | */ | 358 | */ |
431 | static void tomoyo_del_number_group(struct list_head *element) | 359 | static inline void tomoyo_del_number_group(struct list_head *element) |
432 | { | 360 | { |
433 | struct tomoyo_number_group *member = | 361 | /* Nothing to do. */ |
434 | container_of(element, typeof(*member), head.list); | 362 | } |
363 | |||
364 | /** | ||
365 | * tomoyo_try_to_gc - Try to kfree() an entry. | ||
366 | * | ||
367 | * @type: One of values in "enum tomoyo_policy_id". | ||
368 | * @element: Pointer to "struct list_head". | ||
369 | * | ||
370 | * Returns nothing. | ||
371 | * | ||
372 | * Caller holds tomoyo_policy_lock mutex. | ||
373 | */ | ||
374 | static void tomoyo_try_to_gc(const enum tomoyo_policy_id type, | ||
375 | struct list_head *element) | ||
376 | { | ||
377 | /* | ||
378 | * __list_del_entry() guarantees that the list element became no longer | ||
379 | * reachable from the list which the element was originally on (e.g. | ||
380 | * tomoyo_domain_list). Also, synchronize_srcu() guarantees that the | ||
381 | * list element became no longer referenced by syscall users. | ||
382 | */ | ||
383 | __list_del_entry(element); | ||
384 | mutex_unlock(&tomoyo_policy_lock); | ||
385 | synchronize_srcu(&tomoyo_ss); | ||
386 | /* | ||
387 | * However, there are two users which may still be using the list | ||
388 | * element. We need to defer until both users forget this element. | ||
389 | * | ||
390 | * Don't kfree() until "struct tomoyo_io_buffer"->r.{domain,group,acl} | ||
391 | * and "struct tomoyo_io_buffer"->w.domain forget this element. | ||
392 | */ | ||
393 | if (tomoyo_struct_used_by_io_buffer(element)) | ||
394 | goto reinject; | ||
395 | switch (type) { | ||
396 | case TOMOYO_ID_TRANSITION_CONTROL: | ||
397 | tomoyo_del_transition_control(element); | ||
398 | break; | ||
399 | case TOMOYO_ID_MANAGER: | ||
400 | tomoyo_del_manager(element); | ||
401 | break; | ||
402 | case TOMOYO_ID_AGGREGATOR: | ||
403 | tomoyo_del_aggregator(element); | ||
404 | break; | ||
405 | case TOMOYO_ID_GROUP: | ||
406 | tomoyo_del_group(element); | ||
407 | break; | ||
408 | case TOMOYO_ID_PATH_GROUP: | ||
409 | tomoyo_del_path_group(element); | ||
410 | break; | ||
411 | case TOMOYO_ID_ADDRESS_GROUP: | ||
412 | tomoyo_del_address_group(element); | ||
413 | break; | ||
414 | case TOMOYO_ID_NUMBER_GROUP: | ||
415 | tomoyo_del_number_group(element); | ||
416 | break; | ||
417 | case TOMOYO_ID_CONDITION: | ||
418 | tomoyo_del_condition(element); | ||
419 | break; | ||
420 | case TOMOYO_ID_NAME: | ||
421 | /* | ||
422 | * Don't kfree() until all "struct tomoyo_io_buffer"->r.w[] | ||
423 | * forget this element. | ||
424 | */ | ||
425 | if (tomoyo_name_used_by_io_buffer | ||
426 | (container_of(element, typeof(struct tomoyo_name), | ||
427 | head.list)->entry.name)) | ||
428 | goto reinject; | ||
429 | tomoyo_del_name(element); | ||
430 | break; | ||
431 | case TOMOYO_ID_ACL: | ||
432 | tomoyo_del_acl(element); | ||
433 | break; | ||
434 | case TOMOYO_ID_DOMAIN: | ||
435 | /* | ||
436 | * Don't kfree() until all "struct cred"->security forget this | ||
437 | * element. | ||
438 | */ | ||
439 | if (atomic_read(&container_of | ||
440 | (element, typeof(struct tomoyo_domain_info), | ||
441 | list)->users)) | ||
442 | goto reinject; | ||
443 | break; | ||
444 | case TOMOYO_MAX_POLICY: | ||
445 | break; | ||
446 | } | ||
447 | mutex_lock(&tomoyo_policy_lock); | ||
448 | if (type == TOMOYO_ID_DOMAIN) | ||
449 | tomoyo_del_domain(element); | ||
450 | tomoyo_memory_free(element); | ||
451 | return; | ||
452 | reinject: | ||
453 | /* | ||
454 | * We can safely reinject this element here bacause | ||
455 | * (1) Appending list elements and removing list elements are protected | ||
456 | * by tomoyo_policy_lock mutex. | ||
457 | * (2) Only this function removes list elements and this function is | ||
458 | * exclusively executed by tomoyo_gc_mutex mutex. | ||
459 | * are true. | ||
460 | */ | ||
461 | mutex_lock(&tomoyo_policy_lock); | ||
462 | list_add_rcu(element, element->prev); | ||
435 | } | 463 | } |
436 | 464 | ||
437 | /** | 465 | /** |
@@ -440,19 +468,19 @@ static void tomoyo_del_number_group(struct list_head *element) | |||
440 | * @id: One of values in "enum tomoyo_policy_id". | 468 | * @id: One of values in "enum tomoyo_policy_id". |
441 | * @member_list: Pointer to "struct list_head". | 469 | * @member_list: Pointer to "struct list_head". |
442 | * | 470 | * |
443 | * Returns true if some elements are deleted, false otherwise. | 471 | * Returns nothing. |
444 | */ | 472 | */ |
445 | static bool tomoyo_collect_member(const enum tomoyo_policy_id id, | 473 | static void tomoyo_collect_member(const enum tomoyo_policy_id id, |
446 | struct list_head *member_list) | 474 | struct list_head *member_list) |
447 | { | 475 | { |
448 | struct tomoyo_acl_head *member; | 476 | struct tomoyo_acl_head *member; |
449 | list_for_each_entry(member, member_list, list) { | 477 | struct tomoyo_acl_head *tmp; |
478 | list_for_each_entry_safe(member, tmp, member_list, list) { | ||
450 | if (!member->is_deleted) | 479 | if (!member->is_deleted) |
451 | continue; | 480 | continue; |
452 | if (!tomoyo_add_to_gc(id, &member->list)) | 481 | member->is_deleted = TOMOYO_GC_IN_PROGRESS; |
453 | return false; | 482 | tomoyo_try_to_gc(id, &member->list); |
454 | } | 483 | } |
455 | return true; | ||
456 | } | 484 | } |
457 | 485 | ||
458 | /** | 486 | /** |
@@ -460,22 +488,22 @@ static bool tomoyo_collect_member(const enum tomoyo_policy_id id, | |||
460 | * | 488 | * |
461 | * @list: Pointer to "struct list_head". | 489 | * @list: Pointer to "struct list_head". |
462 | * | 490 | * |
463 | * Returns true if some elements are deleted, false otherwise. | 491 | * Returns nothing. |
464 | */ | 492 | */ |
465 | static bool tomoyo_collect_acl(struct list_head *list) | 493 | static void tomoyo_collect_acl(struct list_head *list) |
466 | { | 494 | { |
467 | struct tomoyo_acl_info *acl; | 495 | struct tomoyo_acl_info *acl; |
468 | list_for_each_entry(acl, list, list) { | 496 | struct tomoyo_acl_info *tmp; |
497 | list_for_each_entry_safe(acl, tmp, list, list) { | ||
469 | if (!acl->is_deleted) | 498 | if (!acl->is_deleted) |
470 | continue; | 499 | continue; |
471 | if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list)) | 500 | acl->is_deleted = TOMOYO_GC_IN_PROGRESS; |
472 | return false; | 501 | tomoyo_try_to_gc(TOMOYO_ID_ACL, &acl->list); |
473 | } | 502 | } |
474 | return true; | ||
475 | } | 503 | } |
476 | 504 | ||
477 | /** | 505 | /** |
478 | * tomoyo_collect_entry - Scan lists for deleted elements. | 506 | * tomoyo_collect_entry - Try to kfree() deleted elements. |
479 | * | 507 | * |
480 | * Returns nothing. | 508 | * Returns nothing. |
481 | */ | 509 | */ |
@@ -484,174 +512,82 @@ static void tomoyo_collect_entry(void) | |||
484 | int i; | 512 | int i; |
485 | enum tomoyo_policy_id id; | 513 | enum tomoyo_policy_id id; |
486 | struct tomoyo_policy_namespace *ns; | 514 | struct tomoyo_policy_namespace *ns; |
487 | int idx; | 515 | mutex_lock(&tomoyo_policy_lock); |
488 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
489 | return; | ||
490 | idx = tomoyo_read_lock(); | ||
491 | { | 516 | { |
492 | struct tomoyo_domain_info *domain; | 517 | struct tomoyo_domain_info *domain; |
493 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 518 | struct tomoyo_domain_info *tmp; |
494 | if (!tomoyo_collect_acl(&domain->acl_info_list)) | 519 | list_for_each_entry_safe(domain, tmp, &tomoyo_domain_list, |
495 | goto unlock; | 520 | list) { |
521 | tomoyo_collect_acl(&domain->acl_info_list); | ||
496 | if (!domain->is_deleted || atomic_read(&domain->users)) | 522 | if (!domain->is_deleted || atomic_read(&domain->users)) |
497 | continue; | 523 | continue; |
498 | /* | 524 | tomoyo_try_to_gc(TOMOYO_ID_DOMAIN, &domain->list); |
499 | * Nobody is referring this domain. But somebody may | ||
500 | * refer this domain after successful execve(). | ||
501 | * We recheck domain->users after SRCU synchronization. | ||
502 | */ | ||
503 | if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list)) | ||
504 | goto unlock; | ||
505 | } | 525 | } |
506 | } | 526 | } |
507 | list_for_each_entry_rcu(ns, &tomoyo_namespace_list, namespace_list) { | 527 | list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { |
508 | for (id = 0; id < TOMOYO_MAX_POLICY; id++) | 528 | for (id = 0; id < TOMOYO_MAX_POLICY; id++) |
509 | if (!tomoyo_collect_member(id, &ns->policy_list[id])) | 529 | tomoyo_collect_member(id, &ns->policy_list[id]); |
510 | goto unlock; | ||
511 | for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) | 530 | for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) |
512 | if (!tomoyo_collect_acl(&ns->acl_group[i])) | 531 | tomoyo_collect_acl(&ns->acl_group[i]); |
513 | goto unlock; | 532 | } |
533 | { | ||
534 | struct tomoyo_shared_acl_head *ptr; | ||
535 | struct tomoyo_shared_acl_head *tmp; | ||
536 | list_for_each_entry_safe(ptr, tmp, &tomoyo_condition_list, | ||
537 | list) { | ||
538 | if (atomic_read(&ptr->users) > 0) | ||
539 | continue; | ||
540 | atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS); | ||
541 | tomoyo_try_to_gc(TOMOYO_ID_CONDITION, &ptr->list); | ||
542 | } | ||
543 | } | ||
544 | list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { | ||
514 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) { | 545 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) { |
515 | struct list_head *list = &ns->group_list[i]; | 546 | struct list_head *list = &ns->group_list[i]; |
516 | struct tomoyo_group *group; | 547 | struct tomoyo_group *group; |
548 | struct tomoyo_group *tmp; | ||
517 | switch (i) { | 549 | switch (i) { |
518 | case 0: | 550 | case 0: |
519 | id = TOMOYO_ID_PATH_GROUP; | 551 | id = TOMOYO_ID_PATH_GROUP; |
520 | break; | 552 | break; |
521 | default: | 553 | case 1: |
522 | id = TOMOYO_ID_NUMBER_GROUP; | 554 | id = TOMOYO_ID_NUMBER_GROUP; |
523 | break; | 555 | break; |
556 | default: | ||
557 | id = TOMOYO_ID_ADDRESS_GROUP; | ||
558 | break; | ||
524 | } | 559 | } |
525 | list_for_each_entry(group, list, head.list) { | 560 | list_for_each_entry_safe(group, tmp, list, head.list) { |
526 | if (!tomoyo_collect_member | 561 | tomoyo_collect_member(id, &group->member_list); |
527 | (id, &group->member_list)) | ||
528 | goto unlock; | ||
529 | if (!list_empty(&group->member_list) || | 562 | if (!list_empty(&group->member_list) || |
530 | atomic_read(&group->head.users)) | 563 | atomic_read(&group->head.users) > 0) |
531 | continue; | 564 | continue; |
532 | if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, | 565 | atomic_set(&group->head.users, |
533 | &group->head.list)) | 566 | TOMOYO_GC_IN_PROGRESS); |
534 | goto unlock; | 567 | tomoyo_try_to_gc(TOMOYO_ID_GROUP, |
568 | &group->head.list); | ||
535 | } | 569 | } |
536 | } | 570 | } |
537 | } | 571 | } |
538 | id = TOMOYO_ID_CONDITION; | 572 | for (i = 0; i < TOMOYO_MAX_HASH; i++) { |
539 | for (i = 0; i < TOMOYO_MAX_HASH + 1; i++) { | 573 | struct list_head *list = &tomoyo_name_list[i]; |
540 | struct list_head *list = !i ? | ||
541 | &tomoyo_condition_list : &tomoyo_name_list[i - 1]; | ||
542 | struct tomoyo_shared_acl_head *ptr; | 574 | struct tomoyo_shared_acl_head *ptr; |
543 | list_for_each_entry(ptr, list, list) { | 575 | struct tomoyo_shared_acl_head *tmp; |
544 | if (atomic_read(&ptr->users)) | 576 | list_for_each_entry_safe(ptr, tmp, list, list) { |
577 | if (atomic_read(&ptr->users) > 0) | ||
545 | continue; | 578 | continue; |
546 | if (!tomoyo_add_to_gc(id, &ptr->list)) | 579 | atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS); |
547 | goto unlock; | 580 | tomoyo_try_to_gc(TOMOYO_ID_NAME, &ptr->list); |
548 | } | 581 | } |
549 | id = TOMOYO_ID_NAME; | ||
550 | } | 582 | } |
551 | unlock: | ||
552 | tomoyo_read_unlock(idx); | ||
553 | mutex_unlock(&tomoyo_policy_lock); | 583 | mutex_unlock(&tomoyo_policy_lock); |
554 | } | 584 | } |
555 | 585 | ||
556 | /** | 586 | /** |
557 | * tomoyo_kfree_entry - Delete entries in tomoyo_gc_list. | ||
558 | * | ||
559 | * Returns true if some entries were kfree()d, false otherwise. | ||
560 | */ | ||
561 | static bool tomoyo_kfree_entry(void) | ||
562 | { | ||
563 | struct tomoyo_gc *p; | ||
564 | struct tomoyo_gc *tmp; | ||
565 | bool result = false; | ||
566 | |||
567 | list_for_each_entry_safe(p, tmp, &tomoyo_gc_list, list) { | ||
568 | struct list_head *element = p->element; | ||
569 | |||
570 | /* | ||
571 | * list_del_rcu() in tomoyo_add_to_gc() guarantees that the | ||
572 | * list element became no longer reachable from the list which | ||
573 | * the element was originally on (e.g. tomoyo_domain_list). | ||
574 | * Also, synchronize_srcu() in tomoyo_gc_thread() guarantees | ||
575 | * that the list element became no longer referenced by syscall | ||
576 | * users. | ||
577 | * | ||
578 | * However, there are three users which may still be using the | ||
579 | * list element. We need to defer until all of these users | ||
580 | * forget the list element. | ||
581 | * | ||
582 | * Firstly, defer until "struct tomoyo_io_buffer"->r.{domain, | ||
583 | * group,acl} and "struct tomoyo_io_buffer"->w.domain forget | ||
584 | * the list element. | ||
585 | */ | ||
586 | if (tomoyo_struct_used_by_io_buffer(element)) | ||
587 | continue; | ||
588 | /* | ||
589 | * Secondly, defer until all other elements in the | ||
590 | * tomoyo_gc_list list forget the list element. | ||
591 | */ | ||
592 | if (tomoyo_element_linked_by_gc((const u8 *) element, p->size)) | ||
593 | continue; | ||
594 | switch (p->type) { | ||
595 | case TOMOYO_ID_TRANSITION_CONTROL: | ||
596 | tomoyo_del_transition_control(element); | ||
597 | break; | ||
598 | case TOMOYO_ID_AGGREGATOR: | ||
599 | tomoyo_del_aggregator(element); | ||
600 | break; | ||
601 | case TOMOYO_ID_MANAGER: | ||
602 | tomoyo_del_manager(element); | ||
603 | break; | ||
604 | case TOMOYO_ID_CONDITION: | ||
605 | tomoyo_del_condition(element); | ||
606 | break; | ||
607 | case TOMOYO_ID_NAME: | ||
608 | /* | ||
609 | * Thirdly, defer until all "struct tomoyo_io_buffer" | ||
610 | * ->r.w[] forget the list element. | ||
611 | */ | ||
612 | if (tomoyo_name_used_by_io_buffer( | ||
613 | container_of(element, typeof(struct tomoyo_name), | ||
614 | head.list)->entry.name, p->size)) | ||
615 | continue; | ||
616 | tomoyo_del_name(element); | ||
617 | break; | ||
618 | case TOMOYO_ID_ACL: | ||
619 | tomoyo_del_acl(element); | ||
620 | break; | ||
621 | case TOMOYO_ID_DOMAIN: | ||
622 | if (!tomoyo_del_domain(element)) | ||
623 | continue; | ||
624 | break; | ||
625 | case TOMOYO_ID_PATH_GROUP: | ||
626 | tomoyo_del_path_group(element); | ||
627 | break; | ||
628 | case TOMOYO_ID_GROUP: | ||
629 | tomoyo_del_group(element); | ||
630 | break; | ||
631 | case TOMOYO_ID_NUMBER_GROUP: | ||
632 | tomoyo_del_number_group(element); | ||
633 | break; | ||
634 | case TOMOYO_MAX_POLICY: | ||
635 | break; | ||
636 | } | ||
637 | tomoyo_memory_free(element); | ||
638 | list_del(&p->list); | ||
639 | kfree(p); | ||
640 | tomoyo_gc_list_len--; | ||
641 | result = true; | ||
642 | } | ||
643 | return result; | ||
644 | } | ||
645 | |||
646 | /** | ||
647 | * tomoyo_gc_thread - Garbage collector thread function. | 587 | * tomoyo_gc_thread - Garbage collector thread function. |
648 | * | 588 | * |
649 | * @unused: Unused. | 589 | * @unused: Unused. |
650 | * | 590 | * |
651 | * In case OOM-killer choose this thread for termination, we create this thread | ||
652 | * as a short live thread whenever /sys/kernel/security/tomoyo/ interface was | ||
653 | * close()d. | ||
654 | * | ||
655 | * Returns 0. | 591 | * Returns 0. |
656 | */ | 592 | */ |
657 | static int tomoyo_gc_thread(void *unused) | 593 | static int tomoyo_gc_thread(void *unused) |
@@ -660,13 +596,7 @@ static int tomoyo_gc_thread(void *unused) | |||
660 | static DEFINE_MUTEX(tomoyo_gc_mutex); | 596 | static DEFINE_MUTEX(tomoyo_gc_mutex); |
661 | if (!mutex_trylock(&tomoyo_gc_mutex)) | 597 | if (!mutex_trylock(&tomoyo_gc_mutex)) |
662 | goto out; | 598 | goto out; |
663 | daemonize("GC for TOMOYO"); | 599 | tomoyo_collect_entry(); |
664 | do { | ||
665 | tomoyo_collect_entry(); | ||
666 | if (list_empty(&tomoyo_gc_list)) | ||
667 | break; | ||
668 | synchronize_srcu(&tomoyo_ss); | ||
669 | } while (tomoyo_kfree_entry()); | ||
670 | { | 600 | { |
671 | struct tomoyo_io_buffer *head; | 601 | struct tomoyo_io_buffer *head; |
672 | struct tomoyo_io_buffer *tmp; | 602 | struct tomoyo_io_buffer *tmp; |
diff --git a/security/tomoyo/group.c b/security/tomoyo/group.c index 5fb0e1298400..50092534ec54 100644 --- a/security/tomoyo/group.c +++ b/security/tomoyo/group.c | |||
@@ -42,7 +42,26 @@ static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a, | |||
42 | } | 42 | } |
43 | 43 | ||
44 | /** | 44 | /** |
45 | * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group" list. | 45 | * tomoyo_same_address_group - Check for duplicated "struct tomoyo_address_group" entry. |
46 | * | ||
47 | * @a: Pointer to "struct tomoyo_acl_head". | ||
48 | * @b: Pointer to "struct tomoyo_acl_head". | ||
49 | * | ||
50 | * Returns true if @a == @b, false otherwise. | ||
51 | */ | ||
52 | static bool tomoyo_same_address_group(const struct tomoyo_acl_head *a, | ||
53 | const struct tomoyo_acl_head *b) | ||
54 | { | ||
55 | const struct tomoyo_address_group *p1 = container_of(a, typeof(*p1), | ||
56 | head); | ||
57 | const struct tomoyo_address_group *p2 = container_of(b, typeof(*p2), | ||
58 | head); | ||
59 | |||
60 | return tomoyo_same_ipaddr_union(&p1->address, &p2->address); | ||
61 | } | ||
62 | |||
63 | /** | ||
64 | * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" list. | ||
46 | * | 65 | * |
47 | * @param: Pointer to "struct tomoyo_acl_param". | 66 | * @param: Pointer to "struct tomoyo_acl_param". |
48 | * @type: Type of this group. | 67 | * @type: Type of this group. |
@@ -77,6 +96,14 @@ int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type) | |||
77 | * tomoyo_put_number_union() is not needed because | 96 | * tomoyo_put_number_union() is not needed because |
78 | * param->data[0] != '@'. | 97 | * param->data[0] != '@'. |
79 | */ | 98 | */ |
99 | } else { | ||
100 | struct tomoyo_address_group e = { }; | ||
101 | |||
102 | if (param->data[0] == '@' || | ||
103 | !tomoyo_parse_ipaddr_union(param, &e.address)) | ||
104 | goto out; | ||
105 | error = tomoyo_update_policy(&e.head, sizeof(e), param, | ||
106 | tomoyo_same_address_group); | ||
80 | } | 107 | } |
81 | out: | 108 | out: |
82 | tomoyo_put_group(group); | 109 | tomoyo_put_group(group); |
@@ -137,3 +164,35 @@ bool tomoyo_number_matches_group(const unsigned long min, | |||
137 | } | 164 | } |
138 | return matched; | 165 | return matched; |
139 | } | 166 | } |
167 | |||
168 | /** | ||
169 | * tomoyo_address_matches_group - Check whether the given address matches members of the given address group. | ||
170 | * | ||
171 | * @is_ipv6: True if @address is an IPv6 address. | ||
172 | * @address: An IPv4 or IPv6 address. | ||
173 | * @group: Pointer to "struct tomoyo_address_group". | ||
174 | * | ||
175 | * Returns true if @address matches addresses in @group group, false otherwise. | ||
176 | * | ||
177 | * Caller holds tomoyo_read_lock(). | ||
178 | */ | ||
179 | bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address, | ||
180 | const struct tomoyo_group *group) | ||
181 | { | ||
182 | struct tomoyo_address_group *member; | ||
183 | bool matched = false; | ||
184 | const u8 size = is_ipv6 ? 16 : 4; | ||
185 | |||
186 | list_for_each_entry_rcu(member, &group->member_list, head.list) { | ||
187 | if (member->head.is_deleted) | ||
188 | continue; | ||
189 | if (member->address.is_ipv6 != is_ipv6) | ||
190 | continue; | ||
191 | if (memcmp(&member->address.ip[0], address, size) > 0 || | ||
192 | memcmp(address, &member->address.ip[1], size) > 0) | ||
193 | continue; | ||
194 | matched = true; | ||
195 | break; | ||
196 | } | ||
197 | return matched; | ||
198 | } | ||
diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c index 7a56051146c2..0e995716cc25 100644 --- a/security/tomoyo/memory.c +++ b/security/tomoyo/memory.c | |||
@@ -27,8 +27,6 @@ void tomoyo_warn_oom(const char *function) | |||
27 | panic("MAC Initialization failed.\n"); | 27 | panic("MAC Initialization failed.\n"); |
28 | } | 28 | } |
29 | 29 | ||
30 | /* Lock for protecting tomoyo_memory_used. */ | ||
31 | static DEFINE_SPINLOCK(tomoyo_policy_memory_lock); | ||
32 | /* Memoy currently used by policy/audit log/query. */ | 30 | /* Memoy currently used by policy/audit log/query. */ |
33 | unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; | 31 | unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; |
34 | /* Memory quota for "policy"/"audit log"/"query". */ | 32 | /* Memory quota for "policy"/"audit log"/"query". */ |
@@ -42,22 +40,19 @@ unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT]; | |||
42 | * Returns true on success, false otherwise. | 40 | * Returns true on success, false otherwise. |
43 | * | 41 | * |
44 | * Returns true if @ptr is not NULL and quota not exceeded, false otherwise. | 42 | * Returns true if @ptr is not NULL and quota not exceeded, false otherwise. |
43 | * | ||
44 | * Caller holds tomoyo_policy_lock mutex. | ||
45 | */ | 45 | */ |
46 | bool tomoyo_memory_ok(void *ptr) | 46 | bool tomoyo_memory_ok(void *ptr) |
47 | { | 47 | { |
48 | if (ptr) { | 48 | if (ptr) { |
49 | const size_t s = ksize(ptr); | 49 | const size_t s = ksize(ptr); |
50 | bool result; | ||
51 | spin_lock(&tomoyo_policy_memory_lock); | ||
52 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s; | 50 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s; |
53 | result = !tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] || | 51 | if (!tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] || |
54 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <= | 52 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <= |
55 | tomoyo_memory_quota[TOMOYO_MEMORY_POLICY]; | 53 | tomoyo_memory_quota[TOMOYO_MEMORY_POLICY]) |
56 | if (!result) | ||
57 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s; | ||
58 | spin_unlock(&tomoyo_policy_memory_lock); | ||
59 | if (result) | ||
60 | return true; | 54 | return true; |
55 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s; | ||
61 | } | 56 | } |
62 | tomoyo_warn_oom(__func__); | 57 | tomoyo_warn_oom(__func__); |
63 | return false; | 58 | return false; |
@@ -71,6 +66,8 @@ bool tomoyo_memory_ok(void *ptr) | |||
71 | * | 66 | * |
72 | * Returns pointer to allocated memory on success, NULL otherwise. | 67 | * Returns pointer to allocated memory on success, NULL otherwise. |
73 | * @data is zero-cleared on success. | 68 | * @data is zero-cleared on success. |
69 | * | ||
70 | * Caller holds tomoyo_policy_lock mutex. | ||
74 | */ | 71 | */ |
75 | void *tomoyo_commit_ok(void *data, const unsigned int size) | 72 | void *tomoyo_commit_ok(void *data, const unsigned int size) |
76 | { | 73 | { |
@@ -85,20 +82,6 @@ void *tomoyo_commit_ok(void *data, const unsigned int size) | |||
85 | } | 82 | } |
86 | 83 | ||
87 | /** | 84 | /** |
88 | * tomoyo_memory_free - Free memory for elements. | ||
89 | * | ||
90 | * @ptr: Pointer to allocated memory. | ||
91 | */ | ||
92 | void tomoyo_memory_free(void *ptr) | ||
93 | { | ||
94 | size_t s = ksize(ptr); | ||
95 | spin_lock(&tomoyo_policy_memory_lock); | ||
96 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s; | ||
97 | spin_unlock(&tomoyo_policy_memory_lock); | ||
98 | kfree(ptr); | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group". | 85 | * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group". |
103 | * | 86 | * |
104 | * @param: Pointer to "struct tomoyo_acl_param". | 87 | * @param: Pointer to "struct tomoyo_acl_param". |
@@ -123,7 +106,8 @@ struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, | |||
123 | goto out; | 106 | goto out; |
124 | list = ¶m->ns->group_list[idx]; | 107 | list = ¶m->ns->group_list[idx]; |
125 | list_for_each_entry(group, list, head.list) { | 108 | list_for_each_entry(group, list, head.list) { |
126 | if (e.group_name != group->group_name) | 109 | if (e.group_name != group->group_name || |
110 | atomic_read(&group->head.users) == TOMOYO_GC_IN_PROGRESS) | ||
127 | continue; | 111 | continue; |
128 | atomic_inc(&group->head.users); | 112 | atomic_inc(&group->head.users); |
129 | found = true; | 113 | found = true; |
@@ -175,7 +159,8 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) | |||
175 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 159 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
176 | return NULL; | 160 | return NULL; |
177 | list_for_each_entry(ptr, head, head.list) { | 161 | list_for_each_entry(ptr, head, head.list) { |
178 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) | 162 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name) || |
163 | atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS) | ||
179 | continue; | 164 | continue; |
180 | atomic_inc(&ptr->head.users); | 165 | atomic_inc(&ptr->head.users); |
181 | goto out; | 166 | goto out; |
diff --git a/security/tomoyo/network.c b/security/tomoyo/network.c new file mode 100644 index 000000000000..97527710a72a --- /dev/null +++ b/security/tomoyo/network.c | |||
@@ -0,0 +1,771 @@ | |||
1 | /* | ||
2 | * security/tomoyo/network.c | ||
3 | * | ||
4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION | ||
5 | */ | ||
6 | |||
7 | #include "common.h" | ||
8 | #include <linux/slab.h> | ||
9 | |||
10 | /* Structure for holding inet domain socket's address. */ | ||
11 | struct tomoyo_inet_addr_info { | ||
12 | __be16 port; /* In network byte order. */ | ||
13 | const __be32 *address; /* In network byte order. */ | ||
14 | bool is_ipv6; | ||
15 | }; | ||
16 | |||
17 | /* Structure for holding unix domain socket's address. */ | ||
18 | struct tomoyo_unix_addr_info { | ||
19 | u8 *addr; /* This may not be '\0' terminated string. */ | ||
20 | unsigned int addr_len; | ||
21 | }; | ||
22 | |||
23 | /* Structure for holding socket address. */ | ||
24 | struct tomoyo_addr_info { | ||
25 | u8 protocol; | ||
26 | u8 operation; | ||
27 | struct tomoyo_inet_addr_info inet; | ||
28 | struct tomoyo_unix_addr_info unix0; | ||
29 | }; | ||
30 | |||
31 | /* String table for socket's protocols. */ | ||
32 | const char * const tomoyo_proto_keyword[TOMOYO_SOCK_MAX] = { | ||
33 | [SOCK_STREAM] = "stream", | ||
34 | [SOCK_DGRAM] = "dgram", | ||
35 | [SOCK_RAW] = "raw", | ||
36 | [SOCK_SEQPACKET] = "seqpacket", | ||
37 | [0] = " ", /* Dummy for avoiding NULL pointer dereference. */ | ||
38 | [4] = " ", /* Dummy for avoiding NULL pointer dereference. */ | ||
39 | }; | ||
40 | |||
41 | /** | ||
42 | * tomoyo_parse_ipaddr_union - Parse an IP address. | ||
43 | * | ||
44 | * @param: Pointer to "struct tomoyo_acl_param". | ||
45 | * @ptr: Pointer to "struct tomoyo_ipaddr_union". | ||
46 | * | ||
47 | * Returns true on success, false otherwise. | ||
48 | */ | ||
49 | bool tomoyo_parse_ipaddr_union(struct tomoyo_acl_param *param, | ||
50 | struct tomoyo_ipaddr_union *ptr) | ||
51 | { | ||
52 | u8 * const min = ptr->ip[0].in6_u.u6_addr8; | ||
53 | u8 * const max = ptr->ip[1].in6_u.u6_addr8; | ||
54 | char *address = tomoyo_read_token(param); | ||
55 | const char *end; | ||
56 | |||
57 | if (!strchr(address, ':') && | ||
58 | in4_pton(address, -1, min, '-', &end) > 0) { | ||
59 | ptr->is_ipv6 = false; | ||
60 | if (!*end) | ||
61 | ptr->ip[1].s6_addr32[0] = ptr->ip[0].s6_addr32[0]; | ||
62 | else if (*end++ != '-' || | ||
63 | in4_pton(end, -1, max, '\0', &end) <= 0 || *end) | ||
64 | return false; | ||
65 | return true; | ||
66 | } | ||
67 | if (in6_pton(address, -1, min, '-', &end) > 0) { | ||
68 | ptr->is_ipv6 = true; | ||
69 | if (!*end) | ||
70 | memmove(max, min, sizeof(u16) * 8); | ||
71 | else if (*end++ != '-' || | ||
72 | in6_pton(end, -1, max, '\0', &end) <= 0 || *end) | ||
73 | return false; | ||
74 | return true; | ||
75 | } | ||
76 | return false; | ||
77 | } | ||
78 | |||
79 | /** | ||
80 | * tomoyo_print_ipv4 - Print an IPv4 address. | ||
81 | * | ||
82 | * @buffer: Buffer to write to. | ||
83 | * @buffer_len: Size of @buffer. | ||
84 | * @min_ip: Pointer to __be32. | ||
85 | * @max_ip: Pointer to __be32. | ||
86 | * | ||
87 | * Returns nothing. | ||
88 | */ | ||
89 | static void tomoyo_print_ipv4(char *buffer, const unsigned int buffer_len, | ||
90 | const __be32 *min_ip, const __be32 *max_ip) | ||
91 | { | ||
92 | snprintf(buffer, buffer_len, "%pI4%c%pI4", min_ip, | ||
93 | *min_ip == *max_ip ? '\0' : '-', max_ip); | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * tomoyo_print_ipv6 - Print an IPv6 address. | ||
98 | * | ||
99 | * @buffer: Buffer to write to. | ||
100 | * @buffer_len: Size of @buffer. | ||
101 | * @min_ip: Pointer to "struct in6_addr". | ||
102 | * @max_ip: Pointer to "struct in6_addr". | ||
103 | * | ||
104 | * Returns nothing. | ||
105 | */ | ||
106 | static void tomoyo_print_ipv6(char *buffer, const unsigned int buffer_len, | ||
107 | const struct in6_addr *min_ip, | ||
108 | const struct in6_addr *max_ip) | ||
109 | { | ||
110 | snprintf(buffer, buffer_len, "%pI6c%c%pI6c", min_ip, | ||
111 | !memcmp(min_ip, max_ip, 16) ? '\0' : '-', max_ip); | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * tomoyo_print_ip - Print an IP address. | ||
116 | * | ||
117 | * @buf: Buffer to write to. | ||
118 | * @size: Size of @buf. | ||
119 | * @ptr: Pointer to "struct ipaddr_union". | ||
120 | * | ||
121 | * Returns nothing. | ||
122 | */ | ||
123 | void tomoyo_print_ip(char *buf, const unsigned int size, | ||
124 | const struct tomoyo_ipaddr_union *ptr) | ||
125 | { | ||
126 | if (ptr->is_ipv6) | ||
127 | tomoyo_print_ipv6(buf, size, &ptr->ip[0], &ptr->ip[1]); | ||
128 | else | ||
129 | tomoyo_print_ipv4(buf, size, &ptr->ip[0].s6_addr32[0], | ||
130 | &ptr->ip[1].s6_addr32[0]); | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * Mapping table from "enum tomoyo_network_acl_index" to | ||
135 | * "enum tomoyo_mac_index" for inet domain socket. | ||
136 | */ | ||
137 | static const u8 tomoyo_inet2mac | ||
138 | [TOMOYO_SOCK_MAX][TOMOYO_MAX_NETWORK_OPERATION] = { | ||
139 | [SOCK_STREAM] = { | ||
140 | [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_STREAM_BIND, | ||
141 | [TOMOYO_NETWORK_LISTEN] = | ||
142 | TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN, | ||
143 | [TOMOYO_NETWORK_CONNECT] = | ||
144 | TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT, | ||
145 | }, | ||
146 | [SOCK_DGRAM] = { | ||
147 | [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_DGRAM_BIND, | ||
148 | [TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_INET_DGRAM_SEND, | ||
149 | }, | ||
150 | [SOCK_RAW] = { | ||
151 | [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_RAW_BIND, | ||
152 | [TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_INET_RAW_SEND, | ||
153 | }, | ||
154 | }; | ||
155 | |||
156 | /* | ||
157 | * Mapping table from "enum tomoyo_network_acl_index" to | ||
158 | * "enum tomoyo_mac_index" for unix domain socket. | ||
159 | */ | ||
160 | static const u8 tomoyo_unix2mac | ||
161 | [TOMOYO_SOCK_MAX][TOMOYO_MAX_NETWORK_OPERATION] = { | ||
162 | [SOCK_STREAM] = { | ||
163 | [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND, | ||
164 | [TOMOYO_NETWORK_LISTEN] = | ||
165 | TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN, | ||
166 | [TOMOYO_NETWORK_CONNECT] = | ||
167 | TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT, | ||
168 | }, | ||
169 | [SOCK_DGRAM] = { | ||
170 | [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND, | ||
171 | [TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND, | ||
172 | }, | ||
173 | [SOCK_SEQPACKET] = { | ||
174 | [TOMOYO_NETWORK_BIND] = | ||
175 | TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND, | ||
176 | [TOMOYO_NETWORK_LISTEN] = | ||
177 | TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN, | ||
178 | [TOMOYO_NETWORK_CONNECT] = | ||
179 | TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT, | ||
180 | }, | ||
181 | }; | ||
182 | |||
183 | /** | ||
184 | * tomoyo_same_inet_acl - Check for duplicated "struct tomoyo_inet_acl" entry. | ||
185 | * | ||
186 | * @a: Pointer to "struct tomoyo_acl_info". | ||
187 | * @b: Pointer to "struct tomoyo_acl_info". | ||
188 | * | ||
189 | * Returns true if @a == @b except permission bits, false otherwise. | ||
190 | */ | ||
191 | static bool tomoyo_same_inet_acl(const struct tomoyo_acl_info *a, | ||
192 | const struct tomoyo_acl_info *b) | ||
193 | { | ||
194 | const struct tomoyo_inet_acl *p1 = container_of(a, typeof(*p1), head); | ||
195 | const struct tomoyo_inet_acl *p2 = container_of(b, typeof(*p2), head); | ||
196 | |||
197 | return p1->protocol == p2->protocol && | ||
198 | tomoyo_same_ipaddr_union(&p1->address, &p2->address) && | ||
199 | tomoyo_same_number_union(&p1->port, &p2->port); | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * tomoyo_same_unix_acl - Check for duplicated "struct tomoyo_unix_acl" entry. | ||
204 | * | ||
205 | * @a: Pointer to "struct tomoyo_acl_info". | ||
206 | * @b: Pointer to "struct tomoyo_acl_info". | ||
207 | * | ||
208 | * Returns true if @a == @b except permission bits, false otherwise. | ||
209 | */ | ||
210 | static bool tomoyo_same_unix_acl(const struct tomoyo_acl_info *a, | ||
211 | const struct tomoyo_acl_info *b) | ||
212 | { | ||
213 | const struct tomoyo_unix_acl *p1 = container_of(a, typeof(*p1), head); | ||
214 | const struct tomoyo_unix_acl *p2 = container_of(b, typeof(*p2), head); | ||
215 | |||
216 | return p1->protocol == p2->protocol && | ||
217 | tomoyo_same_name_union(&p1->name, &p2->name); | ||
218 | } | ||
219 | |||
220 | /** | ||
221 | * tomoyo_merge_inet_acl - Merge duplicated "struct tomoyo_inet_acl" entry. | ||
222 | * | ||
223 | * @a: Pointer to "struct tomoyo_acl_info". | ||
224 | * @b: Pointer to "struct tomoyo_acl_info". | ||
225 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | ||
226 | * | ||
227 | * Returns true if @a is empty, false otherwise. | ||
228 | */ | ||
229 | static bool tomoyo_merge_inet_acl(struct tomoyo_acl_info *a, | ||
230 | struct tomoyo_acl_info *b, | ||
231 | const bool is_delete) | ||
232 | { | ||
233 | u8 * const a_perm = | ||
234 | &container_of(a, struct tomoyo_inet_acl, head)->perm; | ||
235 | u8 perm = *a_perm; | ||
236 | const u8 b_perm = container_of(b, struct tomoyo_inet_acl, head)->perm; | ||
237 | |||
238 | if (is_delete) | ||
239 | perm &= ~b_perm; | ||
240 | else | ||
241 | perm |= b_perm; | ||
242 | *a_perm = perm; | ||
243 | return !perm; | ||
244 | } | ||
245 | |||
246 | /** | ||
247 | * tomoyo_merge_unix_acl - Merge duplicated "struct tomoyo_unix_acl" entry. | ||
248 | * | ||
249 | * @a: Pointer to "struct tomoyo_acl_info". | ||
250 | * @b: Pointer to "struct tomoyo_acl_info". | ||
251 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | ||
252 | * | ||
253 | * Returns true if @a is empty, false otherwise. | ||
254 | */ | ||
255 | static bool tomoyo_merge_unix_acl(struct tomoyo_acl_info *a, | ||
256 | struct tomoyo_acl_info *b, | ||
257 | const bool is_delete) | ||
258 | { | ||
259 | u8 * const a_perm = | ||
260 | &container_of(a, struct tomoyo_unix_acl, head)->perm; | ||
261 | u8 perm = *a_perm; | ||
262 | const u8 b_perm = container_of(b, struct tomoyo_unix_acl, head)->perm; | ||
263 | |||
264 | if (is_delete) | ||
265 | perm &= ~b_perm; | ||
266 | else | ||
267 | perm |= b_perm; | ||
268 | *a_perm = perm; | ||
269 | return !perm; | ||
270 | } | ||
271 | |||
272 | /** | ||
273 | * tomoyo_write_inet_network - Write "struct tomoyo_inet_acl" list. | ||
274 | * | ||
275 | * @param: Pointer to "struct tomoyo_acl_param". | ||
276 | * | ||
277 | * Returns 0 on success, negative value otherwise. | ||
278 | * | ||
279 | * Caller holds tomoyo_read_lock(). | ||
280 | */ | ||
281 | int tomoyo_write_inet_network(struct tomoyo_acl_param *param) | ||
282 | { | ||
283 | struct tomoyo_inet_acl e = { .head.type = TOMOYO_TYPE_INET_ACL }; | ||
284 | int error = -EINVAL; | ||
285 | u8 type; | ||
286 | const char *protocol = tomoyo_read_token(param); | ||
287 | const char *operation = tomoyo_read_token(param); | ||
288 | |||
289 | for (e.protocol = 0; e.protocol < TOMOYO_SOCK_MAX; e.protocol++) | ||
290 | if (!strcmp(protocol, tomoyo_proto_keyword[e.protocol])) | ||
291 | break; | ||
292 | for (type = 0; type < TOMOYO_MAX_NETWORK_OPERATION; type++) | ||
293 | if (tomoyo_permstr(operation, tomoyo_socket_keyword[type])) | ||
294 | e.perm |= 1 << type; | ||
295 | if (e.protocol == TOMOYO_SOCK_MAX || !e.perm) | ||
296 | return -EINVAL; | ||
297 | if (param->data[0] == '@') { | ||
298 | param->data++; | ||
299 | e.address.group = | ||
300 | tomoyo_get_group(param, TOMOYO_ADDRESS_GROUP); | ||
301 | if (!e.address.group) | ||
302 | return -ENOMEM; | ||
303 | } else { | ||
304 | if (!tomoyo_parse_ipaddr_union(param, &e.address)) | ||
305 | goto out; | ||
306 | } | ||
307 | if (!tomoyo_parse_number_union(param, &e.port) || | ||
308 | e.port.values[1] > 65535) | ||
309 | goto out; | ||
310 | error = tomoyo_update_domain(&e.head, sizeof(e), param, | ||
311 | tomoyo_same_inet_acl, | ||
312 | tomoyo_merge_inet_acl); | ||
313 | out: | ||
314 | tomoyo_put_group(e.address.group); | ||
315 | tomoyo_put_number_union(&e.port); | ||
316 | return error; | ||
317 | } | ||
318 | |||
319 | /** | ||
320 | * tomoyo_write_unix_network - Write "struct tomoyo_unix_acl" list. | ||
321 | * | ||
322 | * @param: Pointer to "struct tomoyo_acl_param". | ||
323 | * | ||
324 | * Returns 0 on success, negative value otherwise. | ||
325 | */ | ||
326 | int tomoyo_write_unix_network(struct tomoyo_acl_param *param) | ||
327 | { | ||
328 | struct tomoyo_unix_acl e = { .head.type = TOMOYO_TYPE_UNIX_ACL }; | ||
329 | int error; | ||
330 | u8 type; | ||
331 | const char *protocol = tomoyo_read_token(param); | ||
332 | const char *operation = tomoyo_read_token(param); | ||
333 | |||
334 | for (e.protocol = 0; e.protocol < TOMOYO_SOCK_MAX; e.protocol++) | ||
335 | if (!strcmp(protocol, tomoyo_proto_keyword[e.protocol])) | ||
336 | break; | ||
337 | for (type = 0; type < TOMOYO_MAX_NETWORK_OPERATION; type++) | ||
338 | if (tomoyo_permstr(operation, tomoyo_socket_keyword[type])) | ||
339 | e.perm |= 1 << type; | ||
340 | if (e.protocol == TOMOYO_SOCK_MAX || !e.perm) | ||
341 | return -EINVAL; | ||
342 | if (!tomoyo_parse_name_union(param, &e.name)) | ||
343 | return -EINVAL; | ||
344 | error = tomoyo_update_domain(&e.head, sizeof(e), param, | ||
345 | tomoyo_same_unix_acl, | ||
346 | tomoyo_merge_unix_acl); | ||
347 | tomoyo_put_name_union(&e.name); | ||
348 | return error; | ||
349 | } | ||
350 | |||
351 | /** | ||
352 | * tomoyo_audit_net_log - Audit network log. | ||
353 | * | ||
354 | * @r: Pointer to "struct tomoyo_request_info". | ||
355 | * @family: Name of socket family ("inet" or "unix"). | ||
356 | * @protocol: Name of protocol in @family. | ||
357 | * @operation: Name of socket operation. | ||
358 | * @address: Name of address. | ||
359 | * | ||
360 | * Returns 0 on success, negative value otherwise. | ||
361 | */ | ||
362 | static int tomoyo_audit_net_log(struct tomoyo_request_info *r, | ||
363 | const char *family, const u8 protocol, | ||
364 | const u8 operation, const char *address) | ||
365 | { | ||
366 | return tomoyo_supervisor(r, "network %s %s %s %s\n", family, | ||
367 | tomoyo_proto_keyword[protocol], | ||
368 | tomoyo_socket_keyword[operation], address); | ||
369 | } | ||
370 | |||
371 | /** | ||
372 | * tomoyo_audit_inet_log - Audit INET network log. | ||
373 | * | ||
374 | * @r: Pointer to "struct tomoyo_request_info". | ||
375 | * | ||
376 | * Returns 0 on success, negative value otherwise. | ||
377 | */ | ||
378 | static int tomoyo_audit_inet_log(struct tomoyo_request_info *r) | ||
379 | { | ||
380 | char buf[128]; | ||
381 | int len; | ||
382 | const __be32 *address = r->param.inet_network.address; | ||
383 | |||
384 | if (r->param.inet_network.is_ipv6) | ||
385 | tomoyo_print_ipv6(buf, sizeof(buf), (const struct in6_addr *) | ||
386 | address, (const struct in6_addr *) address); | ||
387 | else | ||
388 | tomoyo_print_ipv4(buf, sizeof(buf), address, address); | ||
389 | len = strlen(buf); | ||
390 | snprintf(buf + len, sizeof(buf) - len, " %u", | ||
391 | r->param.inet_network.port); | ||
392 | return tomoyo_audit_net_log(r, "inet", r->param.inet_network.protocol, | ||
393 | r->param.inet_network.operation, buf); | ||
394 | } | ||
395 | |||
396 | /** | ||
397 | * tomoyo_audit_unix_log - Audit UNIX network log. | ||
398 | * | ||
399 | * @r: Pointer to "struct tomoyo_request_info". | ||
400 | * | ||
401 | * Returns 0 on success, negative value otherwise. | ||
402 | */ | ||
403 | static int tomoyo_audit_unix_log(struct tomoyo_request_info *r) | ||
404 | { | ||
405 | return tomoyo_audit_net_log(r, "unix", r->param.unix_network.protocol, | ||
406 | r->param.unix_network.operation, | ||
407 | r->param.unix_network.address->name); | ||
408 | } | ||
409 | |||
410 | /** | ||
411 | * tomoyo_check_inet_acl - Check permission for inet domain socket operation. | ||
412 | * | ||
413 | * @r: Pointer to "struct tomoyo_request_info". | ||
414 | * @ptr: Pointer to "struct tomoyo_acl_info". | ||
415 | * | ||
416 | * Returns true if granted, false otherwise. | ||
417 | */ | ||
418 | static bool tomoyo_check_inet_acl(struct tomoyo_request_info *r, | ||
419 | const struct tomoyo_acl_info *ptr) | ||
420 | { | ||
421 | const struct tomoyo_inet_acl *acl = | ||
422 | container_of(ptr, typeof(*acl), head); | ||
423 | const u8 size = r->param.inet_network.is_ipv6 ? 16 : 4; | ||
424 | |||
425 | if (!(acl->perm & (1 << r->param.inet_network.operation)) || | ||
426 | !tomoyo_compare_number_union(r->param.inet_network.port, | ||
427 | &acl->port)) | ||
428 | return false; | ||
429 | if (acl->address.group) | ||
430 | return tomoyo_address_matches_group | ||
431 | (r->param.inet_network.is_ipv6, | ||
432 | r->param.inet_network.address, acl->address.group); | ||
433 | return acl->address.is_ipv6 == r->param.inet_network.is_ipv6 && | ||
434 | memcmp(&acl->address.ip[0], | ||
435 | r->param.inet_network.address, size) <= 0 && | ||
436 | memcmp(r->param.inet_network.address, | ||
437 | &acl->address.ip[1], size) <= 0; | ||
438 | } | ||
439 | |||
440 | /** | ||
441 | * tomoyo_check_unix_acl - Check permission for unix domain socket operation. | ||
442 | * | ||
443 | * @r: Pointer to "struct tomoyo_request_info". | ||
444 | * @ptr: Pointer to "struct tomoyo_acl_info". | ||
445 | * | ||
446 | * Returns true if granted, false otherwise. | ||
447 | */ | ||
448 | static bool tomoyo_check_unix_acl(struct tomoyo_request_info *r, | ||
449 | const struct tomoyo_acl_info *ptr) | ||
450 | { | ||
451 | const struct tomoyo_unix_acl *acl = | ||
452 | container_of(ptr, typeof(*acl), head); | ||
453 | |||
454 | return (acl->perm & (1 << r->param.unix_network.operation)) && | ||
455 | tomoyo_compare_name_union(r->param.unix_network.address, | ||
456 | &acl->name); | ||
457 | } | ||
458 | |||
459 | /** | ||
460 | * tomoyo_inet_entry - Check permission for INET network operation. | ||
461 | * | ||
462 | * @address: Pointer to "struct tomoyo_addr_info". | ||
463 | * | ||
464 | * Returns 0 on success, negative value otherwise. | ||
465 | */ | ||
466 | static int tomoyo_inet_entry(const struct tomoyo_addr_info *address) | ||
467 | { | ||
468 | const int idx = tomoyo_read_lock(); | ||
469 | struct tomoyo_request_info r; | ||
470 | int error = 0; | ||
471 | const u8 type = tomoyo_inet2mac[address->protocol][address->operation]; | ||
472 | |||
473 | if (type && tomoyo_init_request_info(&r, NULL, type) | ||
474 | != TOMOYO_CONFIG_DISABLED) { | ||
475 | r.param_type = TOMOYO_TYPE_INET_ACL; | ||
476 | r.param.inet_network.protocol = address->protocol; | ||
477 | r.param.inet_network.operation = address->operation; | ||
478 | r.param.inet_network.is_ipv6 = address->inet.is_ipv6; | ||
479 | r.param.inet_network.address = address->inet.address; | ||
480 | r.param.inet_network.port = ntohs(address->inet.port); | ||
481 | do { | ||
482 | tomoyo_check_acl(&r, tomoyo_check_inet_acl); | ||
483 | error = tomoyo_audit_inet_log(&r); | ||
484 | } while (error == TOMOYO_RETRY_REQUEST); | ||
485 | } | ||
486 | tomoyo_read_unlock(idx); | ||
487 | return error; | ||
488 | } | ||
489 | |||
490 | /** | ||
491 | * tomoyo_check_inet_address - Check permission for inet domain socket's operation. | ||
492 | * | ||
493 | * @addr: Pointer to "struct sockaddr". | ||
494 | * @addr_len: Size of @addr. | ||
495 | * @port: Port number. | ||
496 | * @address: Pointer to "struct tomoyo_addr_info". | ||
497 | * | ||
498 | * Returns 0 on success, negative value otherwise. | ||
499 | */ | ||
500 | static int tomoyo_check_inet_address(const struct sockaddr *addr, | ||
501 | const unsigned int addr_len, | ||
502 | const u16 port, | ||
503 | struct tomoyo_addr_info *address) | ||
504 | { | ||
505 | struct tomoyo_inet_addr_info *i = &address->inet; | ||
506 | |||
507 | switch (addr->sa_family) { | ||
508 | case AF_INET6: | ||
509 | if (addr_len < SIN6_LEN_RFC2133) | ||
510 | goto skip; | ||
511 | i->is_ipv6 = true; | ||
512 | i->address = (__be32 *) | ||
513 | ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr; | ||
514 | i->port = ((struct sockaddr_in6 *) addr)->sin6_port; | ||
515 | break; | ||
516 | case AF_INET: | ||
517 | if (addr_len < sizeof(struct sockaddr_in)) | ||
518 | goto skip; | ||
519 | i->is_ipv6 = false; | ||
520 | i->address = (__be32 *) | ||
521 | &((struct sockaddr_in *) addr)->sin_addr; | ||
522 | i->port = ((struct sockaddr_in *) addr)->sin_port; | ||
523 | break; | ||
524 | default: | ||
525 | goto skip; | ||
526 | } | ||
527 | if (address->protocol == SOCK_RAW) | ||
528 | i->port = htons(port); | ||
529 | return tomoyo_inet_entry(address); | ||
530 | skip: | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | /** | ||
535 | * tomoyo_unix_entry - Check permission for UNIX network operation. | ||
536 | * | ||
537 | * @address: Pointer to "struct tomoyo_addr_info". | ||
538 | * | ||
539 | * Returns 0 on success, negative value otherwise. | ||
540 | */ | ||
541 | static int tomoyo_unix_entry(const struct tomoyo_addr_info *address) | ||
542 | { | ||
543 | const int idx = tomoyo_read_lock(); | ||
544 | struct tomoyo_request_info r; | ||
545 | int error = 0; | ||
546 | const u8 type = tomoyo_unix2mac[address->protocol][address->operation]; | ||
547 | |||
548 | if (type && tomoyo_init_request_info(&r, NULL, type) | ||
549 | != TOMOYO_CONFIG_DISABLED) { | ||
550 | char *buf = address->unix0.addr; | ||
551 | int len = address->unix0.addr_len - sizeof(sa_family_t); | ||
552 | |||
553 | if (len <= 0) { | ||
554 | buf = "anonymous"; | ||
555 | len = 9; | ||
556 | } else if (buf[0]) { | ||
557 | len = strnlen(buf, len); | ||
558 | } | ||
559 | buf = tomoyo_encode2(buf, len); | ||
560 | if (buf) { | ||
561 | struct tomoyo_path_info addr; | ||
562 | |||
563 | addr.name = buf; | ||
564 | tomoyo_fill_path_info(&addr); | ||
565 | r.param_type = TOMOYO_TYPE_UNIX_ACL; | ||
566 | r.param.unix_network.protocol = address->protocol; | ||
567 | r.param.unix_network.operation = address->operation; | ||
568 | r.param.unix_network.address = &addr; | ||
569 | do { | ||
570 | tomoyo_check_acl(&r, tomoyo_check_unix_acl); | ||
571 | error = tomoyo_audit_unix_log(&r); | ||
572 | } while (error == TOMOYO_RETRY_REQUEST); | ||
573 | kfree(buf); | ||
574 | } else | ||
575 | error = -ENOMEM; | ||
576 | } | ||
577 | tomoyo_read_unlock(idx); | ||
578 | return error; | ||
579 | } | ||
580 | |||
581 | /** | ||
582 | * tomoyo_check_unix_address - Check permission for unix domain socket's operation. | ||
583 | * | ||
584 | * @addr: Pointer to "struct sockaddr". | ||
585 | * @addr_len: Size of @addr. | ||
586 | * @address: Pointer to "struct tomoyo_addr_info". | ||
587 | * | ||
588 | * Returns 0 on success, negative value otherwise. | ||
589 | */ | ||
590 | static int tomoyo_check_unix_address(struct sockaddr *addr, | ||
591 | const unsigned int addr_len, | ||
592 | struct tomoyo_addr_info *address) | ||
593 | { | ||
594 | struct tomoyo_unix_addr_info *u = &address->unix0; | ||
595 | |||
596 | if (addr->sa_family != AF_UNIX) | ||
597 | return 0; | ||
598 | u->addr = ((struct sockaddr_un *) addr)->sun_path; | ||
599 | u->addr_len = addr_len; | ||
600 | return tomoyo_unix_entry(address); | ||
601 | } | ||
602 | |||
603 | /** | ||
604 | * tomoyo_kernel_service - Check whether I'm kernel service or not. | ||
605 | * | ||
606 | * Returns true if I'm kernel service, false otherwise. | ||
607 | */ | ||
608 | static bool tomoyo_kernel_service(void) | ||
609 | { | ||
610 | /* Nothing to do if I am a kernel service. */ | ||
611 | return segment_eq(get_fs(), KERNEL_DS); | ||
612 | } | ||
613 | |||
614 | /** | ||
615 | * tomoyo_sock_family - Get socket's family. | ||
616 | * | ||
617 | * @sk: Pointer to "struct sock". | ||
618 | * | ||
619 | * Returns one of PF_INET, PF_INET6, PF_UNIX or 0. | ||
620 | */ | ||
621 | static u8 tomoyo_sock_family(struct sock *sk) | ||
622 | { | ||
623 | u8 family; | ||
624 | |||
625 | if (tomoyo_kernel_service()) | ||
626 | return 0; | ||
627 | family = sk->sk_family; | ||
628 | switch (family) { | ||
629 | case PF_INET: | ||
630 | case PF_INET6: | ||
631 | case PF_UNIX: | ||
632 | return family; | ||
633 | default: | ||
634 | return 0; | ||
635 | } | ||
636 | } | ||
637 | |||
638 | /** | ||
639 | * tomoyo_socket_listen_permission - Check permission for listening a socket. | ||
640 | * | ||
641 | * @sock: Pointer to "struct socket". | ||
642 | * | ||
643 | * Returns 0 on success, negative value otherwise. | ||
644 | */ | ||
645 | int tomoyo_socket_listen_permission(struct socket *sock) | ||
646 | { | ||
647 | struct tomoyo_addr_info address; | ||
648 | const u8 family = tomoyo_sock_family(sock->sk); | ||
649 | const unsigned int type = sock->type; | ||
650 | struct sockaddr_storage addr; | ||
651 | int addr_len; | ||
652 | |||
653 | if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET)) | ||
654 | return 0; | ||
655 | { | ||
656 | const int error = sock->ops->getname(sock, (struct sockaddr *) | ||
657 | &addr, &addr_len, 0); | ||
658 | |||
659 | if (error) | ||
660 | return error; | ||
661 | } | ||
662 | address.protocol = type; | ||
663 | address.operation = TOMOYO_NETWORK_LISTEN; | ||
664 | if (family == PF_UNIX) | ||
665 | return tomoyo_check_unix_address((struct sockaddr *) &addr, | ||
666 | addr_len, &address); | ||
667 | return tomoyo_check_inet_address((struct sockaddr *) &addr, addr_len, | ||
668 | 0, &address); | ||
669 | } | ||
670 | |||
671 | /** | ||
672 | * tomoyo_socket_connect_permission - Check permission for setting the remote address of a socket. | ||
673 | * | ||
674 | * @sock: Pointer to "struct socket". | ||
675 | * @addr: Pointer to "struct sockaddr". | ||
676 | * @addr_len: Size of @addr. | ||
677 | * | ||
678 | * Returns 0 on success, negative value otherwise. | ||
679 | */ | ||
680 | int tomoyo_socket_connect_permission(struct socket *sock, | ||
681 | struct sockaddr *addr, int addr_len) | ||
682 | { | ||
683 | struct tomoyo_addr_info address; | ||
684 | const u8 family = tomoyo_sock_family(sock->sk); | ||
685 | const unsigned int type = sock->type; | ||
686 | |||
687 | if (!family) | ||
688 | return 0; | ||
689 | address.protocol = type; | ||
690 | switch (type) { | ||
691 | case SOCK_DGRAM: | ||
692 | case SOCK_RAW: | ||
693 | address.operation = TOMOYO_NETWORK_SEND; | ||
694 | break; | ||
695 | case SOCK_STREAM: | ||
696 | case SOCK_SEQPACKET: | ||
697 | address.operation = TOMOYO_NETWORK_CONNECT; | ||
698 | break; | ||
699 | default: | ||
700 | return 0; | ||
701 | } | ||
702 | if (family == PF_UNIX) | ||
703 | return tomoyo_check_unix_address(addr, addr_len, &address); | ||
704 | return tomoyo_check_inet_address(addr, addr_len, sock->sk->sk_protocol, | ||
705 | &address); | ||
706 | } | ||
707 | |||
708 | /** | ||
709 | * tomoyo_socket_bind_permission - Check permission for setting the local address of a socket. | ||
710 | * | ||
711 | * @sock: Pointer to "struct socket". | ||
712 | * @addr: Pointer to "struct sockaddr". | ||
713 | * @addr_len: Size of @addr. | ||
714 | * | ||
715 | * Returns 0 on success, negative value otherwise. | ||
716 | */ | ||
717 | int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr, | ||
718 | int addr_len) | ||
719 | { | ||
720 | struct tomoyo_addr_info address; | ||
721 | const u8 family = tomoyo_sock_family(sock->sk); | ||
722 | const unsigned int type = sock->type; | ||
723 | |||
724 | if (!family) | ||
725 | return 0; | ||
726 | switch (type) { | ||
727 | case SOCK_STREAM: | ||
728 | case SOCK_DGRAM: | ||
729 | case SOCK_RAW: | ||
730 | case SOCK_SEQPACKET: | ||
731 | address.protocol = type; | ||
732 | address.operation = TOMOYO_NETWORK_BIND; | ||
733 | break; | ||
734 | default: | ||
735 | return 0; | ||
736 | } | ||
737 | if (family == PF_UNIX) | ||
738 | return tomoyo_check_unix_address(addr, addr_len, &address); | ||
739 | return tomoyo_check_inet_address(addr, addr_len, sock->sk->sk_protocol, | ||
740 | &address); | ||
741 | } | ||
742 | |||
743 | /** | ||
744 | * tomoyo_socket_sendmsg_permission - Check permission for sending a datagram. | ||
745 | * | ||
746 | * @sock: Pointer to "struct socket". | ||
747 | * @msg: Pointer to "struct msghdr". | ||
748 | * @size: Unused. | ||
749 | * | ||
750 | * Returns 0 on success, negative value otherwise. | ||
751 | */ | ||
752 | int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg, | ||
753 | int size) | ||
754 | { | ||
755 | struct tomoyo_addr_info address; | ||
756 | const u8 family = tomoyo_sock_family(sock->sk); | ||
757 | const unsigned int type = sock->type; | ||
758 | |||
759 | if (!msg->msg_name || !family || | ||
760 | (type != SOCK_DGRAM && type != SOCK_RAW)) | ||
761 | return 0; | ||
762 | address.protocol = type; | ||
763 | address.operation = TOMOYO_NETWORK_SEND; | ||
764 | if (family == PF_UNIX) | ||
765 | return tomoyo_check_unix_address((struct sockaddr *) | ||
766 | msg->msg_name, | ||
767 | msg->msg_namelen, &address); | ||
768 | return tomoyo_check_inet_address((struct sockaddr *) msg->msg_name, | ||
769 | msg->msg_namelen, | ||
770 | sock->sk->sk_protocol, &address); | ||
771 | } | ||
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 6c601bd300f3..738bbdf8d4c7 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -15,17 +15,19 @@ | |||
15 | #include "../../fs/internal.h" | 15 | #include "../../fs/internal.h" |
16 | 16 | ||
17 | /** | 17 | /** |
18 | * tomoyo_encode: Convert binary string to ascii string. | 18 | * tomoyo_encode2 - Encode binary string to ascii string. |
19 | * | 19 | * |
20 | * @str: String in binary format. | 20 | * @str: String in binary format. |
21 | * @str_len: Size of @str in byte. | ||
21 | * | 22 | * |
22 | * Returns pointer to @str in ascii format on success, NULL otherwise. | 23 | * Returns pointer to @str in ascii format on success, NULL otherwise. |
23 | * | 24 | * |
24 | * This function uses kzalloc(), so caller must kfree() if this function | 25 | * This function uses kzalloc(), so caller must kfree() if this function |
25 | * didn't return NULL. | 26 | * didn't return NULL. |
26 | */ | 27 | */ |
27 | char *tomoyo_encode(const char *str) | 28 | char *tomoyo_encode2(const char *str, int str_len) |
28 | { | 29 | { |
30 | int i; | ||
29 | int len = 0; | 31 | int len = 0; |
30 | const char *p = str; | 32 | const char *p = str; |
31 | char *cp; | 33 | char *cp; |
@@ -33,8 +35,9 @@ char *tomoyo_encode(const char *str) | |||
33 | 35 | ||
34 | if (!p) | 36 | if (!p) |
35 | return NULL; | 37 | return NULL; |
36 | while (*p) { | 38 | for (i = 0; i < str_len; i++) { |
37 | const unsigned char c = *p++; | 39 | const unsigned char c = p[i]; |
40 | |||
38 | if (c == '\\') | 41 | if (c == '\\') |
39 | len += 2; | 42 | len += 2; |
40 | else if (c > ' ' && c < 127) | 43 | else if (c > ' ' && c < 127) |
@@ -49,8 +52,8 @@ char *tomoyo_encode(const char *str) | |||
49 | return NULL; | 52 | return NULL; |
50 | cp0 = cp; | 53 | cp0 = cp; |
51 | p = str; | 54 | p = str; |
52 | while (*p) { | 55 | for (i = 0; i < str_len; i++) { |
53 | const unsigned char c = *p++; | 56 | const unsigned char c = p[i]; |
54 | 57 | ||
55 | if (c == '\\') { | 58 | if (c == '\\') { |
56 | *cp++ = '\\'; | 59 | *cp++ = '\\'; |
@@ -68,6 +71,21 @@ char *tomoyo_encode(const char *str) | |||
68 | } | 71 | } |
69 | 72 | ||
70 | /** | 73 | /** |
74 | * tomoyo_encode - Encode binary string to ascii string. | ||
75 | * | ||
76 | * @str: String in binary format. | ||
77 | * | ||
78 | * Returns pointer to @str in ascii format on success, NULL otherwise. | ||
79 | * | ||
80 | * This function uses kzalloc(), so caller must kfree() if this function | ||
81 | * didn't return NULL. | ||
82 | */ | ||
83 | char *tomoyo_encode(const char *str) | ||
84 | { | ||
85 | return str ? tomoyo_encode2(str, strlen(str)) : NULL; | ||
86 | } | ||
87 | |||
88 | /** | ||
71 | * tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root. | 89 | * tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root. |
72 | * | 90 | * |
73 | * @path: Pointer to "struct path". | 91 | * @path: Pointer to "struct path". |
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c index a49c3bfd4dd5..2672ac4f3beb 100644 --- a/security/tomoyo/securityfs_if.c +++ b/security/tomoyo/securityfs_if.c | |||
@@ -8,6 +8,124 @@ | |||
8 | #include "common.h" | 8 | #include "common.h" |
9 | 9 | ||
10 | /** | 10 | /** |
11 | * tomoyo_check_task_acl - Check permission for task operation. | ||
12 | * | ||
13 | * @r: Pointer to "struct tomoyo_request_info". | ||
14 | * @ptr: Pointer to "struct tomoyo_acl_info". | ||
15 | * | ||
16 | * Returns true if granted, false otherwise. | ||
17 | */ | ||
18 | static bool tomoyo_check_task_acl(struct tomoyo_request_info *r, | ||
19 | const struct tomoyo_acl_info *ptr) | ||
20 | { | ||
21 | const struct tomoyo_task_acl *acl = container_of(ptr, typeof(*acl), | ||
22 | head); | ||
23 | return !tomoyo_pathcmp(r->param.task.domainname, acl->domainname); | ||
24 | } | ||
25 | |||
26 | /** | ||
27 | * tomoyo_write_self - write() for /sys/kernel/security/tomoyo/self_domain interface. | ||
28 | * | ||
29 | * @file: Pointer to "struct file". | ||
30 | * @buf: Domainname to transit to. | ||
31 | * @count: Size of @buf. | ||
32 | * @ppos: Unused. | ||
33 | * | ||
34 | * Returns @count on success, negative value otherwise. | ||
35 | * | ||
36 | * If domain transition was permitted but the domain transition failed, this | ||
37 | * function returns error rather than terminating current thread with SIGKILL. | ||
38 | */ | ||
39 | static ssize_t tomoyo_write_self(struct file *file, const char __user *buf, | ||
40 | size_t count, loff_t *ppos) | ||
41 | { | ||
42 | char *data; | ||
43 | int error; | ||
44 | if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10) | ||
45 | return -ENOMEM; | ||
46 | data = kzalloc(count + 1, GFP_NOFS); | ||
47 | if (!data) | ||
48 | return -ENOMEM; | ||
49 | if (copy_from_user(data, buf, count)) { | ||
50 | error = -EFAULT; | ||
51 | goto out; | ||
52 | } | ||
53 | tomoyo_normalize_line(data); | ||
54 | if (tomoyo_correct_domain(data)) { | ||
55 | const int idx = tomoyo_read_lock(); | ||
56 | struct tomoyo_path_info name; | ||
57 | struct tomoyo_request_info r; | ||
58 | name.name = data; | ||
59 | tomoyo_fill_path_info(&name); | ||
60 | /* Check "task manual_domain_transition" permission. */ | ||
61 | tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE); | ||
62 | r.param_type = TOMOYO_TYPE_MANUAL_TASK_ACL; | ||
63 | r.param.task.domainname = &name; | ||
64 | tomoyo_check_acl(&r, tomoyo_check_task_acl); | ||
65 | if (!r.granted) | ||
66 | error = -EPERM; | ||
67 | else { | ||
68 | struct tomoyo_domain_info *new_domain = | ||
69 | tomoyo_assign_domain(data, true); | ||
70 | if (!new_domain) { | ||
71 | error = -ENOENT; | ||
72 | } else { | ||
73 | struct cred *cred = prepare_creds(); | ||
74 | if (!cred) { | ||
75 | error = -ENOMEM; | ||
76 | } else { | ||
77 | struct tomoyo_domain_info *old_domain = | ||
78 | cred->security; | ||
79 | cred->security = new_domain; | ||
80 | atomic_inc(&new_domain->users); | ||
81 | atomic_dec(&old_domain->users); | ||
82 | commit_creds(cred); | ||
83 | error = 0; | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | tomoyo_read_unlock(idx); | ||
88 | } else | ||
89 | error = -EINVAL; | ||
90 | out: | ||
91 | kfree(data); | ||
92 | return error ? error : count; | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * tomoyo_read_self - read() for /sys/kernel/security/tomoyo/self_domain interface. | ||
97 | * | ||
98 | * @file: Pointer to "struct file". | ||
99 | * @buf: Domainname which current thread belongs to. | ||
100 | * @count: Size of @buf. | ||
101 | * @ppos: Bytes read by now. | ||
102 | * | ||
103 | * Returns read size on success, negative value otherwise. | ||
104 | */ | ||
105 | static ssize_t tomoyo_read_self(struct file *file, char __user *buf, | ||
106 | size_t count, loff_t *ppos) | ||
107 | { | ||
108 | const char *domain = tomoyo_domain()->domainname->name; | ||
109 | loff_t len = strlen(domain); | ||
110 | loff_t pos = *ppos; | ||
111 | if (pos >= len || !count) | ||
112 | return 0; | ||
113 | len -= pos; | ||
114 | if (count < len) | ||
115 | len = count; | ||
116 | if (copy_to_user(buf, domain + pos, len)) | ||
117 | return -EFAULT; | ||
118 | *ppos += len; | ||
119 | return len; | ||
120 | } | ||
121 | |||
122 | /* Operations for /sys/kernel/security/tomoyo/self_domain interface. */ | ||
123 | static const struct file_operations tomoyo_self_operations = { | ||
124 | .write = tomoyo_write_self, | ||
125 | .read = tomoyo_read_self, | ||
126 | }; | ||
127 | |||
128 | /** | ||
11 | * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. | 129 | * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. |
12 | * | 130 | * |
13 | * @inode: Pointer to "struct inode". | 131 | * @inode: Pointer to "struct inode". |
@@ -135,8 +253,6 @@ static int __init tomoyo_initerface_init(void) | |||
135 | TOMOYO_EXCEPTIONPOLICY); | 253 | TOMOYO_EXCEPTIONPOLICY); |
136 | tomoyo_create_entry("audit", 0400, tomoyo_dir, | 254 | tomoyo_create_entry("audit", 0400, tomoyo_dir, |
137 | TOMOYO_AUDIT); | 255 | TOMOYO_AUDIT); |
138 | tomoyo_create_entry("self_domain", 0400, tomoyo_dir, | ||
139 | TOMOYO_SELFDOMAIN); | ||
140 | tomoyo_create_entry(".process_status", 0600, tomoyo_dir, | 256 | tomoyo_create_entry(".process_status", 0600, tomoyo_dir, |
141 | TOMOYO_PROCESS_STATUS); | 257 | TOMOYO_PROCESS_STATUS); |
142 | tomoyo_create_entry("stat", 0644, tomoyo_dir, | 258 | tomoyo_create_entry("stat", 0644, tomoyo_dir, |
@@ -147,6 +263,9 @@ static int __init tomoyo_initerface_init(void) | |||
147 | TOMOYO_MANAGER); | 263 | TOMOYO_MANAGER); |
148 | tomoyo_create_entry("version", 0400, tomoyo_dir, | 264 | tomoyo_create_entry("version", 0400, tomoyo_dir, |
149 | TOMOYO_VERSION); | 265 | TOMOYO_VERSION); |
266 | securityfs_create_file("self_domain", 0666, tomoyo_dir, NULL, | ||
267 | &tomoyo_self_operations); | ||
268 | tomoyo_load_builtin_policy(); | ||
150 | return 0; | 269 | return 0; |
151 | } | 270 | } |
152 | 271 | ||
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index f776400a8f31..4b327b691745 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -442,6 +442,64 @@ static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path) | |||
442 | return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path); | 442 | return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path); |
443 | } | 443 | } |
444 | 444 | ||
445 | /** | ||
446 | * tomoyo_socket_listen - Check permission for listen(). | ||
447 | * | ||
448 | * @sock: Pointer to "struct socket". | ||
449 | * @backlog: Backlog parameter. | ||
450 | * | ||
451 | * Returns 0 on success, negative value otherwise. | ||
452 | */ | ||
453 | static int tomoyo_socket_listen(struct socket *sock, int backlog) | ||
454 | { | ||
455 | return tomoyo_socket_listen_permission(sock); | ||
456 | } | ||
457 | |||
458 | /** | ||
459 | * tomoyo_socket_connect - Check permission for connect(). | ||
460 | * | ||
461 | * @sock: Pointer to "struct socket". | ||
462 | * @addr: Pointer to "struct sockaddr". | ||
463 | * @addr_len: Size of @addr. | ||
464 | * | ||
465 | * Returns 0 on success, negative value otherwise. | ||
466 | */ | ||
467 | static int tomoyo_socket_connect(struct socket *sock, struct sockaddr *addr, | ||
468 | int addr_len) | ||
469 | { | ||
470 | return tomoyo_socket_connect_permission(sock, addr, addr_len); | ||
471 | } | ||
472 | |||
473 | /** | ||
474 | * tomoyo_socket_bind - Check permission for bind(). | ||
475 | * | ||
476 | * @sock: Pointer to "struct socket". | ||
477 | * @addr: Pointer to "struct sockaddr". | ||
478 | * @addr_len: Size of @addr. | ||
479 | * | ||
480 | * Returns 0 on success, negative value otherwise. | ||
481 | */ | ||
482 | static int tomoyo_socket_bind(struct socket *sock, struct sockaddr *addr, | ||
483 | int addr_len) | ||
484 | { | ||
485 | return tomoyo_socket_bind_permission(sock, addr, addr_len); | ||
486 | } | ||
487 | |||
488 | /** | ||
489 | * tomoyo_socket_sendmsg - Check permission for sendmsg(). | ||
490 | * | ||
491 | * @sock: Pointer to "struct socket". | ||
492 | * @msg: Pointer to "struct msghdr". | ||
493 | * @size: Size of message. | ||
494 | * | ||
495 | * Returns 0 on success, negative value otherwise. | ||
496 | */ | ||
497 | static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg, | ||
498 | int size) | ||
499 | { | ||
500 | return tomoyo_socket_sendmsg_permission(sock, msg, size); | ||
501 | } | ||
502 | |||
445 | /* | 503 | /* |
446 | * tomoyo_security_ops is a "struct security_operations" which is used for | 504 | * tomoyo_security_ops is a "struct security_operations" which is used for |
447 | * registering TOMOYO. | 505 | * registering TOMOYO. |
@@ -472,6 +530,10 @@ static struct security_operations tomoyo_security_ops = { | |||
472 | .sb_mount = tomoyo_sb_mount, | 530 | .sb_mount = tomoyo_sb_mount, |
473 | .sb_umount = tomoyo_sb_umount, | 531 | .sb_umount = tomoyo_sb_umount, |
474 | .sb_pivotroot = tomoyo_sb_pivotroot, | 532 | .sb_pivotroot = tomoyo_sb_pivotroot, |
533 | .socket_bind = tomoyo_socket_bind, | ||
534 | .socket_connect = tomoyo_socket_connect, | ||
535 | .socket_listen = tomoyo_socket_listen, | ||
536 | .socket_sendmsg = tomoyo_socket_sendmsg, | ||
475 | }; | 537 | }; |
476 | 538 | ||
477 | /* Lock for GC. */ | 539 | /* Lock for GC. */ |
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index c36bd1107fc8..4a9b4b2eb755 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c | |||
@@ -42,6 +42,39 @@ const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = { | |||
42 | [TOMOYO_MAC_FILE_MOUNT] = TOMOYO_MAC_CATEGORY_FILE, | 42 | [TOMOYO_MAC_FILE_MOUNT] = TOMOYO_MAC_CATEGORY_FILE, |
43 | [TOMOYO_MAC_FILE_UMOUNT] = TOMOYO_MAC_CATEGORY_FILE, | 43 | [TOMOYO_MAC_FILE_UMOUNT] = TOMOYO_MAC_CATEGORY_FILE, |
44 | [TOMOYO_MAC_FILE_PIVOT_ROOT] = TOMOYO_MAC_CATEGORY_FILE, | 44 | [TOMOYO_MAC_FILE_PIVOT_ROOT] = TOMOYO_MAC_CATEGORY_FILE, |
45 | /* CONFIG::network group */ | ||
46 | [TOMOYO_MAC_NETWORK_INET_STREAM_BIND] = | ||
47 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
48 | [TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN] = | ||
49 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
50 | [TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT] = | ||
51 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
52 | [TOMOYO_MAC_NETWORK_INET_DGRAM_BIND] = | ||
53 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
54 | [TOMOYO_MAC_NETWORK_INET_DGRAM_SEND] = | ||
55 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
56 | [TOMOYO_MAC_NETWORK_INET_RAW_BIND] = | ||
57 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
58 | [TOMOYO_MAC_NETWORK_INET_RAW_SEND] = | ||
59 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
60 | [TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND] = | ||
61 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
62 | [TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN] = | ||
63 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
64 | [TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT] = | ||
65 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
66 | [TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND] = | ||
67 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
68 | [TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND] = | ||
69 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
70 | [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND] = | ||
71 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
72 | [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = | ||
73 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
74 | [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = | ||
75 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
76 | /* CONFIG::misc group */ | ||
77 | [TOMOYO_MAC_ENVIRON] = TOMOYO_MAC_CATEGORY_MISC, | ||
45 | }; | 78 | }; |
46 | 79 | ||
47 | /** | 80 | /** |
@@ -126,6 +159,31 @@ char *tomoyo_read_token(struct tomoyo_acl_param *param) | |||
126 | } | 159 | } |
127 | 160 | ||
128 | /** | 161 | /** |
162 | * tomoyo_get_domainname - Read a domainname from a line. | ||
163 | * | ||
164 | * @param: Pointer to "struct tomoyo_acl_param". | ||
165 | * | ||
166 | * Returns a domainname on success, NULL otherwise. | ||
167 | */ | ||
168 | const struct tomoyo_path_info *tomoyo_get_domainname | ||
169 | (struct tomoyo_acl_param *param) | ||
170 | { | ||
171 | char *start = param->data; | ||
172 | char *pos = start; | ||
173 | while (*pos) { | ||
174 | if (*pos++ != ' ' || *pos++ == '/') | ||
175 | continue; | ||
176 | pos -= 2; | ||
177 | *pos++ = '\0'; | ||
178 | break; | ||
179 | } | ||
180 | param->data = pos; | ||
181 | if (tomoyo_correct_domain(start)) | ||
182 | return tomoyo_get_name(start); | ||
183 | return NULL; | ||
184 | } | ||
185 | |||
186 | /** | ||
129 | * tomoyo_parse_ulong - Parse an "unsigned long" value. | 187 | * tomoyo_parse_ulong - Parse an "unsigned long" value. |
130 | * | 188 | * |
131 | * @result: Pointer to "unsigned long". | 189 | * @result: Pointer to "unsigned long". |
@@ -920,14 +978,17 @@ int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, | |||
920 | const u8 index) | 978 | const u8 index) |
921 | { | 979 | { |
922 | u8 mode; | 980 | u8 mode; |
923 | const u8 category = TOMOYO_MAC_CATEGORY_FILE; | 981 | struct tomoyo_profile *p; |
982 | |||
924 | if (!tomoyo_policy_loaded) | 983 | if (!tomoyo_policy_loaded) |
925 | return TOMOYO_CONFIG_DISABLED; | 984 | return TOMOYO_CONFIG_DISABLED; |
926 | mode = tomoyo_profile(ns, profile)->config[index]; | 985 | p = tomoyo_profile(ns, profile); |
986 | mode = p->config[index]; | ||
927 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) | 987 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) |
928 | mode = tomoyo_profile(ns, profile)->config[category]; | 988 | mode = p->config[tomoyo_index2category[index] |
989 | + TOMOYO_MAX_MAC_INDEX]; | ||
929 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) | 990 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) |
930 | mode = tomoyo_profile(ns, profile)->default_config; | 991 | mode = p->default_config; |
931 | return mode & 3; | 992 | return mode & 3; |
932 | } | 993 | } |
933 | 994 | ||
@@ -996,6 +1057,17 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) | |||
996 | perm = container_of(ptr, struct tomoyo_mkdev_acl, | 1057 | perm = container_of(ptr, struct tomoyo_mkdev_acl, |
997 | head)->perm; | 1058 | head)->perm; |
998 | break; | 1059 | break; |
1060 | case TOMOYO_TYPE_INET_ACL: | ||
1061 | perm = container_of(ptr, struct tomoyo_inet_acl, | ||
1062 | head)->perm; | ||
1063 | break; | ||
1064 | case TOMOYO_TYPE_UNIX_ACL: | ||
1065 | perm = container_of(ptr, struct tomoyo_unix_acl, | ||
1066 | head)->perm; | ||
1067 | break; | ||
1068 | case TOMOYO_TYPE_MANUAL_TASK_ACL: | ||
1069 | perm = 0; | ||
1070 | break; | ||
999 | default: | 1071 | default: |
1000 | perm = 1; | 1072 | perm = 1; |
1001 | } | 1073 | } |