diff options
Diffstat (limited to 'security/tomoyo')
-rw-r--r-- | security/tomoyo/Kconfig | 2 | ||||
-rw-r--r-- | security/tomoyo/Makefile | 2 | ||||
-rw-r--r-- | security/tomoyo/common.c | 104 | ||||
-rw-r--r-- | security/tomoyo/common.h | 127 | ||||
-rw-r--r-- | security/tomoyo/gc.c | 40 | ||||
-rw-r--r-- | security/tomoyo/group.c | 61 | ||||
-rw-r--r-- | security/tomoyo/network.c | 771 | ||||
-rw-r--r-- | security/tomoyo/realpath.c | 32 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.c | 62 | ||||
-rw-r--r-- | security/tomoyo/util.c | 31 |
10 files changed, 1215 insertions, 17 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 f7ade960f6cf..fc2a8ce40301 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile | |||
@@ -1,4 +1,4 @@ | |||
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 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/ |
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index d116e1ece3e6..85d915587a71 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -44,10 +44,27 @@ const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX | |||
44 | [TOMOYO_MAC_FILE_MOUNT] = "mount", | 44 | [TOMOYO_MAC_FILE_MOUNT] = "mount", |
45 | [TOMOYO_MAC_FILE_UMOUNT] = "unmount", | 45 | [TOMOYO_MAC_FILE_UMOUNT] = "unmount", |
46 | [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", | ||
47 | /* CONFIG::misc group */ | 63 | /* CONFIG::misc group */ |
48 | [TOMOYO_MAC_ENVIRON] = "env", | 64 | [TOMOYO_MAC_ENVIRON] = "env", |
49 | /* CONFIG group */ | 65 | /* CONFIG group */ |
50 | [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", | ||
51 | [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_MISC] = "misc", | 68 | [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_MISC] = "misc", |
52 | }; | 69 | }; |
53 | 70 | ||
@@ -135,11 +152,20 @@ const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { | |||
135 | [TOMOYO_TYPE_UMOUNT] = "unmount", | 152 | [TOMOYO_TYPE_UMOUNT] = "unmount", |
136 | }; | 153 | }; |
137 | 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 | |||
138 | /* String table for categories. */ | 163 | /* String table for categories. */ |
139 | static const char * const tomoyo_category_keywords | 164 | static const char * const tomoyo_category_keywords |
140 | [TOMOYO_MAX_MAC_CATEGORY_INDEX] = { | 165 | [TOMOYO_MAX_MAC_CATEGORY_INDEX] = { |
141 | [TOMOYO_MAC_CATEGORY_FILE] = "file", | 166 | [TOMOYO_MAC_CATEGORY_FILE] = "file", |
142 | [TOMOYO_MAC_CATEGORY_MISC] = "misc", | 167 | [TOMOYO_MAC_CATEGORY_NETWORK] = "network", |
168 | [TOMOYO_MAC_CATEGORY_MISC] = "misc", | ||
143 | }; | 169 | }; |
144 | 170 | ||
145 | /* Permit policy management by non-root user? */ | 171 | /* Permit policy management by non-root user? */ |
@@ -1042,8 +1068,10 @@ static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns, | |||
1042 | static const struct { | 1068 | static const struct { |
1043 | const char *keyword; | 1069 | const char *keyword; |
1044 | int (*write) (struct tomoyo_acl_param *); | 1070 | int (*write) (struct tomoyo_acl_param *); |
1045 | } tomoyo_callback[2] = { | 1071 | } tomoyo_callback[4] = { |
1046 | { "file ", tomoyo_write_file }, | 1072 | { "file ", tomoyo_write_file }, |
1073 | { "network inet ", tomoyo_write_inet_network }, | ||
1074 | { "network unix ", tomoyo_write_unix_network }, | ||
1047 | { "misc ", tomoyo_write_misc }, | 1075 | { "misc ", tomoyo_write_misc }, |
1048 | }; | 1076 | }; |
1049 | u8 i; | 1077 | u8 i; |
@@ -1375,6 +1403,60 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
1375 | tomoyo_print_number_union(head, &ptr->mode); | 1403 | tomoyo_print_number_union(head, &ptr->mode); |
1376 | tomoyo_print_number_union(head, &ptr->major); | 1404 | tomoyo_print_number_union(head, &ptr->major); |
1377 | tomoyo_print_number_union(head, &ptr->minor); | 1405 | tomoyo_print_number_union(head, &ptr->minor); |
1406 | } else if (acl_type == TOMOYO_TYPE_INET_ACL) { | ||
1407 | struct tomoyo_inet_acl *ptr = | ||
1408 | container_of(acl, typeof(*ptr), head); | ||
1409 | const u8 perm = ptr->perm; | ||
1410 | |||
1411 | for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) { | ||
1412 | if (!(perm & (1 << bit))) | ||
1413 | continue; | ||
1414 | if (first) { | ||
1415 | tomoyo_set_group(head, "network inet "); | ||
1416 | tomoyo_set_string(head, tomoyo_proto_keyword | ||
1417 | [ptr->protocol]); | ||
1418 | tomoyo_set_space(head); | ||
1419 | first = false; | ||
1420 | } else { | ||
1421 | tomoyo_set_slash(head); | ||
1422 | } | ||
1423 | tomoyo_set_string(head, tomoyo_socket_keyword[bit]); | ||
1424 | } | ||
1425 | if (first) | ||
1426 | return true; | ||
1427 | tomoyo_set_space(head); | ||
1428 | if (ptr->address.group) { | ||
1429 | tomoyo_set_string(head, "@"); | ||
1430 | tomoyo_set_string(head, ptr->address.group->group_name | ||
1431 | ->name); | ||
1432 | } else { | ||
1433 | char buf[128]; | ||
1434 | tomoyo_print_ip(buf, sizeof(buf), &ptr->address); | ||
1435 | tomoyo_io_printf(head, "%s", buf); | ||
1436 | } | ||
1437 | tomoyo_print_number_union(head, &ptr->port); | ||
1438 | } else if (acl_type == TOMOYO_TYPE_UNIX_ACL) { | ||
1439 | struct tomoyo_unix_acl *ptr = | ||
1440 | container_of(acl, typeof(*ptr), head); | ||
1441 | const u8 perm = ptr->perm; | ||
1442 | |||
1443 | for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) { | ||
1444 | if (!(perm & (1 << bit))) | ||
1445 | continue; | ||
1446 | if (first) { | ||
1447 | tomoyo_set_group(head, "network unix "); | ||
1448 | tomoyo_set_string(head, tomoyo_proto_keyword | ||
1449 | [ptr->protocol]); | ||
1450 | tomoyo_set_space(head); | ||
1451 | first = false; | ||
1452 | } else { | ||
1453 | tomoyo_set_slash(head); | ||
1454 | } | ||
1455 | tomoyo_set_string(head, tomoyo_socket_keyword[bit]); | ||
1456 | } | ||
1457 | if (first) | ||
1458 | return true; | ||
1459 | tomoyo_print_name_union(head, &ptr->name); | ||
1378 | } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { | 1460 | } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { |
1379 | struct tomoyo_mount_acl *ptr = | 1461 | struct tomoyo_mount_acl *ptr = |
1380 | container_of(acl, typeof(*ptr), head); | 1462 | container_of(acl, typeof(*ptr), head); |
@@ -1548,8 +1630,9 @@ static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { | |||
1548 | 1630 | ||
1549 | /* String table for grouping keywords. */ | 1631 | /* String table for grouping keywords. */ |
1550 | static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { | 1632 | static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { |
1551 | [TOMOYO_PATH_GROUP] = "path_group ", | 1633 | [TOMOYO_PATH_GROUP] = "path_group ", |
1552 | [TOMOYO_NUMBER_GROUP] = "number_group ", | 1634 | [TOMOYO_NUMBER_GROUP] = "number_group ", |
1635 | [TOMOYO_ADDRESS_GROUP] = "address_group ", | ||
1553 | }; | 1636 | }; |
1554 | 1637 | ||
1555 | /** | 1638 | /** |
@@ -1591,7 +1674,7 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) | |||
1591 | } | 1674 | } |
1592 | 1675 | ||
1593 | /** | 1676 | /** |
1594 | * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group" list. | 1677 | * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" list. |
1595 | * | 1678 | * |
1596 | * @head: Pointer to "struct tomoyo_io_buffer". | 1679 | * @head: Pointer to "struct tomoyo_io_buffer". |
1597 | * @idx: Index number. | 1680 | * @idx: Index number. |
@@ -1628,6 +1711,15 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | |||
1628 | (ptr, | 1711 | (ptr, |
1629 | struct tomoyo_number_group, | 1712 | struct tomoyo_number_group, |
1630 | head)->number); | 1713 | head)->number); |
1714 | } else if (idx == TOMOYO_ADDRESS_GROUP) { | ||
1715 | char buffer[128]; | ||
1716 | |||
1717 | struct tomoyo_address_group *member = | ||
1718 | container_of(ptr, typeof(*member), | ||
1719 | head); | ||
1720 | tomoyo_print_ip(buffer, sizeof(buffer), | ||
1721 | &member->address); | ||
1722 | tomoyo_io_printf(head, " %s", buffer); | ||
1631 | } | 1723 | } |
1632 | tomoyo_set_lf(head); | 1724 | tomoyo_set_lf(head); |
1633 | } | 1725 | } |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 63720a328edd..d1c758e7f92b 100644 --- a/security/tomoyo/common.h +++ b/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,6 +44,12 @@ | |||
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 | ||
39 | /* Profile number is an integer between 0 and 255. */ | 55 | /* Profile number is an integer between 0 and 255. */ |
@@ -136,6 +152,7 @@ enum tomoyo_mode_index { | |||
136 | /* Index numbers for entry type. */ | 152 | /* Index numbers for entry type. */ |
137 | enum tomoyo_policy_id { | 153 | enum tomoyo_policy_id { |
138 | TOMOYO_ID_GROUP, | 154 | TOMOYO_ID_GROUP, |
155 | TOMOYO_ID_ADDRESS_GROUP, | ||
139 | TOMOYO_ID_PATH_GROUP, | 156 | TOMOYO_ID_PATH_GROUP, |
140 | TOMOYO_ID_NUMBER_GROUP, | 157 | TOMOYO_ID_NUMBER_GROUP, |
141 | TOMOYO_ID_TRANSITION_CONTROL, | 158 | TOMOYO_ID_TRANSITION_CONTROL, |
@@ -166,6 +183,7 @@ enum tomoyo_domain_info_flags_index { | |||
166 | enum tomoyo_group_id { | 183 | enum tomoyo_group_id { |
167 | TOMOYO_PATH_GROUP, | 184 | TOMOYO_PATH_GROUP, |
168 | TOMOYO_NUMBER_GROUP, | 185 | TOMOYO_NUMBER_GROUP, |
186 | TOMOYO_ADDRESS_GROUP, | ||
169 | TOMOYO_MAX_GROUP | 187 | TOMOYO_MAX_GROUP |
170 | }; | 188 | }; |
171 | 189 | ||
@@ -196,6 +214,8 @@ enum tomoyo_acl_entry_type_index { | |||
196 | TOMOYO_TYPE_PATH_NUMBER_ACL, | 214 | TOMOYO_TYPE_PATH_NUMBER_ACL, |
197 | TOMOYO_TYPE_MKDEV_ACL, | 215 | TOMOYO_TYPE_MKDEV_ACL, |
198 | TOMOYO_TYPE_MOUNT_ACL, | 216 | TOMOYO_TYPE_MOUNT_ACL, |
217 | TOMOYO_TYPE_INET_ACL, | ||
218 | TOMOYO_TYPE_UNIX_ACL, | ||
199 | TOMOYO_TYPE_ENV_ACL, | 219 | TOMOYO_TYPE_ENV_ACL, |
200 | }; | 220 | }; |
201 | 221 | ||
@@ -229,6 +249,15 @@ enum tomoyo_mkdev_acl_index { | |||
229 | TOMOYO_MAX_MKDEV_OPERATION | 249 | TOMOYO_MAX_MKDEV_OPERATION |
230 | }; | 250 | }; |
231 | 251 | ||
252 | /* Index numbers for socket operations. */ | ||
253 | enum tomoyo_network_acl_index { | ||
254 | TOMOYO_NETWORK_BIND, /* bind() operation. */ | ||
255 | TOMOYO_NETWORK_LISTEN, /* listen() operation. */ | ||
256 | TOMOYO_NETWORK_CONNECT, /* connect() operation. */ | ||
257 | TOMOYO_NETWORK_SEND, /* send() operation. */ | ||
258 | TOMOYO_MAX_NETWORK_OPERATION | ||
259 | }; | ||
260 | |||
232 | /* Index numbers for access controls with two pathnames. */ | 261 | /* Index numbers for access controls with two pathnames. */ |
233 | enum tomoyo_path2_acl_index { | 262 | enum tomoyo_path2_acl_index { |
234 | TOMOYO_TYPE_LINK, | 263 | TOMOYO_TYPE_LINK, |
@@ -301,6 +330,21 @@ enum tomoyo_mac_index { | |||
301 | TOMOYO_MAC_FILE_MOUNT, | 330 | TOMOYO_MAC_FILE_MOUNT, |
302 | TOMOYO_MAC_FILE_UMOUNT, | 331 | TOMOYO_MAC_FILE_UMOUNT, |
303 | TOMOYO_MAC_FILE_PIVOT_ROOT, | 332 | TOMOYO_MAC_FILE_PIVOT_ROOT, |
333 | TOMOYO_MAC_NETWORK_INET_STREAM_BIND, | ||
334 | TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN, | ||
335 | TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT, | ||
336 | TOMOYO_MAC_NETWORK_INET_DGRAM_BIND, | ||
337 | TOMOYO_MAC_NETWORK_INET_DGRAM_SEND, | ||
338 | TOMOYO_MAC_NETWORK_INET_RAW_BIND, | ||
339 | TOMOYO_MAC_NETWORK_INET_RAW_SEND, | ||
340 | TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND, | ||
341 | TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN, | ||
342 | TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT, | ||
343 | TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND, | ||
344 | TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND, | ||
345 | TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND, | ||
346 | TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN, | ||
347 | TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT, | ||
304 | TOMOYO_MAC_ENVIRON, | 348 | TOMOYO_MAC_ENVIRON, |
305 | TOMOYO_MAX_MAC_INDEX | 349 | TOMOYO_MAX_MAC_INDEX |
306 | }; | 350 | }; |
@@ -308,6 +352,7 @@ enum tomoyo_mac_index { | |||
308 | /* Index numbers for category of functionality. */ | 352 | /* Index numbers for category of functionality. */ |
309 | enum tomoyo_mac_category_index { | 353 | enum tomoyo_mac_category_index { |
310 | TOMOYO_MAC_CATEGORY_FILE, | 354 | TOMOYO_MAC_CATEGORY_FILE, |
355 | TOMOYO_MAC_CATEGORY_NETWORK, | ||
311 | TOMOYO_MAC_CATEGORY_MISC, | 356 | TOMOYO_MAC_CATEGORY_MISC, |
312 | TOMOYO_MAX_MAC_CATEGORY_INDEX | 357 | TOMOYO_MAX_MAC_CATEGORY_INDEX |
313 | }; | 358 | }; |
@@ -403,6 +448,22 @@ struct tomoyo_request_info { | |||
403 | const struct tomoyo_path_info *name; | 448 | const struct tomoyo_path_info *name; |
404 | } environ; | 449 | } environ; |
405 | struct { | 450 | struct { |
451 | const __be32 *address; | ||
452 | u16 port; | ||
453 | /* One of values smaller than TOMOYO_SOCK_MAX. */ | ||
454 | u8 protocol; | ||
455 | /* One of values in "enum tomoyo_network_acl_index". */ | ||
456 | u8 operation; | ||
457 | bool is_ipv6; | ||
458 | } inet_network; | ||
459 | struct { | ||
460 | const struct tomoyo_path_info *address; | ||
461 | /* One of values smaller than TOMOYO_SOCK_MAX. */ | ||
462 | u8 protocol; | ||
463 | /* One of values in "enum tomoyo_network_acl_index". */ | ||
464 | u8 operation; | ||
465 | } unix_network; | ||
466 | struct { | ||
406 | const struct tomoyo_path_info *type; | 467 | const struct tomoyo_path_info *type; |
407 | const struct tomoyo_path_info *dir; | 468 | const struct tomoyo_path_info *dir; |
408 | const struct tomoyo_path_info *dev; | 469 | const struct tomoyo_path_info *dev; |
@@ -448,7 +509,14 @@ struct tomoyo_number_union { | |||
448 | u8 value_type[2]; | 509 | u8 value_type[2]; |
449 | }; | 510 | }; |
450 | 511 | ||
451 | /* Structure for "path_group"/"number_group" directive. */ | 512 | /* Structure for holding an IP address. */ |
513 | struct tomoyo_ipaddr_union { | ||
514 | struct in6_addr ip[2]; /* Big endian. */ | ||
515 | struct tomoyo_group *group; /* Pointer to address group. */ | ||
516 | bool is_ipv6; /* Valid only if @group == NULL. */ | ||
517 | }; | ||
518 | |||
519 | /* Structure for "path_group"/"number_group"/"address_group" directive. */ | ||
452 | struct tomoyo_group { | 520 | struct tomoyo_group { |
453 | struct tomoyo_shared_acl_head head; | 521 | struct tomoyo_shared_acl_head head; |
454 | const struct tomoyo_path_info *group_name; | 522 | const struct tomoyo_path_info *group_name; |
@@ -467,6 +535,13 @@ struct tomoyo_number_group { | |||
467 | struct tomoyo_number_union number; | 535 | struct tomoyo_number_union number; |
468 | }; | 536 | }; |
469 | 537 | ||
538 | /* Structure for "address_group" directive. */ | ||
539 | struct tomoyo_address_group { | ||
540 | struct tomoyo_acl_head head; | ||
541 | /* Structure for holding an IP address. */ | ||
542 | struct tomoyo_ipaddr_union address; | ||
543 | }; | ||
544 | |||
470 | /* Subset of "struct stat". Used by conditional ACL and audit logs. */ | 545 | /* Subset of "struct stat". Used by conditional ACL and audit logs. */ |
471 | struct tomoyo_mini_stat { | 546 | struct tomoyo_mini_stat { |
472 | uid_t uid; | 547 | uid_t uid; |
@@ -650,6 +725,23 @@ struct tomoyo_env_acl { | |||
650 | const struct tomoyo_path_info *env; /* environment variable */ | 725 | const struct tomoyo_path_info *env; /* environment variable */ |
651 | }; | 726 | }; |
652 | 727 | ||
728 | /* Structure for "network inet" directive. */ | ||
729 | struct tomoyo_inet_acl { | ||
730 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_INET_ACL */ | ||
731 | u8 protocol; | ||
732 | u8 perm; /* Bitmask of values in "enum tomoyo_network_acl_index" */ | ||
733 | struct tomoyo_ipaddr_union address; | ||
734 | struct tomoyo_number_union port; | ||
735 | }; | ||
736 | |||
737 | /* Structure for "network unix" directive. */ | ||
738 | struct tomoyo_unix_acl { | ||
739 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_UNIX_ACL */ | ||
740 | u8 protocol; | ||
741 | u8 perm; /* Bitmask of values in "enum tomoyo_network_acl_index" */ | ||
742 | struct tomoyo_name_union name; | ||
743 | }; | ||
744 | |||
653 | /* Structure for holding a line from /sys/kernel/security/tomoyo/ interface. */ | 745 | /* Structure for holding a line from /sys/kernel/security/tomoyo/ interface. */ |
654 | struct tomoyo_acl_param { | 746 | struct tomoyo_acl_param { |
655 | char *data; | 747 | char *data; |
@@ -793,6 +885,8 @@ struct tomoyo_policy_namespace { | |||
793 | 885 | ||
794 | /********** Function prototypes. **********/ | 886 | /********** Function prototypes. **********/ |
795 | 887 | ||
888 | bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address, | ||
889 | const struct tomoyo_group *group); | ||
796 | bool tomoyo_compare_number_union(const unsigned long value, | 890 | bool tomoyo_compare_number_union(const unsigned long value, |
797 | const struct tomoyo_number_union *ptr); | 891 | const struct tomoyo_number_union *ptr); |
798 | bool tomoyo_condition(struct tomoyo_request_info *r, | 892 | bool tomoyo_condition(struct tomoyo_request_info *r, |
@@ -808,6 +902,8 @@ bool tomoyo_memory_ok(void *ptr); | |||
808 | bool tomoyo_number_matches_group(const unsigned long min, | 902 | bool tomoyo_number_matches_group(const unsigned long min, |
809 | const unsigned long max, | 903 | const unsigned long max, |
810 | const struct tomoyo_group *group); | 904 | const struct tomoyo_group *group); |
905 | bool tomoyo_parse_ipaddr_union(struct tomoyo_acl_param *param, | ||
906 | struct tomoyo_ipaddr_union *ptr); | ||
811 | bool tomoyo_parse_name_union(struct tomoyo_acl_param *param, | 907 | bool tomoyo_parse_name_union(struct tomoyo_acl_param *param, |
812 | struct tomoyo_name_union *ptr); | 908 | struct tomoyo_name_union *ptr); |
813 | bool tomoyo_parse_number_union(struct tomoyo_acl_param *param, | 909 | bool tomoyo_parse_number_union(struct tomoyo_acl_param *param, |
@@ -817,6 +913,7 @@ bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, | |||
817 | bool tomoyo_permstr(const char *string, const char *keyword); | 913 | bool tomoyo_permstr(const char *string, const char *keyword); |
818 | bool tomoyo_str_starts(char **src, const char *find); | 914 | bool tomoyo_str_starts(char **src, const char *find); |
819 | char *tomoyo_encode(const char *str); | 915 | char *tomoyo_encode(const char *str); |
916 | char *tomoyo_encode2(const char *str, int str_len); | ||
820 | char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt, | 917 | char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt, |
821 | va_list args); | 918 | va_list args); |
822 | char *tomoyo_read_token(struct tomoyo_acl_param *param); | 919 | char *tomoyo_read_token(struct tomoyo_acl_param *param); |
@@ -855,6 +952,13 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | |||
855 | const struct tomoyo_path_info *filename); | 952 | const struct tomoyo_path_info *filename); |
856 | int tomoyo_poll_control(struct file *file, poll_table *wait); | 953 | int tomoyo_poll_control(struct file *file, poll_table *wait); |
857 | int tomoyo_poll_log(struct file *file, poll_table *wait); | 954 | int tomoyo_poll_log(struct file *file, poll_table *wait); |
955 | int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr, | ||
956 | int addr_len); | ||
957 | int tomoyo_socket_connect_permission(struct socket *sock, | ||
958 | struct sockaddr *addr, int addr_len); | ||
959 | int tomoyo_socket_listen_permission(struct socket *sock); | ||
960 | int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg, | ||
961 | int size); | ||
858 | int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) | 962 | int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) |
859 | __printf(2, 3); | 963 | __printf(2, 3); |
860 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | 964 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, |
@@ -874,8 +978,10 @@ int tomoyo_write_aggregator(struct tomoyo_acl_param *param); | |||
874 | int tomoyo_write_file(struct tomoyo_acl_param *param); | 978 | int tomoyo_write_file(struct tomoyo_acl_param *param); |
875 | int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type); | 979 | int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type); |
876 | int tomoyo_write_misc(struct tomoyo_acl_param *param); | 980 | int tomoyo_write_misc(struct tomoyo_acl_param *param); |
981 | int tomoyo_write_inet_network(struct tomoyo_acl_param *param); | ||
877 | int tomoyo_write_transition_control(struct tomoyo_acl_param *param, | 982 | int tomoyo_write_transition_control(struct tomoyo_acl_param *param, |
878 | const u8 type); | 983 | const u8 type); |
984 | int tomoyo_write_unix_network(struct tomoyo_acl_param *param); | ||
879 | ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer, | 985 | ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer, |
880 | const int buffer_len); | 986 | const int buffer_len); |
881 | ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, | 987 | ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, |
@@ -911,6 +1017,8 @@ void tomoyo_load_policy(const char *filename); | |||
911 | void tomoyo_memory_free(void *ptr); | 1017 | void tomoyo_memory_free(void *ptr); |
912 | void tomoyo_normalize_line(unsigned char *buffer); | 1018 | void tomoyo_normalize_line(unsigned char *buffer); |
913 | void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register); | 1019 | void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register); |
1020 | void tomoyo_print_ip(char *buf, const unsigned int size, | ||
1021 | const struct tomoyo_ipaddr_union *ptr); | ||
914 | void tomoyo_print_ulong(char *buffer, const int buffer_len, | 1022 | void tomoyo_print_ulong(char *buffer, const int buffer_len, |
915 | const unsigned long value, const u8 type); | 1023 | const unsigned long value, const u8 type); |
916 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr); | 1024 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr); |
@@ -933,6 +1041,8 @@ extern const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX | |||
933 | + TOMOYO_MAX_MAC_CATEGORY_INDEX]; | 1041 | + TOMOYO_MAX_MAC_CATEGORY_INDEX]; |
934 | extern const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE]; | 1042 | extern const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE]; |
935 | extern const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION]; | 1043 | extern const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION]; |
1044 | extern const char * const tomoyo_proto_keyword[TOMOYO_SOCK_MAX]; | ||
1045 | extern const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION]; | ||
936 | extern const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX]; | 1046 | extern const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX]; |
937 | extern const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION]; | 1047 | extern const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION]; |
938 | extern const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION]; | 1048 | extern const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION]; |
@@ -1112,6 +1222,21 @@ static inline bool tomoyo_same_number_union | |||
1112 | } | 1222 | } |
1113 | 1223 | ||
1114 | /** | 1224 | /** |
1225 | * tomoyo_same_ipaddr_union - Check for duplicated "struct tomoyo_ipaddr_union" entry. | ||
1226 | * | ||
1227 | * @a: Pointer to "struct tomoyo_ipaddr_union". | ||
1228 | * @b: Pointer to "struct tomoyo_ipaddr_union". | ||
1229 | * | ||
1230 | * Returns true if @a == @b, false otherwise. | ||
1231 | */ | ||
1232 | static inline bool tomoyo_same_ipaddr_union | ||
1233 | (const struct tomoyo_ipaddr_union *a, const struct tomoyo_ipaddr_union *b) | ||
1234 | { | ||
1235 | return !memcmp(a->ip, b->ip, sizeof(a->ip)) && a->group == b->group && | ||
1236 | a->is_ipv6 == b->is_ipv6; | ||
1237 | } | ||
1238 | |||
1239 | /** | ||
1115 | * tomoyo_current_namespace - Get "struct tomoyo_policy_namespace" for current thread. | 1240 | * tomoyo_current_namespace - Get "struct tomoyo_policy_namespace" for current thread. |
1116 | * | 1241 | * |
1117 | * Returns pointer to "struct tomoyo_policy_namespace" for current thread. | 1242 | * Returns pointer to "struct tomoyo_policy_namespace" for current thread. |
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index 818b07998111..7747ceb9a221 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c | |||
@@ -16,6 +16,7 @@ static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock); | |||
16 | /* Size of an element. */ | 16 | /* Size of an element. */ |
17 | static const u8 tomoyo_element_size[TOMOYO_MAX_POLICY] = { | 17 | static const u8 tomoyo_element_size[TOMOYO_MAX_POLICY] = { |
18 | [TOMOYO_ID_GROUP] = sizeof(struct tomoyo_group), | 18 | [TOMOYO_ID_GROUP] = sizeof(struct tomoyo_group), |
19 | [TOMOYO_ID_ADDRESS_GROUP] = sizeof(struct tomoyo_address_group), | ||
19 | [TOMOYO_ID_PATH_GROUP] = sizeof(struct tomoyo_path_group), | 20 | [TOMOYO_ID_PATH_GROUP] = sizeof(struct tomoyo_path_group), |
20 | [TOMOYO_ID_NUMBER_GROUP] = sizeof(struct tomoyo_number_group), | 21 | [TOMOYO_ID_NUMBER_GROUP] = sizeof(struct tomoyo_number_group), |
21 | [TOMOYO_ID_AGGREGATOR] = sizeof(struct tomoyo_aggregator), | 22 | [TOMOYO_ID_AGGREGATOR] = sizeof(struct tomoyo_aggregator), |
@@ -36,6 +37,8 @@ static const u8 tomoyo_acl_size[] = { | |||
36 | [TOMOYO_TYPE_PATH_NUMBER_ACL] = sizeof(struct tomoyo_path_number_acl), | 37 | [TOMOYO_TYPE_PATH_NUMBER_ACL] = sizeof(struct tomoyo_path_number_acl), |
37 | [TOMOYO_TYPE_MKDEV_ACL] = sizeof(struct tomoyo_mkdev_acl), | 38 | [TOMOYO_TYPE_MKDEV_ACL] = sizeof(struct tomoyo_mkdev_acl), |
38 | [TOMOYO_TYPE_MOUNT_ACL] = sizeof(struct tomoyo_mount_acl), | 39 | [TOMOYO_TYPE_MOUNT_ACL] = sizeof(struct tomoyo_mount_acl), |
40 | [TOMOYO_TYPE_INET_ACL] = sizeof(struct tomoyo_inet_acl), | ||
41 | [TOMOYO_TYPE_UNIX_ACL] = sizeof(struct tomoyo_unix_acl), | ||
39 | [TOMOYO_TYPE_ENV_ACL] = sizeof(struct tomoyo_env_acl), | 42 | [TOMOYO_TYPE_ENV_ACL] = sizeof(struct tomoyo_env_acl), |
40 | }; | 43 | }; |
41 | 44 | ||
@@ -302,6 +305,23 @@ static void tomoyo_del_acl(struct list_head *element) | |||
302 | tomoyo_put_name(entry->env); | 305 | tomoyo_put_name(entry->env); |
303 | } | 306 | } |
304 | break; | 307 | break; |
308 | case TOMOYO_TYPE_INET_ACL: | ||
309 | { | ||
310 | struct tomoyo_inet_acl *entry = | ||
311 | container_of(acl, typeof(*entry), head); | ||
312 | |||
313 | tomoyo_put_group(entry->address.group); | ||
314 | tomoyo_put_number_union(&entry->port); | ||
315 | } | ||
316 | break; | ||
317 | case TOMOYO_TYPE_UNIX_ACL: | ||
318 | { | ||
319 | struct tomoyo_unix_acl *entry = | ||
320 | container_of(acl, typeof(*entry), head); | ||
321 | |||
322 | tomoyo_put_name_union(&entry->name); | ||
323 | } | ||
324 | break; | ||
305 | } | 325 | } |
306 | } | 326 | } |
307 | 327 | ||
@@ -431,6 +451,18 @@ static void tomoyo_del_group(struct list_head *element) | |||
431 | } | 451 | } |
432 | 452 | ||
433 | /** | 453 | /** |
454 | * tomoyo_del_address_group - Delete members in "struct tomoyo_address_group". | ||
455 | * | ||
456 | * @element: Pointer to "struct list_head". | ||
457 | * | ||
458 | * Returns nothing. | ||
459 | */ | ||
460 | static inline void tomoyo_del_address_group(struct list_head *element) | ||
461 | { | ||
462 | /* Nothing to do. */ | ||
463 | } | ||
464 | |||
465 | /** | ||
434 | * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group". | 466 | * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group". |
435 | * | 467 | * |
436 | * @element: Pointer to "struct list_head". | 468 | * @element: Pointer to "struct list_head". |
@@ -527,9 +559,12 @@ static void tomoyo_collect_entry(void) | |||
527 | case 0: | 559 | case 0: |
528 | id = TOMOYO_ID_PATH_GROUP; | 560 | id = TOMOYO_ID_PATH_GROUP; |
529 | break; | 561 | break; |
530 | default: | 562 | case 1: |
531 | id = TOMOYO_ID_NUMBER_GROUP; | 563 | id = TOMOYO_ID_NUMBER_GROUP; |
532 | break; | 564 | break; |
565 | default: | ||
566 | id = TOMOYO_ID_ADDRESS_GROUP; | ||
567 | break; | ||
533 | } | 568 | } |
534 | list_for_each_entry(group, list, head.list) { | 569 | list_for_each_entry(group, list, head.list) { |
535 | if (!tomoyo_collect_member | 570 | if (!tomoyo_collect_member |
@@ -634,6 +669,9 @@ static bool tomoyo_kfree_entry(void) | |||
634 | case TOMOYO_ID_PATH_GROUP: | 669 | case TOMOYO_ID_PATH_GROUP: |
635 | tomoyo_del_path_group(element); | 670 | tomoyo_del_path_group(element); |
636 | break; | 671 | break; |
672 | case TOMOYO_ID_ADDRESS_GROUP: | ||
673 | tomoyo_del_address_group(element); | ||
674 | break; | ||
637 | case TOMOYO_ID_GROUP: | 675 | case TOMOYO_ID_GROUP: |
638 | tomoyo_del_group(element); | 676 | tomoyo_del_group(element); |
639 | break; | 677 | break; |
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/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/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 cb7d507b6312..a1c3d9ccebfa 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c | |||
@@ -42,6 +42,37 @@ 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, | ||
45 | /* CONFIG::misc group */ | 76 | /* CONFIG::misc group */ |
46 | [TOMOYO_MAC_ENVIRON] = TOMOYO_MAC_CATEGORY_MISC, | 77 | [TOMOYO_MAC_ENVIRON] = TOMOYO_MAC_CATEGORY_MISC, |
47 | }; | 78 | }; |