From d58e0da854376841ac99defeb117a83f086715c6 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sat, 10 Sep 2011 15:22:48 +0900 Subject: TOMOYO: Add environment variable name restriction support. This patch adds support for checking environment variable's names. Although TOMOYO already provides ability to check argv[]/envp[] passed to execve() requests, file execute /bin/sh exec.envp["LD_LIBRARY_PATH"]="bar" will reject execution of /bin/sh if environment variable LD_LIBRARY_PATH is not defined. To grant execution of /bin/sh if LD_LIBRARY_PATH is not defined, administrators have to specify like file execute /bin/sh exec.envp["LD_LIBRARY_PATH"]="/system/lib" file execute /bin/sh exec.envp["LD_LIBRARY_PATH"]=NULL . Since there are many environment variables whereas conditional checks are applied as "&&", it is difficult to cover all combinations. Therefore, this patch supports conditional checks that are applied as "||", by specifying like file execute /bin/sh misc env LD_LIBRARY_PATH exec.envp["LD_LIBRARY_PATH"]="/system/lib" which means "grant execution of /bin/sh if environment variable is not defined or is defined and its value is /system/lib". Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'security/tomoyo/common.c') diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index c8439cf2a44..d116e1ece3e 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -20,6 +20,7 @@ const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = { /* String table for /sys/kernel/security/tomoyo/profile */ const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX] = { + /* CONFIG::file group */ [TOMOYO_MAC_FILE_EXECUTE] = "execute", [TOMOYO_MAC_FILE_OPEN] = "open", [TOMOYO_MAC_FILE_CREATE] = "create", @@ -43,7 +44,11 @@ const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX [TOMOYO_MAC_FILE_MOUNT] = "mount", [TOMOYO_MAC_FILE_UMOUNT] = "unmount", [TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root", + /* CONFIG::misc group */ + [TOMOYO_MAC_ENVIRON] = "env", + /* CONFIG group */ [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file", + [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_MISC] = "misc", }; /* String table for conditions. */ @@ -133,7 +138,8 @@ const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { /* String table for categories. */ static const char * const tomoyo_category_keywords [TOMOYO_MAX_MAC_CATEGORY_INDEX] = { - [TOMOYO_MAC_CATEGORY_FILE] = "file", + [TOMOYO_MAC_CATEGORY_FILE] = "file", + [TOMOYO_MAC_CATEGORY_MISC] = "misc", }; /* Permit policy management by non-root user? */ @@ -1036,11 +1042,13 @@ static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns, static const struct { const char *keyword; int (*write) (struct tomoyo_acl_param *); - } tomoyo_callback[1] = { + } tomoyo_callback[2] = { { "file ", tomoyo_write_file }, + { "misc ", tomoyo_write_misc }, }; u8 i; - for (i = 0; i < 1; i++) { + + for (i = 0; i < ARRAY_SIZE(tomoyo_callback); i++) { if (!tomoyo_str_starts(¶m.data, tomoyo_callback[i].keyword)) continue; @@ -1375,6 +1383,12 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, tomoyo_print_name_union(head, &ptr->dir_name); tomoyo_print_name_union(head, &ptr->fs_type); tomoyo_print_number_union(head, &ptr->flags); + } else if (acl_type == TOMOYO_TYPE_ENV_ACL) { + struct tomoyo_env_acl *ptr = + container_of(acl, typeof(*ptr), head); + + tomoyo_set_group(head, "misc env "); + tomoyo_set_string(head, ptr->env->name); } if (acl->cond) { head->r.print_cond_part = true; -- cgit v1.2.3-70-g09d2 From 059d84dbb3897d4ee494a9c842c5dda54316cb47 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sat, 10 Sep 2011 15:23:54 +0900 Subject: TOMOYO: Add socket operation restriction support. This patch adds support for permission checks for PF_INET/PF_INET6/PF_UNIX socket's bind()/listen()/connect()/send() operations. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/Kconfig | 2 + security/tomoyo/Makefile | 2 +- security/tomoyo/common.c | 104 +++++- security/tomoyo/common.h | 127 +++++++- security/tomoyo/gc.c | 40 ++- security/tomoyo/group.c | 61 +++- security/tomoyo/network.c | 771 +++++++++++++++++++++++++++++++++++++++++++++ security/tomoyo/realpath.c | 32 +- security/tomoyo/tomoyo.c | 62 ++++ security/tomoyo/util.c | 31 ++ 10 files changed, 1215 insertions(+), 17 deletions(-) create mode 100644 security/tomoyo/network.c (limited to 'security/tomoyo/common.c') diff --git a/security/tomoyo/Kconfig b/security/tomoyo/Kconfig index 7c7f8c16c10..8eb779b9d77 100644 --- a/security/tomoyo/Kconfig +++ b/security/tomoyo/Kconfig @@ -1,8 +1,10 @@ config SECURITY_TOMOYO bool "TOMOYO Linux Support" depends on SECURITY + depends on NET select SECURITYFS select SECURITY_PATH + select SECURITY_NETWORK default n help This selects TOMOYO Linux, pathname-based access control. diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index f7ade960f6c..fc2a8ce4030 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile @@ -1,4 +1,4 @@ -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 +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 $(obj)/policy/profile.conf: @mkdir -p $(obj)/policy/ diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index d116e1ece3e..85d915587a7 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 [TOMOYO_MAC_FILE_MOUNT] = "mount", [TOMOYO_MAC_FILE_UMOUNT] = "unmount", [TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root", + /* CONFIG::network group */ + [TOMOYO_MAC_NETWORK_INET_STREAM_BIND] = "inet_stream_bind", + [TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN] = "inet_stream_listen", + [TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT] = "inet_stream_connect", + [TOMOYO_MAC_NETWORK_INET_DGRAM_BIND] = "inet_dgram_bind", + [TOMOYO_MAC_NETWORK_INET_DGRAM_SEND] = "inet_dgram_send", + [TOMOYO_MAC_NETWORK_INET_RAW_BIND] = "inet_raw_bind", + [TOMOYO_MAC_NETWORK_INET_RAW_SEND] = "inet_raw_send", + [TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND] = "unix_stream_bind", + [TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN] = "unix_stream_listen", + [TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT] = "unix_stream_connect", + [TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND] = "unix_dgram_bind", + [TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND] = "unix_dgram_send", + [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND] = "unix_seqpacket_bind", + [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = "unix_seqpacket_listen", + [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect", /* CONFIG::misc group */ [TOMOYO_MAC_ENVIRON] = "env", /* CONFIG group */ [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file", + [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_NETWORK] = "network", [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_MISC] = "misc", }; @@ -135,11 +152,20 @@ const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { [TOMOYO_TYPE_UMOUNT] = "unmount", }; +/* String table for socket's operation. */ +const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION] = { + [TOMOYO_NETWORK_BIND] = "bind", + [TOMOYO_NETWORK_LISTEN] = "listen", + [TOMOYO_NETWORK_CONNECT] = "connect", + [TOMOYO_NETWORK_SEND] = "send", +}; + /* String table for categories. */ static const char * const tomoyo_category_keywords [TOMOYO_MAX_MAC_CATEGORY_INDEX] = { - [TOMOYO_MAC_CATEGORY_FILE] = "file", - [TOMOYO_MAC_CATEGORY_MISC] = "misc", + [TOMOYO_MAC_CATEGORY_FILE] = "file", + [TOMOYO_MAC_CATEGORY_NETWORK] = "network", + [TOMOYO_MAC_CATEGORY_MISC] = "misc", }; /* Permit policy management by non-root user? */ @@ -1042,8 +1068,10 @@ static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns, static const struct { const char *keyword; int (*write) (struct tomoyo_acl_param *); - } tomoyo_callback[2] = { + } tomoyo_callback[4] = { { "file ", tomoyo_write_file }, + { "network inet ", tomoyo_write_inet_network }, + { "network unix ", tomoyo_write_unix_network }, { "misc ", tomoyo_write_misc }, }; u8 i; @@ -1375,6 +1403,60 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, tomoyo_print_number_union(head, &ptr->mode); tomoyo_print_number_union(head, &ptr->major); tomoyo_print_number_union(head, &ptr->minor); + } else if (acl_type == TOMOYO_TYPE_INET_ACL) { + struct tomoyo_inet_acl *ptr = + container_of(acl, typeof(*ptr), head); + const u8 perm = ptr->perm; + + for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) { + if (!(perm & (1 << bit))) + continue; + if (first) { + tomoyo_set_group(head, "network inet "); + tomoyo_set_string(head, tomoyo_proto_keyword + [ptr->protocol]); + tomoyo_set_space(head); + first = false; + } else { + tomoyo_set_slash(head); + } + tomoyo_set_string(head, tomoyo_socket_keyword[bit]); + } + if (first) + return true; + tomoyo_set_space(head); + if (ptr->address.group) { + tomoyo_set_string(head, "@"); + tomoyo_set_string(head, ptr->address.group->group_name + ->name); + } else { + char buf[128]; + tomoyo_print_ip(buf, sizeof(buf), &ptr->address); + tomoyo_io_printf(head, "%s", buf); + } + tomoyo_print_number_union(head, &ptr->port); + } else if (acl_type == TOMOYO_TYPE_UNIX_ACL) { + struct tomoyo_unix_acl *ptr = + container_of(acl, typeof(*ptr), head); + const u8 perm = ptr->perm; + + for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) { + if (!(perm & (1 << bit))) + continue; + if (first) { + tomoyo_set_group(head, "network unix "); + tomoyo_set_string(head, tomoyo_proto_keyword + [ptr->protocol]); + tomoyo_set_space(head); + first = false; + } else { + tomoyo_set_slash(head); + } + tomoyo_set_string(head, tomoyo_socket_keyword[bit]); + } + if (first) + return true; + tomoyo_print_name_union(head, &ptr->name); } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { struct tomoyo_mount_acl *ptr = container_of(acl, typeof(*ptr), head); @@ -1548,8 +1630,9 @@ static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { /* String table for grouping keywords. */ static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { - [TOMOYO_PATH_GROUP] = "path_group ", - [TOMOYO_NUMBER_GROUP] = "number_group ", + [TOMOYO_PATH_GROUP] = "path_group ", + [TOMOYO_NUMBER_GROUP] = "number_group ", + [TOMOYO_ADDRESS_GROUP] = "address_group ", }; /** @@ -1591,7 +1674,7 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) } /** - * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group" list. + * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" list. * * @head: Pointer to "struct tomoyo_io_buffer". * @idx: Index number. @@ -1628,6 +1711,15 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) (ptr, struct tomoyo_number_group, head)->number); + } else if (idx == TOMOYO_ADDRESS_GROUP) { + char buffer[128]; + + struct tomoyo_address_group *member = + container_of(ptr, typeof(*member), + head); + tomoyo_print_ip(buffer, sizeof(buffer), + &member->address); + tomoyo_io_printf(head, " %s", buffer); } tomoyo_set_lf(head); } diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 63720a328ed..d1c758e7f92 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -23,6 +23,16 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /********** Constants definitions. **********/ @@ -34,6 +44,12 @@ #define TOMOYO_HASH_BITS 8 #define TOMOYO_MAX_HASH (1u<value_type[1] == b->value_type[1]; } +/** + * tomoyo_same_ipaddr_union - Check for duplicated "struct tomoyo_ipaddr_union" entry. + * + * @a: Pointer to "struct tomoyo_ipaddr_union". + * @b: Pointer to "struct tomoyo_ipaddr_union". + * + * Returns true if @a == @b, false otherwise. + */ +static inline bool tomoyo_same_ipaddr_union +(const struct tomoyo_ipaddr_union *a, const struct tomoyo_ipaddr_union *b) +{ + return !memcmp(a->ip, b->ip, sizeof(a->ip)) && a->group == b->group && + a->is_ipv6 == b->is_ipv6; +} + /** * tomoyo_current_namespace - Get "struct tomoyo_policy_namespace" for current thread. * diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index 818b0799811..7747ceb9a22 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c @@ -16,6 +16,7 @@ static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock); /* Size of an element. */ static const u8 tomoyo_element_size[TOMOYO_MAX_POLICY] = { [TOMOYO_ID_GROUP] = sizeof(struct tomoyo_group), + [TOMOYO_ID_ADDRESS_GROUP] = sizeof(struct tomoyo_address_group), [TOMOYO_ID_PATH_GROUP] = sizeof(struct tomoyo_path_group), [TOMOYO_ID_NUMBER_GROUP] = sizeof(struct tomoyo_number_group), [TOMOYO_ID_AGGREGATOR] = sizeof(struct tomoyo_aggregator), @@ -36,6 +37,8 @@ static const u8 tomoyo_acl_size[] = { [TOMOYO_TYPE_PATH_NUMBER_ACL] = sizeof(struct tomoyo_path_number_acl), [TOMOYO_TYPE_MKDEV_ACL] = sizeof(struct tomoyo_mkdev_acl), [TOMOYO_TYPE_MOUNT_ACL] = sizeof(struct tomoyo_mount_acl), + [TOMOYO_TYPE_INET_ACL] = sizeof(struct tomoyo_inet_acl), + [TOMOYO_TYPE_UNIX_ACL] = sizeof(struct tomoyo_unix_acl), [TOMOYO_TYPE_ENV_ACL] = sizeof(struct tomoyo_env_acl), }; @@ -302,6 +305,23 @@ static void tomoyo_del_acl(struct list_head *element) tomoyo_put_name(entry->env); } break; + case TOMOYO_TYPE_INET_ACL: + { + struct tomoyo_inet_acl *entry = + container_of(acl, typeof(*entry), head); + + tomoyo_put_group(entry->address.group); + tomoyo_put_number_union(&entry->port); + } + break; + case TOMOYO_TYPE_UNIX_ACL: + { + struct tomoyo_unix_acl *entry = + container_of(acl, typeof(*entry), head); + + tomoyo_put_name_union(&entry->name); + } + break; } } @@ -430,6 +450,18 @@ static void tomoyo_del_group(struct list_head *element) tomoyo_put_name(group->group_name); } +/** + * tomoyo_del_address_group - Delete members in "struct tomoyo_address_group". + * + * @element: Pointer to "struct list_head". + * + * Returns nothing. + */ +static inline void tomoyo_del_address_group(struct list_head *element) +{ + /* Nothing to do. */ +} + /** * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group". * @@ -527,9 +559,12 @@ static void tomoyo_collect_entry(void) case 0: id = TOMOYO_ID_PATH_GROUP; break; - default: + case 1: id = TOMOYO_ID_NUMBER_GROUP; break; + default: + id = TOMOYO_ID_ADDRESS_GROUP; + break; } list_for_each_entry(group, list, head.list) { if (!tomoyo_collect_member @@ -634,6 +669,9 @@ static bool tomoyo_kfree_entry(void) case TOMOYO_ID_PATH_GROUP: tomoyo_del_path_group(element); break; + case TOMOYO_ID_ADDRESS_GROUP: + tomoyo_del_address_group(element); + break; case TOMOYO_ID_GROUP: tomoyo_del_group(element); break; diff --git a/security/tomoyo/group.c b/security/tomoyo/group.c index 5fb0e129840..50092534ec5 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, } /** - * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group" list. + * tomoyo_same_address_group - Check for duplicated "struct tomoyo_address_group" entry. + * + * @a: Pointer to "struct tomoyo_acl_head". + * @b: Pointer to "struct tomoyo_acl_head". + * + * Returns true if @a == @b, false otherwise. + */ +static bool tomoyo_same_address_group(const struct tomoyo_acl_head *a, + const struct tomoyo_acl_head *b) +{ + const struct tomoyo_address_group *p1 = container_of(a, typeof(*p1), + head); + const struct tomoyo_address_group *p2 = container_of(b, typeof(*p2), + head); + + return tomoyo_same_ipaddr_union(&p1->address, &p2->address); +} + +/** + * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" list. * * @param: Pointer to "struct tomoyo_acl_param". * @type: Type of this group. @@ -77,6 +96,14 @@ int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type) * tomoyo_put_number_union() is not needed because * param->data[0] != '@'. */ + } else { + struct tomoyo_address_group e = { }; + + if (param->data[0] == '@' || + !tomoyo_parse_ipaddr_union(param, &e.address)) + goto out; + error = tomoyo_update_policy(&e.head, sizeof(e), param, + tomoyo_same_address_group); } out: tomoyo_put_group(group); @@ -137,3 +164,35 @@ bool tomoyo_number_matches_group(const unsigned long min, } return matched; } + +/** + * tomoyo_address_matches_group - Check whether the given address matches members of the given address group. + * + * @is_ipv6: True if @address is an IPv6 address. + * @address: An IPv4 or IPv6 address. + * @group: Pointer to "struct tomoyo_address_group". + * + * Returns true if @address matches addresses in @group group, false otherwise. + * + * Caller holds tomoyo_read_lock(). + */ +bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address, + const struct tomoyo_group *group) +{ + struct tomoyo_address_group *member; + bool matched = false; + const u8 size = is_ipv6 ? 16 : 4; + + list_for_each_entry_rcu(member, &group->member_list, head.list) { + if (member->head.is_deleted) + continue; + if (member->address.is_ipv6 != is_ipv6) + continue; + if (memcmp(&member->address.ip[0], address, size) > 0 || + memcmp(address, &member->address.ip[1], size) > 0) + continue; + matched = true; + break; + } + return matched; +} diff --git a/security/tomoyo/network.c b/security/tomoyo/network.c new file mode 100644 index 00000000000..97527710a72 --- /dev/null +++ b/security/tomoyo/network.c @@ -0,0 +1,771 @@ +/* + * security/tomoyo/network.c + * + * Copyright (C) 2005-2011 NTT DATA CORPORATION + */ + +#include "common.h" +#include + +/* Structure for holding inet domain socket's address. */ +struct tomoyo_inet_addr_info { + __be16 port; /* In network byte order. */ + const __be32 *address; /* In network byte order. */ + bool is_ipv6; +}; + +/* Structure for holding unix domain socket's address. */ +struct tomoyo_unix_addr_info { + u8 *addr; /* This may not be '\0' terminated string. */ + unsigned int addr_len; +}; + +/* Structure for holding socket address. */ +struct tomoyo_addr_info { + u8 protocol; + u8 operation; + struct tomoyo_inet_addr_info inet; + struct tomoyo_unix_addr_info unix0; +}; + +/* String table for socket's protocols. */ +const char * const tomoyo_proto_keyword[TOMOYO_SOCK_MAX] = { + [SOCK_STREAM] = "stream", + [SOCK_DGRAM] = "dgram", + [SOCK_RAW] = "raw", + [SOCK_SEQPACKET] = "seqpacket", + [0] = " ", /* Dummy for avoiding NULL pointer dereference. */ + [4] = " ", /* Dummy for avoiding NULL pointer dereference. */ +}; + +/** + * tomoyo_parse_ipaddr_union - Parse an IP address. + * + * @param: Pointer to "struct tomoyo_acl_param". + * @ptr: Pointer to "struct tomoyo_ipaddr_union". + * + * Returns true on success, false otherwise. + */ +bool tomoyo_parse_ipaddr_union(struct tomoyo_acl_param *param, + struct tomoyo_ipaddr_union *ptr) +{ + u8 * const min = ptr->ip[0].in6_u.u6_addr8; + u8 * const max = ptr->ip[1].in6_u.u6_addr8; + char *address = tomoyo_read_token(param); + const char *end; + + if (!strchr(address, ':') && + in4_pton(address, -1, min, '-', &end) > 0) { + ptr->is_ipv6 = false; + if (!*end) + ptr->ip[1].s6_addr32[0] = ptr->ip[0].s6_addr32[0]; + else if (*end++ != '-' || + in4_pton(end, -1, max, '\0', &end) <= 0 || *end) + return false; + return true; + } + if (in6_pton(address, -1, min, '-', &end) > 0) { + ptr->is_ipv6 = true; + if (!*end) + memmove(max, min, sizeof(u16) * 8); + else if (*end++ != '-' || + in6_pton(end, -1, max, '\0', &end) <= 0 || *end) + return false; + return true; + } + return false; +} + +/** + * tomoyo_print_ipv4 - Print an IPv4 address. + * + * @buffer: Buffer to write to. + * @buffer_len: Size of @buffer. + * @min_ip: Pointer to __be32. + * @max_ip: Pointer to __be32. + * + * Returns nothing. + */ +static void tomoyo_print_ipv4(char *buffer, const unsigned int buffer_len, + const __be32 *min_ip, const __be32 *max_ip) +{ + snprintf(buffer, buffer_len, "%pI4%c%pI4", min_ip, + *min_ip == *max_ip ? '\0' : '-', max_ip); +} + +/** + * tomoyo_print_ipv6 - Print an IPv6 address. + * + * @buffer: Buffer to write to. + * @buffer_len: Size of @buffer. + * @min_ip: Pointer to "struct in6_addr". + * @max_ip: Pointer to "struct in6_addr". + * + * Returns nothing. + */ +static void tomoyo_print_ipv6(char *buffer, const unsigned int buffer_len, + const struct in6_addr *min_ip, + const struct in6_addr *max_ip) +{ + snprintf(buffer, buffer_len, "%pI6c%c%pI6c", min_ip, + !memcmp(min_ip, max_ip, 16) ? '\0' : '-', max_ip); +} + +/** + * tomoyo_print_ip - Print an IP address. + * + * @buf: Buffer to write to. + * @size: Size of @buf. + * @ptr: Pointer to "struct ipaddr_union". + * + * Returns nothing. + */ +void tomoyo_print_ip(char *buf, const unsigned int size, + const struct tomoyo_ipaddr_union *ptr) +{ + if (ptr->is_ipv6) + tomoyo_print_ipv6(buf, size, &ptr->ip[0], &ptr->ip[1]); + else + tomoyo_print_ipv4(buf, size, &ptr->ip[0].s6_addr32[0], + &ptr->ip[1].s6_addr32[0]); +} + +/* + * Mapping table from "enum tomoyo_network_acl_index" to + * "enum tomoyo_mac_index" for inet domain socket. + */ +static const u8 tomoyo_inet2mac +[TOMOYO_SOCK_MAX][TOMOYO_MAX_NETWORK_OPERATION] = { + [SOCK_STREAM] = { + [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_STREAM_BIND, + [TOMOYO_NETWORK_LISTEN] = + TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN, + [TOMOYO_NETWORK_CONNECT] = + TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT, + }, + [SOCK_DGRAM] = { + [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_DGRAM_BIND, + [TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_INET_DGRAM_SEND, + }, + [SOCK_RAW] = { + [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_RAW_BIND, + [TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_INET_RAW_SEND, + }, +}; + +/* + * Mapping table from "enum tomoyo_network_acl_index" to + * "enum tomoyo_mac_index" for unix domain socket. + */ +static const u8 tomoyo_unix2mac +[TOMOYO_SOCK_MAX][TOMOYO_MAX_NETWORK_OPERATION] = { + [SOCK_STREAM] = { + [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND, + [TOMOYO_NETWORK_LISTEN] = + TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN, + [TOMOYO_NETWORK_CONNECT] = + TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT, + }, + [SOCK_DGRAM] = { + [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND, + [TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND, + }, + [SOCK_SEQPACKET] = { + [TOMOYO_NETWORK_BIND] = + TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND, + [TOMOYO_NETWORK_LISTEN] = + TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN, + [TOMOYO_NETWORK_CONNECT] = + TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT, + }, +}; + +/** + * tomoyo_same_inet_acl - Check for duplicated "struct tomoyo_inet_acl" entry. + * + * @a: Pointer to "struct tomoyo_acl_info". + * @b: Pointer to "struct tomoyo_acl_info". + * + * Returns true if @a == @b except permission bits, false otherwise. + */ +static bool tomoyo_same_inet_acl(const struct tomoyo_acl_info *a, + const struct tomoyo_acl_info *b) +{ + const struct tomoyo_inet_acl *p1 = container_of(a, typeof(*p1), head); + const struct tomoyo_inet_acl *p2 = container_of(b, typeof(*p2), head); + + return p1->protocol == p2->protocol && + tomoyo_same_ipaddr_union(&p1->address, &p2->address) && + tomoyo_same_number_union(&p1->port, &p2->port); +} + +/** + * tomoyo_same_unix_acl - Check for duplicated "struct tomoyo_unix_acl" entry. + * + * @a: Pointer to "struct tomoyo_acl_info". + * @b: Pointer to "struct tomoyo_acl_info". + * + * Returns true if @a == @b except permission bits, false otherwise. + */ +static bool tomoyo_same_unix_acl(const struct tomoyo_acl_info *a, + const struct tomoyo_acl_info *b) +{ + const struct tomoyo_unix_acl *p1 = container_of(a, typeof(*p1), head); + const struct tomoyo_unix_acl *p2 = container_of(b, typeof(*p2), head); + + return p1->protocol == p2->protocol && + tomoyo_same_name_union(&p1->name, &p2->name); +} + +/** + * tomoyo_merge_inet_acl - Merge duplicated "struct tomoyo_inet_acl" entry. + * + * @a: Pointer to "struct tomoyo_acl_info". + * @b: Pointer to "struct tomoyo_acl_info". + * @is_delete: True for @a &= ~@b, false for @a |= @b. + * + * Returns true if @a is empty, false otherwise. + */ +static bool tomoyo_merge_inet_acl(struct tomoyo_acl_info *a, + struct tomoyo_acl_info *b, + const bool is_delete) +{ + u8 * const a_perm = + &container_of(a, struct tomoyo_inet_acl, head)->perm; + u8 perm = *a_perm; + const u8 b_perm = container_of(b, struct tomoyo_inet_acl, head)->perm; + + if (is_delete) + perm &= ~b_perm; + else + perm |= b_perm; + *a_perm = perm; + return !perm; +} + +/** + * tomoyo_merge_unix_acl - Merge duplicated "struct tomoyo_unix_acl" entry. + * + * @a: Pointer to "struct tomoyo_acl_info". + * @b: Pointer to "struct tomoyo_acl_info". + * @is_delete: True for @a &= ~@b, false for @a |= @b. + * + * Returns true if @a is empty, false otherwise. + */ +static bool tomoyo_merge_unix_acl(struct tomoyo_acl_info *a, + struct tomoyo_acl_info *b, + const bool is_delete) +{ + u8 * const a_perm = + &container_of(a, struct tomoyo_unix_acl, head)->perm; + u8 perm = *a_perm; + const u8 b_perm = container_of(b, struct tomoyo_unix_acl, head)->perm; + + if (is_delete) + perm &= ~b_perm; + else + perm |= b_perm; + *a_perm = perm; + return !perm; +} + +/** + * tomoyo_write_inet_network - Write "struct tomoyo_inet_acl" list. + * + * @param: Pointer to "struct tomoyo_acl_param". + * + * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). + */ +int tomoyo_write_inet_network(struct tomoyo_acl_param *param) +{ + struct tomoyo_inet_acl e = { .head.type = TOMOYO_TYPE_INET_ACL }; + int error = -EINVAL; + u8 type; + const char *protocol = tomoyo_read_token(param); + const char *operation = tomoyo_read_token(param); + + for (e.protocol = 0; e.protocol < TOMOYO_SOCK_MAX; e.protocol++) + if (!strcmp(protocol, tomoyo_proto_keyword[e.protocol])) + break; + for (type = 0; type < TOMOYO_MAX_NETWORK_OPERATION; type++) + if (tomoyo_permstr(operation, tomoyo_socket_keyword[type])) + e.perm |= 1 << type; + if (e.protocol == TOMOYO_SOCK_MAX || !e.perm) + return -EINVAL; + if (param->data[0] == '@') { + param->data++; + e.address.group = + tomoyo_get_group(param, TOMOYO_ADDRESS_GROUP); + if (!e.address.group) + return -ENOMEM; + } else { + if (!tomoyo_parse_ipaddr_union(param, &e.address)) + goto out; + } + if (!tomoyo_parse_number_union(param, &e.port) || + e.port.values[1] > 65535) + goto out; + error = tomoyo_update_domain(&e.head, sizeof(e), param, + tomoyo_same_inet_acl, + tomoyo_merge_inet_acl); +out: + tomoyo_put_group(e.address.group); + tomoyo_put_number_union(&e.port); + return error; +} + +/** + * tomoyo_write_unix_network - Write "struct tomoyo_unix_acl" list. + * + * @param: Pointer to "struct tomoyo_acl_param". + * + * Returns 0 on success, negative value otherwise. + */ +int tomoyo_write_unix_network(struct tomoyo_acl_param *param) +{ + struct tomoyo_unix_acl e = { .head.type = TOMOYO_TYPE_UNIX_ACL }; + int error; + u8 type; + const char *protocol = tomoyo_read_token(param); + const char *operation = tomoyo_read_token(param); + + for (e.protocol = 0; e.protocol < TOMOYO_SOCK_MAX; e.protocol++) + if (!strcmp(protocol, tomoyo_proto_keyword[e.protocol])) + break; + for (type = 0; type < TOMOYO_MAX_NETWORK_OPERATION; type++) + if (tomoyo_permstr(operation, tomoyo_socket_keyword[type])) + e.perm |= 1 << type; + if (e.protocol == TOMOYO_SOCK_MAX || !e.perm) + return -EINVAL; + if (!tomoyo_parse_name_union(param, &e.name)) + return -EINVAL; + error = tomoyo_update_domain(&e.head, sizeof(e), param, + tomoyo_same_unix_acl, + tomoyo_merge_unix_acl); + tomoyo_put_name_union(&e.name); + return error; +} + +/** + * tomoyo_audit_net_log - Audit network log. + * + * @r: Pointer to "struct tomoyo_request_info". + * @family: Name of socket family ("inet" or "unix"). + * @protocol: Name of protocol in @family. + * @operation: Name of socket operation. + * @address: Name of address. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_audit_net_log(struct tomoyo_request_info *r, + const char *family, const u8 protocol, + const u8 operation, const char *address) +{ + return tomoyo_supervisor(r, "network %s %s %s %s\n", family, + tomoyo_proto_keyword[protocol], + tomoyo_socket_keyword[operation], address); +} + +/** + * tomoyo_audit_inet_log - Audit INET network log. + * + * @r: Pointer to "struct tomoyo_request_info". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_audit_inet_log(struct tomoyo_request_info *r) +{ + char buf[128]; + int len; + const __be32 *address = r->param.inet_network.address; + + if (r->param.inet_network.is_ipv6) + tomoyo_print_ipv6(buf, sizeof(buf), (const struct in6_addr *) + address, (const struct in6_addr *) address); + else + tomoyo_print_ipv4(buf, sizeof(buf), address, address); + len = strlen(buf); + snprintf(buf + len, sizeof(buf) - len, " %u", + r->param.inet_network.port); + return tomoyo_audit_net_log(r, "inet", r->param.inet_network.protocol, + r->param.inet_network.operation, buf); +} + +/** + * tomoyo_audit_unix_log - Audit UNIX network log. + * + * @r: Pointer to "struct tomoyo_request_info". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_audit_unix_log(struct tomoyo_request_info *r) +{ + return tomoyo_audit_net_log(r, "unix", r->param.unix_network.protocol, + r->param.unix_network.operation, + r->param.unix_network.address->name); +} + +/** + * tomoyo_check_inet_acl - Check permission for inet domain socket operation. + * + * @r: Pointer to "struct tomoyo_request_info". + * @ptr: Pointer to "struct tomoyo_acl_info". + * + * Returns true if granted, false otherwise. + */ +static bool tomoyo_check_inet_acl(struct tomoyo_request_info *r, + const struct tomoyo_acl_info *ptr) +{ + const struct tomoyo_inet_acl *acl = + container_of(ptr, typeof(*acl), head); + const u8 size = r->param.inet_network.is_ipv6 ? 16 : 4; + + if (!(acl->perm & (1 << r->param.inet_network.operation)) || + !tomoyo_compare_number_union(r->param.inet_network.port, + &acl->port)) + return false; + if (acl->address.group) + return tomoyo_address_matches_group + (r->param.inet_network.is_ipv6, + r->param.inet_network.address, acl->address.group); + return acl->address.is_ipv6 == r->param.inet_network.is_ipv6 && + memcmp(&acl->address.ip[0], + r->param.inet_network.address, size) <= 0 && + memcmp(r->param.inet_network.address, + &acl->address.ip[1], size) <= 0; +} + +/** + * tomoyo_check_unix_acl - Check permission for unix domain socket operation. + * + * @r: Pointer to "struct tomoyo_request_info". + * @ptr: Pointer to "struct tomoyo_acl_info". + * + * Returns true if granted, false otherwise. + */ +static bool tomoyo_check_unix_acl(struct tomoyo_request_info *r, + const struct tomoyo_acl_info *ptr) +{ + const struct tomoyo_unix_acl *acl = + container_of(ptr, typeof(*acl), head); + + return (acl->perm & (1 << r->param.unix_network.operation)) && + tomoyo_compare_name_union(r->param.unix_network.address, + &acl->name); +} + +/** + * tomoyo_inet_entry - Check permission for INET network operation. + * + * @address: Pointer to "struct tomoyo_addr_info". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_inet_entry(const struct tomoyo_addr_info *address) +{ + const int idx = tomoyo_read_lock(); + struct tomoyo_request_info r; + int error = 0; + const u8 type = tomoyo_inet2mac[address->protocol][address->operation]; + + if (type && tomoyo_init_request_info(&r, NULL, type) + != TOMOYO_CONFIG_DISABLED) { + r.param_type = TOMOYO_TYPE_INET_ACL; + r.param.inet_network.protocol = address->protocol; + r.param.inet_network.operation = address->operation; + r.param.inet_network.is_ipv6 = address->inet.is_ipv6; + r.param.inet_network.address = address->inet.address; + r.param.inet_network.port = ntohs(address->inet.port); + do { + tomoyo_check_acl(&r, tomoyo_check_inet_acl); + error = tomoyo_audit_inet_log(&r); + } while (error == TOMOYO_RETRY_REQUEST); + } + tomoyo_read_unlock(idx); + return error; +} + +/** + * tomoyo_check_inet_address - Check permission for inet domain socket's operation. + * + * @addr: Pointer to "struct sockaddr". + * @addr_len: Size of @addr. + * @port: Port number. + * @address: Pointer to "struct tomoyo_addr_info". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_check_inet_address(const struct sockaddr *addr, + const unsigned int addr_len, + const u16 port, + struct tomoyo_addr_info *address) +{ + struct tomoyo_inet_addr_info *i = &address->inet; + + switch (addr->sa_family) { + case AF_INET6: + if (addr_len < SIN6_LEN_RFC2133) + goto skip; + i->is_ipv6 = true; + i->address = (__be32 *) + ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr; + i->port = ((struct sockaddr_in6 *) addr)->sin6_port; + break; + case AF_INET: + if (addr_len < sizeof(struct sockaddr_in)) + goto skip; + i->is_ipv6 = false; + i->address = (__be32 *) + &((struct sockaddr_in *) addr)->sin_addr; + i->port = ((struct sockaddr_in *) addr)->sin_port; + break; + default: + goto skip; + } + if (address->protocol == SOCK_RAW) + i->port = htons(port); + return tomoyo_inet_entry(address); +skip: + return 0; +} + +/** + * tomoyo_unix_entry - Check permission for UNIX network operation. + * + * @address: Pointer to "struct tomoyo_addr_info". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_unix_entry(const struct tomoyo_addr_info *address) +{ + const int idx = tomoyo_read_lock(); + struct tomoyo_request_info r; + int error = 0; + const u8 type = tomoyo_unix2mac[address->protocol][address->operation]; + + if (type && tomoyo_init_request_info(&r, NULL, type) + != TOMOYO_CONFIG_DISABLED) { + char *buf = address->unix0.addr; + int len = address->unix0.addr_len - sizeof(sa_family_t); + + if (len <= 0) { + buf = "anonymous"; + len = 9; + } else if (buf[0]) { + len = strnlen(buf, len); + } + buf = tomoyo_encode2(buf, len); + if (buf) { + struct tomoyo_path_info addr; + + addr.name = buf; + tomoyo_fill_path_info(&addr); + r.param_type = TOMOYO_TYPE_UNIX_ACL; + r.param.unix_network.protocol = address->protocol; + r.param.unix_network.operation = address->operation; + r.param.unix_network.address = &addr; + do { + tomoyo_check_acl(&r, tomoyo_check_unix_acl); + error = tomoyo_audit_unix_log(&r); + } while (error == TOMOYO_RETRY_REQUEST); + kfree(buf); + } else + error = -ENOMEM; + } + tomoyo_read_unlock(idx); + return error; +} + +/** + * tomoyo_check_unix_address - Check permission for unix domain socket's operation. + * + * @addr: Pointer to "struct sockaddr". + * @addr_len: Size of @addr. + * @address: Pointer to "struct tomoyo_addr_info". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_check_unix_address(struct sockaddr *addr, + const unsigned int addr_len, + struct tomoyo_addr_info *address) +{ + struct tomoyo_unix_addr_info *u = &address->unix0; + + if (addr->sa_family != AF_UNIX) + return 0; + u->addr = ((struct sockaddr_un *) addr)->sun_path; + u->addr_len = addr_len; + return tomoyo_unix_entry(address); +} + +/** + * tomoyo_kernel_service - Check whether I'm kernel service or not. + * + * Returns true if I'm kernel service, false otherwise. + */ +static bool tomoyo_kernel_service(void) +{ + /* Nothing to do if I am a kernel service. */ + return segment_eq(get_fs(), KERNEL_DS); +} + +/** + * tomoyo_sock_family - Get socket's family. + * + * @sk: Pointer to "struct sock". + * + * Returns one of PF_INET, PF_INET6, PF_UNIX or 0. + */ +static u8 tomoyo_sock_family(struct sock *sk) +{ + u8 family; + + if (tomoyo_kernel_service()) + return 0; + family = sk->sk_family; + switch (family) { + case PF_INET: + case PF_INET6: + case PF_UNIX: + return family; + default: + return 0; + } +} + +/** + * tomoyo_socket_listen_permission - Check permission for listening a socket. + * + * @sock: Pointer to "struct socket". + * + * Returns 0 on success, negative value otherwise. + */ +int tomoyo_socket_listen_permission(struct socket *sock) +{ + struct tomoyo_addr_info address; + const u8 family = tomoyo_sock_family(sock->sk); + const unsigned int type = sock->type; + struct sockaddr_storage addr; + int addr_len; + + if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET)) + return 0; + { + const int error = sock->ops->getname(sock, (struct sockaddr *) + &addr, &addr_len, 0); + + if (error) + return error; + } + address.protocol = type; + address.operation = TOMOYO_NETWORK_LISTEN; + if (family == PF_UNIX) + return tomoyo_check_unix_address((struct sockaddr *) &addr, + addr_len, &address); + return tomoyo_check_inet_address((struct sockaddr *) &addr, addr_len, + 0, &address); +} + +/** + * tomoyo_socket_connect_permission - Check permission for setting the remote address of a socket. + * + * @sock: Pointer to "struct socket". + * @addr: Pointer to "struct sockaddr". + * @addr_len: Size of @addr. + * + * Returns 0 on success, negative value otherwise. + */ +int tomoyo_socket_connect_permission(struct socket *sock, + struct sockaddr *addr, int addr_len) +{ + struct tomoyo_addr_info address; + const u8 family = tomoyo_sock_family(sock->sk); + const unsigned int type = sock->type; + + if (!family) + return 0; + address.protocol = type; + switch (type) { + case SOCK_DGRAM: + case SOCK_RAW: + address.operation = TOMOYO_NETWORK_SEND; + break; + case SOCK_STREAM: + case SOCK_SEQPACKET: + address.operation = TOMOYO_NETWORK_CONNECT; + break; + default: + return 0; + } + if (family == PF_UNIX) + return tomoyo_check_unix_address(addr, addr_len, &address); + return tomoyo_check_inet_address(addr, addr_len, sock->sk->sk_protocol, + &address); +} + +/** + * tomoyo_socket_bind_permission - Check permission for setting the local address of a socket. + * + * @sock: Pointer to "struct socket". + * @addr: Pointer to "struct sockaddr". + * @addr_len: Size of @addr. + * + * Returns 0 on success, negative value otherwise. + */ +int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr, + int addr_len) +{ + struct tomoyo_addr_info address; + const u8 family = tomoyo_sock_family(sock->sk); + const unsigned int type = sock->type; + + if (!family) + return 0; + switch (type) { + case SOCK_STREAM: + case SOCK_DGRAM: + case SOCK_RAW: + case SOCK_SEQPACKET: + address.protocol = type; + address.operation = TOMOYO_NETWORK_BIND; + break; + default: + return 0; + } + if (family == PF_UNIX) + return tomoyo_check_unix_address(addr, addr_len, &address); + return tomoyo_check_inet_address(addr, addr_len, sock->sk->sk_protocol, + &address); +} + +/** + * tomoyo_socket_sendmsg_permission - Check permission for sending a datagram. + * + * @sock: Pointer to "struct socket". + * @msg: Pointer to "struct msghdr". + * @size: Unused. + * + * Returns 0 on success, negative value otherwise. + */ +int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg, + int size) +{ + struct tomoyo_addr_info address; + const u8 family = tomoyo_sock_family(sock->sk); + const unsigned int type = sock->type; + + if (!msg->msg_name || !family || + (type != SOCK_DGRAM && type != SOCK_RAW)) + return 0; + address.protocol = type; + address.operation = TOMOYO_NETWORK_SEND; + if (family == PF_UNIX) + return tomoyo_check_unix_address((struct sockaddr *) + msg->msg_name, + msg->msg_namelen, &address); + return tomoyo_check_inet_address((struct sockaddr *) msg->msg_name, + msg->msg_namelen, + sock->sk->sk_protocol, &address); +} diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 6c601bd300f..738bbdf8d4c 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -15,17 +15,19 @@ #include "../../fs/internal.h" /** - * tomoyo_encode: Convert binary string to ascii string. + * tomoyo_encode2 - Encode binary string to ascii string. * - * @str: String in binary format. + * @str: String in binary format. + * @str_len: Size of @str in byte. * * Returns pointer to @str in ascii format on success, NULL otherwise. * * This function uses kzalloc(), so caller must kfree() if this function * didn't return NULL. */ -char *tomoyo_encode(const char *str) +char *tomoyo_encode2(const char *str, int str_len) { + int i; int len = 0; const char *p = str; char *cp; @@ -33,8 +35,9 @@ char *tomoyo_encode(const char *str) if (!p) return NULL; - while (*p) { - const unsigned char c = *p++; + for (i = 0; i < str_len; i++) { + const unsigned char c = p[i]; + if (c == '\\') len += 2; else if (c > ' ' && c < 127) @@ -49,8 +52,8 @@ char *tomoyo_encode(const char *str) return NULL; cp0 = cp; p = str; - while (*p) { - const unsigned char c = *p++; + for (i = 0; i < str_len; i++) { + const unsigned char c = p[i]; if (c == '\\') { *cp++ = '\\'; @@ -67,6 +70,21 @@ char *tomoyo_encode(const char *str) return cp0; } +/** + * tomoyo_encode - Encode binary string to ascii string. + * + * @str: String in binary format. + * + * Returns pointer to @str in ascii format on success, NULL otherwise. + * + * This function uses kzalloc(), so caller must kfree() if this function + * didn't return NULL. + */ +char *tomoyo_encode(const char *str) +{ + return str ? tomoyo_encode2(str, strlen(str)) : NULL; +} + /** * tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root. * diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index f776400a8f3..4b327b69174 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) return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path); } +/** + * tomoyo_socket_listen - Check permission for listen(). + * + * @sock: Pointer to "struct socket". + * @backlog: Backlog parameter. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_socket_listen(struct socket *sock, int backlog) +{ + return tomoyo_socket_listen_permission(sock); +} + +/** + * tomoyo_socket_connect - Check permission for connect(). + * + * @sock: Pointer to "struct socket". + * @addr: Pointer to "struct sockaddr". + * @addr_len: Size of @addr. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_socket_connect(struct socket *sock, struct sockaddr *addr, + int addr_len) +{ + return tomoyo_socket_connect_permission(sock, addr, addr_len); +} + +/** + * tomoyo_socket_bind - Check permission for bind(). + * + * @sock: Pointer to "struct socket". + * @addr: Pointer to "struct sockaddr". + * @addr_len: Size of @addr. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_socket_bind(struct socket *sock, struct sockaddr *addr, + int addr_len) +{ + return tomoyo_socket_bind_permission(sock, addr, addr_len); +} + +/** + * tomoyo_socket_sendmsg - Check permission for sendmsg(). + * + * @sock: Pointer to "struct socket". + * @msg: Pointer to "struct msghdr". + * @size: Size of message. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg, + int size) +{ + return tomoyo_socket_sendmsg_permission(sock, msg, size); +} + /* * tomoyo_security_ops is a "struct security_operations" which is used for * registering TOMOYO. @@ -472,6 +530,10 @@ static struct security_operations tomoyo_security_ops = { .sb_mount = tomoyo_sb_mount, .sb_umount = tomoyo_sb_umount, .sb_pivotroot = tomoyo_sb_pivotroot, + .socket_bind = tomoyo_socket_bind, + .socket_connect = tomoyo_socket_connect, + .socket_listen = tomoyo_socket_listen, + .socket_sendmsg = tomoyo_socket_sendmsg, }; /* Lock for GC. */ diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index cb7d507b631..a1c3d9ccebf 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c @@ -42,6 +42,37 @@ const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = { [TOMOYO_MAC_FILE_MOUNT] = TOMOYO_MAC_CATEGORY_FILE, [TOMOYO_MAC_FILE_UMOUNT] = TOMOYO_MAC_CATEGORY_FILE, [TOMOYO_MAC_FILE_PIVOT_ROOT] = TOMOYO_MAC_CATEGORY_FILE, + /* CONFIG::network group */ + [TOMOYO_MAC_NETWORK_INET_STREAM_BIND] = + TOMOYO_MAC_CATEGORY_NETWORK, + [TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN] = + TOMOYO_MAC_CATEGORY_NETWORK, + [TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT] = + TOMOYO_MAC_CATEGORY_NETWORK, + [TOMOYO_MAC_NETWORK_INET_DGRAM_BIND] = + TOMOYO_MAC_CATEGORY_NETWORK, + [TOMOYO_MAC_NETWORK_INET_DGRAM_SEND] = + TOMOYO_MAC_CATEGORY_NETWORK, + [TOMOYO_MAC_NETWORK_INET_RAW_BIND] = + TOMOYO_MAC_CATEGORY_NETWORK, + [TOMOYO_MAC_NETWORK_INET_RAW_SEND] = + TOMOYO_MAC_CATEGORY_NETWORK, + [TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND] = + TOMOYO_MAC_CATEGORY_NETWORK, + [TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN] = + TOMOYO_MAC_CATEGORY_NETWORK, + [TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT] = + TOMOYO_MAC_CATEGORY_NETWORK, + [TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND] = + TOMOYO_MAC_CATEGORY_NETWORK, + [TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND] = + TOMOYO_MAC_CATEGORY_NETWORK, + [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND] = + TOMOYO_MAC_CATEGORY_NETWORK, + [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = + TOMOYO_MAC_CATEGORY_NETWORK, + [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = + TOMOYO_MAC_CATEGORY_NETWORK, /* CONFIG::misc group */ [TOMOYO_MAC_ENVIRON] = TOMOYO_MAC_CATEGORY_MISC, }; -- cgit v1.2.3-70-g09d2 From 1f067a682a9bd252107ac6f6946b7332fde42344 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sat, 10 Sep 2011 15:24:56 +0900 Subject: TOMOYO: Allow controlling generation of access granted logs for per an entry basis. Add per-entry flag which controls generation of grant logs because Xen and KVM issues ioctl requests so frequently. For example, file ioctl /dev/null 0x5401 grant_log=no will suppress /sys/kernel/security/tomoyo/audit even if preference says grant_log=yes . Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/audit.c | 7 ++++++- security/tomoyo/common.c | 4 ++++ security/tomoyo/common.h | 12 ++++++++++++ security/tomoyo/condition.c | 15 +++++++++++++++ security/tomoyo/domain.c | 1 + 5 files changed, 38 insertions(+), 1 deletion(-) (limited to 'security/tomoyo/common.c') diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c index 5dbb1f7617c..075c3a6d164 100644 --- a/security/tomoyo/audit.c +++ b/security/tomoyo/audit.c @@ -313,6 +313,7 @@ static unsigned int tomoyo_log_count; */ static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns, const u8 profile, const u8 index, + const struct tomoyo_acl_info *matched_acl, const bool is_granted) { u8 mode; @@ -324,6 +325,9 @@ static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns, p = tomoyo_profile(ns, profile); if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG]) return false; + if (is_granted && matched_acl && matched_acl->cond && + matched_acl->cond->grant_log != TOMOYO_GRANTLOG_AUTO) + return matched_acl->cond->grant_log == TOMOYO_GRANTLOG_YES; mode = p->config[index]; if (mode == TOMOYO_CONFIG_USE_DEFAULT) mode = p->config[category]; @@ -350,7 +354,8 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, char *buf; struct tomoyo_log *entry; bool quota_exceeded = false; - if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, r->granted)) + if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, + r->matched_acl, r->granted)) goto out; buf = tomoyo_init_log(r, len, fmt, args); if (!buf) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 85d915587a7..2704c384bf1 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -1272,6 +1272,10 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head, head->r.cond_step++; /* fall through */ case 3: + if (cond->grant_log != TOMOYO_GRANTLOG_AUTO) + tomoyo_io_printf(head, " grant_log=%s", + tomoyo_yesno(cond->grant_log == + TOMOYO_GRANTLOG_YES)); tomoyo_set_lf(head); return true; } diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index d1c758e7f92..435b3d869fc 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -179,6 +179,16 @@ enum tomoyo_domain_info_flags_index { TOMOYO_MAX_DOMAIN_INFO_FLAGS }; +/* Index numbers for audit type. */ +enum tomoyo_grant_log { + /* Follow profile's configuration. */ + TOMOYO_GRANTLOG_AUTO, + /* Do not generate grant log. */ + TOMOYO_GRANTLOG_NO, + /* Generate grant_log. */ + TOMOYO_GRANTLOG_YES, +}; + /* Index numbers for group entries. */ enum tomoyo_group_id { TOMOYO_PATH_GROUP, @@ -471,6 +481,7 @@ struct tomoyo_request_info { int need_dev; } mount; } param; + struct tomoyo_acl_info *matched_acl; u8 param_type; bool granted; u8 retry; @@ -635,6 +646,7 @@ struct tomoyo_condition { u16 names_count; /* Number of "struct tomoyo_name_union names". */ u16 argc; /* Number of "struct tomoyo_argv". */ u16 envc; /* Number of "struct tomoyo_envp". */ + u8 grant_log; /* One of values in "enum tomoyo_grant_log". */ /* * struct tomoyo_condition_element condition[condc]; * struct tomoyo_number_union values[numbers_count]; diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c index 8a05f71eaf6..3a05eb3e2a6 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, a->numbers_count == b->numbers_count && a->names_count == b->names_count && a->argc == b->argc && a->envc == b->envc && + a->grant_log == b->grant_log && !memcmp(a + 1, b + 1, a->size - sizeof(*a)); } @@ -486,6 +487,20 @@ rerun: goto out; dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word, is_not ? "!" : "", right_word); + if (!strcmp(left_word, "grant_log")) { + if (entry) { + if (is_not || + entry->grant_log != TOMOYO_GRANTLOG_AUTO) + goto out; + else if (!strcmp(right_word, "yes")) + entry->grant_log = TOMOYO_GRANTLOG_YES; + else if (!strcmp(right_word, "no")) + entry->grant_log = TOMOYO_GRANTLOG_NO; + else + goto out; + } + continue; + } if (!strncmp(left_word, "exec.argv[", 10)) { if (!argv) { e.argc++; diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 5931fb1c04d..498fea732f4 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -157,6 +157,7 @@ retry: continue; if (!tomoyo_condition(r, ptr->cond)) continue; + r->matched_acl = ptr; r->granted = true; return; } -- cgit v1.2.3-70-g09d2 From 731d37aa70c7b9de3be6bf2c8287366223bf5ce5 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sat, 10 Sep 2011 15:25:58 +0900 Subject: TOMOYO: Allow domain transition without execve(). To be able to split permissions for Apache's CGI programs which are executed without execve(), add special domain transition which is performed by writing a TOMOYO's domainname to /sys/kernel/security/tomoyo/self_domain interface. This is an API for TOMOYO-aware userland applications. However, since I expect TOMOYO and other LSM modules to run in parallel, this patch does not use /proc/self/attr/ interface in order to avoid conflicts with other LSM modules when it became possible to run multiple LSM modules in parallel. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.c | 75 ++++++++++++++++-------- security/tomoyo/common.h | 16 +++++- security/tomoyo/securityfs_if.c | 122 +++++++++++++++++++++++++++++++++++++++- security/tomoyo/util.c | 25 ++++++++ 4 files changed, 210 insertions(+), 28 deletions(-) (limited to 'security/tomoyo/common.c') diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 2704c384bf1..1fd0fc1059b 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -1010,6 +1010,48 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head, return true; } +/** + * tomoyo_same_task_acl - Check for duplicated "struct tomoyo_task_acl" entry. + * + * @a: Pointer to "struct tomoyo_acl_info". + * @b: Pointer to "struct tomoyo_acl_info". + * + * Returns true if @a == @b, false otherwise. + */ +static bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a, + const struct tomoyo_acl_info *b) +{ + const struct tomoyo_task_acl *p1 = container_of(a, typeof(*p1), head); + const struct tomoyo_task_acl *p2 = container_of(b, typeof(*p2), head); + return p1->domainname == p2->domainname; +} + +/** + * tomoyo_write_task - Update task related list. + * + * @param: Pointer to "struct tomoyo_acl_param". + * + * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). + */ +static int tomoyo_write_task(struct tomoyo_acl_param *param) +{ + int error = -EINVAL; + if (tomoyo_str_starts(¶m->data, "manual_domain_transition ")) { + struct tomoyo_task_acl e = { + .head.type = TOMOYO_TYPE_MANUAL_TASK_ACL, + .domainname = tomoyo_get_domainname(param), + }; + if (e.domainname) + error = tomoyo_update_domain(&e.head, sizeof(e), param, + tomoyo_same_task_acl, + NULL); + tomoyo_put_name(e.domainname); + } + return error; +} + /** * tomoyo_delete_domain - Delete a domain. * @@ -1068,11 +1110,12 @@ static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns, static const struct { const char *keyword; int (*write) (struct tomoyo_acl_param *); - } tomoyo_callback[4] = { + } tomoyo_callback[5] = { { "file ", tomoyo_write_file }, { "network inet ", tomoyo_write_inet_network }, { "network unix ", tomoyo_write_unix_network }, { "misc ", tomoyo_write_misc }, + { "task ", tomoyo_write_task }, }; u8 i; @@ -1343,6 +1386,12 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, if (first) return true; tomoyo_print_name_union(head, &ptr->name); + } else if (acl_type == TOMOYO_TYPE_MANUAL_TASK_ACL) { + struct tomoyo_task_acl *ptr = + container_of(acl, typeof(*ptr), head); + tomoyo_set_group(head, "task "); + tomoyo_set_string(head, "manual_domain_transition "); + tomoyo_set_string(head, ptr->domainname->name); } else if (head->r.print_transition_related_only) { return true; } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { @@ -2178,26 +2227,6 @@ static void tomoyo_read_version(struct tomoyo_io_buffer *head) } } -/** - * tomoyo_read_self_domain - Get the current process's domainname. - * - * @head: Pointer to "struct tomoyo_io_buffer". - * - * Returns the current process's domainname. - */ -static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head) -{ - if (!head->r.eof) { - /* - * tomoyo_domain()->domainname != NULL - * because every process belongs to a domain and - * the domain's name cannot be NULL. - */ - tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name); - head->r.eof = true; - } -} - /* String table for /sys/kernel/security/tomoyo/stat interface. */ static const char * const tomoyo_policy_headers[TOMOYO_MAX_POLICY_STAT] = { [TOMOYO_STAT_POLICY_UPDATES] = "update:", @@ -2328,10 +2357,6 @@ int tomoyo_open_control(const u8 type, struct file *file) head->poll = tomoyo_poll_log; head->read = tomoyo_read_log; break; - case TOMOYO_SELFDOMAIN: - /* /sys/kernel/security/tomoyo/self_domain */ - head->read = tomoyo_read_self_domain; - break; case TOMOYO_PROCESS_STATUS: /* /sys/kernel/security/tomoyo/.process_status */ head->write = tomoyo_write_pid; diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 435b3d869fc..af82683df7f 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -227,6 +227,7 @@ enum tomoyo_acl_entry_type_index { TOMOYO_TYPE_INET_ACL, TOMOYO_TYPE_UNIX_ACL, TOMOYO_TYPE_ENV_ACL, + TOMOYO_TYPE_MANUAL_TASK_ACL, }; /* Index numbers for access controls with one pathname. */ @@ -295,7 +296,6 @@ enum tomoyo_securityfs_interface_index { TOMOYO_EXCEPTIONPOLICY, TOMOYO_PROCESS_STATUS, TOMOYO_STAT, - TOMOYO_SELFDOMAIN, TOMOYO_AUDIT, TOMOYO_VERSION, TOMOYO_PROFILE, @@ -480,6 +480,9 @@ struct tomoyo_request_info { unsigned long flags; int need_dev; } mount; + struct { + const struct tomoyo_path_info *domainname; + } task; } param; struct tomoyo_acl_info *matched_acl; u8 param_type; @@ -679,6 +682,15 @@ struct tomoyo_domain_info { atomic_t users; /* Number of referring credentials. */ }; +/* + * Structure for "task manual_domain_transition" directive. + */ +struct tomoyo_task_acl { + struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MANUAL_TASK_ACL */ + /* Pointer to domainname. */ + const struct tomoyo_path_info *domainname; +}; + /* * Structure for "file execute", "file read", "file write", "file append", * "file unlink", "file getattr", "file rmdir", "file truncate", @@ -935,6 +947,8 @@ const char *tomoyo_get_exe(void); const char *tomoyo_yesno(const unsigned int value); const struct tomoyo_path_info *tomoyo_compare_name_union (const struct tomoyo_path_info *name, const struct tomoyo_name_union *ptr); +const struct tomoyo_path_info *tomoyo_get_domainname +(struct tomoyo_acl_param *param); const struct tomoyo_path_info *tomoyo_get_name(const char *name); const struct tomoyo_path_info *tomoyo_path_matches_group (const struct tomoyo_path_info *pathname, const struct tomoyo_group *group); diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c index a49c3bfd4dd..d08296a4882 100644 --- a/security/tomoyo/securityfs_if.c +++ b/security/tomoyo/securityfs_if.c @@ -7,6 +7,124 @@ #include #include "common.h" +/** + * tomoyo_check_task_acl - Check permission for task operation. + * + * @r: Pointer to "struct tomoyo_request_info". + * @ptr: Pointer to "struct tomoyo_acl_info". + * + * Returns true if granted, false otherwise. + */ +static bool tomoyo_check_task_acl(struct tomoyo_request_info *r, + const struct tomoyo_acl_info *ptr) +{ + const struct tomoyo_task_acl *acl = container_of(ptr, typeof(*acl), + head); + return !tomoyo_pathcmp(r->param.task.domainname, acl->domainname); +} + +/** + * tomoyo_write_self - write() for /sys/kernel/security/tomoyo/self_domain interface. + * + * @file: Pointer to "struct file". + * @buf: Domainname to transit to. + * @count: Size of @buf. + * @ppos: Unused. + * + * Returns @count on success, negative value otherwise. + * + * If domain transition was permitted but the domain transition failed, this + * function returns error rather than terminating current thread with SIGKILL. + */ +static ssize_t tomoyo_write_self(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + char *data; + int error; + if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10) + return -ENOMEM; + data = kzalloc(count + 1, GFP_NOFS); + if (!data) + return -ENOMEM; + if (copy_from_user(data, buf, count)) { + error = -EFAULT; + goto out; + } + tomoyo_normalize_line(data); + if (tomoyo_correct_domain(data)) { + const int idx = tomoyo_read_lock(); + struct tomoyo_path_info name; + struct tomoyo_request_info r; + name.name = data; + tomoyo_fill_path_info(&name); + /* Check "task manual_domain_transition" permission. */ + tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE); + r.param_type = TOMOYO_TYPE_MANUAL_TASK_ACL; + r.param.task.domainname = &name; + tomoyo_check_acl(&r, tomoyo_check_task_acl); + if (!r.granted) + error = -EPERM; + else { + struct tomoyo_domain_info *new_domain = + tomoyo_assign_domain(data, true); + if (!new_domain) { + error = -ENOENT; + } else { + struct cred *cred = prepare_creds(); + if (!cred) { + error = -ENOMEM; + } else { + struct tomoyo_domain_info *old_domain = + cred->security; + cred->security = new_domain; + atomic_inc(&new_domain->users); + atomic_dec(&old_domain->users); + commit_creds(cred); + error = 0; + } + } + } + tomoyo_read_unlock(idx); + } else + error = -EINVAL; +out: + kfree(data); + return error ? error : count; +} + +/** + * tomoyo_read_self - read() for /sys/kernel/security/tomoyo/self_domain interface. + * + * @file: Pointer to "struct file". + * @buf: Domainname which current thread belongs to. + * @count: Size of @buf. + * @ppos: Bytes read by now. + * + * Returns read size on success, negative value otherwise. + */ +static ssize_t tomoyo_read_self(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + const char *domain = tomoyo_domain()->domainname->name; + loff_t len = strlen(domain); + loff_t pos = *ppos; + if (pos >= len || !count) + return 0; + len -= pos; + if (count < len) + len = count; + if (copy_to_user(buf, domain + pos, len)) + return -EFAULT; + *ppos += len; + return len; +} + +/* Operations for /sys/kernel/security/tomoyo/self_domain interface. */ +static const struct file_operations tomoyo_self_operations = { + .write = tomoyo_write_self, + .read = tomoyo_read_self, +}; + /** * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. * @@ -135,8 +253,6 @@ static int __init tomoyo_initerface_init(void) TOMOYO_EXCEPTIONPOLICY); tomoyo_create_entry("audit", 0400, tomoyo_dir, TOMOYO_AUDIT); - tomoyo_create_entry("self_domain", 0400, tomoyo_dir, - TOMOYO_SELFDOMAIN); tomoyo_create_entry(".process_status", 0600, tomoyo_dir, TOMOYO_PROCESS_STATUS); tomoyo_create_entry("stat", 0644, tomoyo_dir, @@ -147,6 +263,8 @@ static int __init tomoyo_initerface_init(void) TOMOYO_MANAGER); tomoyo_create_entry("version", 0400, tomoyo_dir, TOMOYO_VERSION); + securityfs_create_file("self_domain", 0666, tomoyo_dir, NULL, + &tomoyo_self_operations); return 0; } diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index a1c3d9ccebf..50e9b4c73ce 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c @@ -158,6 +158,31 @@ char *tomoyo_read_token(struct tomoyo_acl_param *param) return pos; } +/** + * tomoyo_get_domainname - Read a domainname from a line. + * + * @param: Pointer to "struct tomoyo_acl_param". + * + * Returns a domainname on success, NULL otherwise. + */ +const struct tomoyo_path_info *tomoyo_get_domainname +(struct tomoyo_acl_param *param) +{ + char *start = param->data; + char *pos = start; + while (*pos) { + if (*pos++ != ' ' || *pos++ == '/') + continue; + pos -= 2; + *pos++ = '\0'; + break; + } + param->data = pos; + if (tomoyo_correct_domain(start)) + return tomoyo_get_name(start); + return NULL; +} + /** * tomoyo_parse_ulong - Parse an "unsigned long" value. * -- cgit v1.2.3-70-g09d2 From 843d183cdd816549b73e6bd3ae07f64adddf714b Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 14 Sep 2011 17:03:19 +0900 Subject: TOMOYO: Bump version. Tell userland tools that this is TOMOYO 2.5. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- MAINTAINERS | 2 +- security/tomoyo/Makefile | 2 +- security/tomoyo/common.c | 12 ++++++------ security/tomoyo/common.h | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'security/tomoyo/common.c') diff --git a/MAINTAINERS b/MAINTAINERS index 02a60b8e503..a790022055c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6443,7 +6443,7 @@ L: tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for users in English) L: tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese) L: tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese) W: http://tomoyo.sourceforge.jp/ -T: quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.4.x/tomoyo-lsm/patches/ +T: quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.5.x/tomoyo-lsm/patches/ S: Maintained F: security/tomoyo/ diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index fc2a8ce4030..56a0c7be409 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile @@ -27,7 +27,7 @@ $(obj)/policy/stat.conf: @touch $@ $(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 - @echo Generating built-in policy for TOMOYO 2.4.x. + @echo Generating built-in policy for TOMOYO 2.5.x. @echo "static char tomoyo_builtin_profile[] __initdata =" > $@.tmp @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/profile.conf >> $@.tmp @echo "\"\";" >> $@.tmp diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 1fd0fc1059b..084018351b4 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -345,7 +345,7 @@ void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns) INIT_LIST_HEAD(&ns->group_list[idx]); for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++) INIT_LIST_HEAD(&ns->policy_list[idx]); - ns->profile_version = 20100903; + ns->profile_version = 20110903; tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list); list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list); } @@ -2222,7 +2222,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head) static void tomoyo_read_version(struct tomoyo_io_buffer *head) { if (!head->r.eof) { - tomoyo_io_printf(head, "2.4.0"); + tomoyo_io_printf(head, "2.5.0"); head->r.eof = true; } } @@ -2694,11 +2694,11 @@ void tomoyo_check_profile(void) struct tomoyo_domain_info *domain; const int idx = tomoyo_read_lock(); tomoyo_policy_loaded = true; - printk(KERN_INFO "TOMOYO: 2.4.0\n"); + printk(KERN_INFO "TOMOYO: 2.5.0\n"); list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { const u8 profile = domain->profile; const struct tomoyo_policy_namespace *ns = domain->ns; - if (ns->profile_version != 20100903) + if (ns->profile_version != 20110903) printk(KERN_ERR "Profile version %u is not supported.\n", ns->profile_version); @@ -2709,9 +2709,9 @@ void tomoyo_check_profile(void) else continue; printk(KERN_ERR - "Userland tools for TOMOYO 2.4 must be installed and " + "Userland tools for TOMOYO 2.5 must be installed and " "policy must be initialized.\n"); - printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.4/ " + printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.5/ " "for more information.\n"); panic("STOP!"); } diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index af82683df7f..471c9f9afc1 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -3,7 +3,7 @@ * * Header file for TOMOYO. * - * Copyright (C) 2005-2010 NTT DATA CORPORATION + * Copyright (C) 2005-2011 NTT DATA CORPORATION */ #ifndef _SECURITY_TOMOYO_COMMON_H @@ -901,7 +901,7 @@ struct tomoyo_policy_namespace { struct list_head acl_group[TOMOYO_MAX_ACL_GROUPS]; /* List for connecting to tomoyo_namespace_list list. */ struct list_head namespace_list; - /* Profile version. Currently only 20100903 is defined. */ + /* Profile version. Currently only 20110903 is defined. */ unsigned int profile_version; /* Name of this namespace (e.g. "", "" ). */ const char *name; -- cgit v1.2.3-70-g09d2 From 6bce98edc3365a8f780ff3944ac7992544c194fe Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 16 Sep 2011 22:54:25 +0900 Subject: TOMOYO: Allow specifying domain transition preference. I got an opinion that it is difficult to use exception policy's domain transition control directives because they need to match the pathname specified to "file execute" directives. For example, if "file execute /bin/\*\-ls\-cat" is given, corresponding domain transition control directive needs to be like "no_keep_domain /bin/\*\-ls\-cat from any". If we can specify like below, it will become more convenient. file execute /bin/ls keep exec.realpath="/bin/ls" exec.argv[0]="ls" file execute /bin/cat keep exec.realpath="/bin/cat" exec.argv[0]="cat" file execute /bin/\*\-ls\-cat child file execute /usr/sbin/httpd exec.realpath="/usr/sbin/httpd" exec.argv[0]="/usr/sbin/httpd" In above examples, "keep" works as if keep_domain is specified, "child" works as if "no_reset_domain" and "no_initialize_domain" and "no_keep_domain" are specified, "" causes domain transition to domain upon successful execve() operation. Moreover, we can also allow transition to different domains based on conditions like below example. /usr/sbin/sshd file execute /bin/bash /usr/sbin/sshd //batch-session exec.argc=2 exec.argv[1]="-c" file execute /bin/bash /usr/sbin/sshd //root-session task.uid=0 file execute /bin/bash /usr/sbin/sshd //nonroot-session task.uid!=0 Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.c | 4 ++++ security/tomoyo/common.h | 4 ++++ security/tomoyo/condition.c | 50 +++++++++++++++++++++++++++++++++++++++--- security/tomoyo/domain.c | 53 ++++++++++++++++++++++++++++++++++++++++++--- security/tomoyo/file.c | 38 +++++++++++++++++++++++++++----- 5 files changed, 137 insertions(+), 12 deletions(-) (limited to 'security/tomoyo/common.c') diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 084018351b4..0994948f3ed 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -1203,6 +1203,10 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head, case 0: head->r.cond_index = 0; head->r.cond_step++; + if (cond->transit) { + tomoyo_set_space(head); + tomoyo_set_string(head, cond->transit->name); + } /* fall through */ case 1: { diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 471c9f9afc1..a2bc33fc60b 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -615,6 +615,7 @@ struct tomoyo_execve { struct tomoyo_request_info r; struct tomoyo_obj_info obj; struct linux_binprm *bprm; + const struct tomoyo_path_info *transition; /* For dumping argv[] and envp[]. */ struct tomoyo_page_dump dump; /* For temporary use. */ @@ -650,6 +651,7 @@ struct tomoyo_condition { u16 argc; /* Number of "struct tomoyo_argv". */ u16 envc; /* Number of "struct tomoyo_envp". */ u8 grant_log; /* One of values in "enum tomoyo_grant_log". */ + const struct tomoyo_path_info *transit; /* Maybe NULL. */ /* * struct tomoyo_condition_element condition[condc]; * struct tomoyo_number_union values[numbers_count]; @@ -956,6 +958,8 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, struct path *path, const int flag); int tomoyo_close_control(struct tomoyo_io_buffer *head); int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env); +int tomoyo_execute_permission(struct tomoyo_request_info *r, + const struct tomoyo_path_info *filename); int tomoyo_find_next_domain(struct linux_binprm *bprm); int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, const u8 index); diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c index 3a05eb3e2a6..b854959c0fd 100644 --- a/security/tomoyo/condition.c +++ b/security/tomoyo/condition.c @@ -348,7 +348,7 @@ static inline bool tomoyo_same_condition(const struct tomoyo_condition *a, a->numbers_count == b->numbers_count && a->names_count == b->names_count && a->argc == b->argc && a->envc == b->envc && - a->grant_log == b->grant_log && + a->grant_log == b->grant_log && a->transit == b->transit && !memcmp(a + 1, b + 1, a->size - sizeof(*a)); } @@ -428,6 +428,46 @@ out: return entry; } +/** + * tomoyo_get_transit_preference - Parse domain transition preference for execve(). + * + * @param: Pointer to "struct tomoyo_acl_param". + * @e: Pointer to "struct tomoyo_condition". + * + * Returns the condition string part. + */ +static char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param, + struct tomoyo_condition *e) +{ + char * const pos = param->data; + bool flag; + if (*pos == '<') { + e->transit = tomoyo_get_domainname(param); + goto done; + } + { + char *cp = strchr(pos, ' '); + if (cp) + *cp = '\0'; + flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") || + !strcmp(pos, "initialize") || !strcmp(pos, "reset") || + !strcmp(pos, "child") || !strcmp(pos, "parent"); + if (cp) + *cp = ' '; + } + if (!flag) + return pos; + e->transit = tomoyo_get_name(tomoyo_read_token(param)); +done: + if (e->transit) + return param->data; + /* + * Return a bad read-only condition string that will let + * tomoyo_get_condition() return NULL. + */ + return "/"; +} + /** * tomoyo_get_condition - Parse condition part. * @@ -444,7 +484,8 @@ struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param) struct tomoyo_argv *argv = NULL; struct tomoyo_envp *envp = NULL; struct tomoyo_condition e = { }; - char * const start_of_string = param->data; + char * const start_of_string = + tomoyo_get_transit_preference(param, &e); char * const end_of_string = start_of_string + strlen(start_of_string); char *pos; rerun: @@ -608,8 +649,9 @@ store_value: + e.envc * sizeof(struct tomoyo_envp); entry = kzalloc(e.size, GFP_NOFS); if (!entry) - return NULL; + goto out2; *entry = e; + e.transit = NULL; condp = (struct tomoyo_condition_element *) (entry + 1); numbers_p = (struct tomoyo_number_union *) (condp + e.condc); names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count); @@ -636,6 +678,8 @@ out: tomoyo_del_condition(&entry->head.list); kfree(entry); } +out2: + tomoyo_put_name(e.transit); return NULL; } diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index a1fc6b5f612..860390ee1fb 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -102,6 +102,15 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, new_entry->cond = tomoyo_get_condition(param); if (!new_entry->cond) return -EINVAL; + /* + * Domain transition preference is allowed for only + * "file execute" entries. + */ + if (new_entry->cond->transit && + !(new_entry->type == TOMOYO_TYPE_PATH_ACL && + container_of(new_entry, struct tomoyo_path_acl, head) + ->perm == 1 << TOMOYO_TYPE_EXECUTE)) + goto out; } if (mutex_lock_interruptible(&tomoyo_policy_lock)) goto out; @@ -707,8 +716,7 @@ retry: } /* Check execute permission. */ - retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE, - candidate); + retval = tomoyo_execute_permission(&ee->r, candidate); if (retval == TOMOYO_RETRY_REQUEST) goto retry; if (retval < 0) @@ -722,10 +730,45 @@ retry: if (ee->r.param.path.matched_path) candidate = ee->r.param.path.matched_path; - /* Calculate domain to transit to. */ + /* + * Check for domain transition preference if "file execute" matched. + * If preference is given, make do_execve() fail if domain transition + * has failed, for domain transition preference should be used with + * destination domain defined. + */ + if (ee->transition) { + const char *domainname = ee->transition->name; + reject_on_transition_failure = true; + if (!strcmp(domainname, "keep")) + goto force_keep_domain; + if (!strcmp(domainname, "child")) + goto force_child_domain; + if (!strcmp(domainname, "reset")) + goto force_reset_domain; + if (!strcmp(domainname, "initialize")) + goto force_initialize_domain; + if (!strcmp(domainname, "parent")) { + char *cp; + strncpy(ee->tmp, old_domain->domainname->name, + TOMOYO_EXEC_TMPSIZE - 1); + cp = strrchr(ee->tmp, ' '); + if (cp) + *cp = '\0'; + } else if (*domainname == '<') + strncpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE - 1); + else + snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", + old_domain->domainname->name, domainname); + goto force_jump_domain; + } + /* + * No domain transition preference specified. + * Calculate domain to transit to. + */ switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname, candidate)) { case TOMOYO_TRANSITION_CONTROL_RESET: +force_reset_domain: /* Transit to the root of specified namespace. */ snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", candidate->name); @@ -736,11 +779,13 @@ retry: reject_on_transition_failure = true; break; case TOMOYO_TRANSITION_CONTROL_INITIALIZE: +force_initialize_domain: /* Transit to the child of current namespace's root. */ snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", old_domain->ns->name, candidate->name); break; case TOMOYO_TRANSITION_CONTROL_KEEP: +force_keep_domain: /* Keep current domain. */ domain = old_domain; break; @@ -756,11 +801,13 @@ retry: domain = old_domain; break; } +force_child_domain: /* Normal domain transition. */ snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", old_domain->domainname->name, candidate->name); break; } +force_jump_domain: if (!domain) domain = tomoyo_assign_domain(ee->tmp, true); if (domain) diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 743c35f5084..b280c1bd652 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -570,15 +570,41 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, do { tomoyo_check_acl(r, tomoyo_check_path_acl); error = tomoyo_audit_path_log(r); - /* - * Do not retry for execute request, for alias may have - * changed. - */ - } while (error == TOMOYO_RETRY_REQUEST && - operation != TOMOYO_TYPE_EXECUTE); + } while (error == TOMOYO_RETRY_REQUEST); return error; } +/** + * tomoyo_execute_permission - Check permission for execute operation. + * + * @r: Pointer to "struct tomoyo_request_info". + * @filename: Filename to check. + * + * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). + */ +int tomoyo_execute_permission(struct tomoyo_request_info *r, + const struct tomoyo_path_info *filename) +{ + /* + * Unlike other permission checks, this check is done regardless of + * profile mode settings in order to check for domain transition + * preference. + */ + r->type = TOMOYO_MAC_FILE_EXECUTE; + r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type); + r->param_type = TOMOYO_TYPE_PATH_ACL; + r->param.path.filename = filename; + r->param.path.operation = TOMOYO_TYPE_EXECUTE; + tomoyo_check_acl(r, tomoyo_check_path_acl); + r->ee->transition = r->matched_acl && r->matched_acl->cond ? + r->matched_acl->cond->transit : NULL; + if (r->mode != TOMOYO_CONFIG_DISABLED) + return tomoyo_audit_path_log(r); + return 0; +} + /** * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry. * -- cgit v1.2.3-70-g09d2 From 778c4a4d60d932c1df6d270dcbc88365823c3963 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sun, 25 Sep 2011 17:49:09 +0900 Subject: TOMOYO: Fix make namespacecheck warnings. Commit efe836ab "TOMOYO: Add built-in policy support." introduced tomoyo_load_builtin_policy() but was by error called from nowhere. Commit b22b8b9f "TOMOYO: Rename meminfo to stat and show more statistics." introduced tomoyo_update_stat() but was by error not called from tomoyo_assign_domain(). Also, mark tomoyo_io_printf() and tomoyo_path_permission() static functions, as reported by "make namespacecheck". Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.c | 6 +++++- security/tomoyo/common.h | 4 ---- security/tomoyo/domain.c | 1 + security/tomoyo/file.c | 4 ++-- security/tomoyo/securityfs_if.c | 1 + 5 files changed, 9 insertions(+), 7 deletions(-) (limited to 'security/tomoyo/common.c') diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 0994948f3ed..2e2802060ee 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -262,13 +262,17 @@ static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string) WARN_ON(1); } +static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, + ...) __printf(2, 3); + /** * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure. * * @head: Pointer to "struct tomoyo_io_buffer". * @fmt: The printf()'s format string, followed by parameters. */ -void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) +static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, + ...) { va_list args; size_t len; diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index a2bc33fc60b..1a19ad3e67e 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -978,8 +978,6 @@ int tomoyo_path_number_perm(const u8 operation, struct path *path, unsigned long number); int tomoyo_path_perm(const u8 operation, struct path *path, const char *target); -int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, - const struct tomoyo_path_info *filename); int tomoyo_poll_control(struct file *file, poll_table *wait); int tomoyo_poll_log(struct file *file, poll_table *wait); int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr, @@ -1041,8 +1039,6 @@ void tomoyo_del_condition(struct list_head *element); void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); void tomoyo_get_attributes(struct tomoyo_obj_info *obj); void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns); -void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) - __printf(2, 3); void tomoyo_load_policy(const char *filename); void tomoyo_memory_free(void *ptr); void tomoyo_normalize_line(unsigned char *buffer); diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 860390ee1fb..70acf7aebbd 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -567,6 +567,7 @@ out: tomoyo_write_log(&r, "use_profile %u\n", entry->profile); tomoyo_write_log(&r, "use_group %u\n", entry->group); + tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); } } return entry; diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index b280c1bd652..40039079074 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -555,8 +555,8 @@ static int tomoyo_update_path2_acl(const u8 perm, * * Caller holds tomoyo_read_lock(). */ -int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, - const struct tomoyo_path_info *filename) +static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, + const struct tomoyo_path_info *filename) { int error; diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c index d08296a4882..2672ac4f3be 100644 --- a/security/tomoyo/securityfs_if.c +++ b/security/tomoyo/securityfs_if.c @@ -265,6 +265,7 @@ static int __init tomoyo_initerface_init(void) TOMOYO_VERSION); securityfs_create_file("self_domain", 0666, tomoyo_dir, NULL, &tomoyo_self_operations); + tomoyo_load_builtin_policy(); return 0; } -- cgit v1.2.3-70-g09d2 From e2b8b25a6795488eba7bb757706b3ac725c31fac Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 11 Oct 2011 14:05:08 +0900 Subject: TOMOYO: Remove redundant tasklist_lock. rcu_read_lock() is sufficient for calling find_task_by_pid_ns()/find_task_by_vpid(). Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'security/tomoyo/common.c') diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 2e2802060ee..365f3bddee7 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -984,14 +984,12 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head, (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { struct task_struct *p; rcu_read_lock(); - read_lock(&tasklist_lock); if (global_pid) p = find_task_by_pid_ns(pid, &init_pid_ns); else p = find_task_by_vpid(pid); if (p) domain = tomoyo_real_domain(p); - read_unlock(&tasklist_lock); rcu_read_unlock(); } else if (!strncmp(data, "domain=", 7)) { if (tomoyo_domain_def(data + 7)) @@ -1664,14 +1662,12 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head) global_pid = true; pid = (unsigned int) simple_strtoul(buf, NULL, 10); rcu_read_lock(); - read_lock(&tasklist_lock); if (global_pid) p = find_task_by_pid_ns(pid, &init_pid_ns); else p = find_task_by_vpid(pid); if (p) domain = tomoyo_real_domain(p); - read_unlock(&tasklist_lock); rcu_read_unlock(); if (!domain) return; -- cgit v1.2.3-70-g09d2 From 6afcb3b7393f5aa388a0d077c490ed411ab3cd27 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sun, 16 Oct 2011 09:43:46 +0900 Subject: TOMOYO: Fix unused kernel config option. CONFIG_SECURITY_TOMOYO_MAX_{ACCEPT_ENTRY,AUDIT_LOG} introduced by commit 0e4ae0e0 "TOMOYO: Make several options configurable." were by error not used. Reported-by: Paul Bolle Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'security/tomoyo/common.c') diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 365f3bddee7..96b7233a0df 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -502,8 +502,10 @@ static struct tomoyo_profile *tomoyo_assign_profile TOMOYO_CONFIG_WANT_REJECT_LOG; memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT, sizeof(ptr->config)); - ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 1024; - ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048; + ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = + CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG; + ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = + CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY; mb(); /* Avoid out-of-order execution. */ ns->profile_ptr[profile] = ptr; entry = NULL; -- cgit v1.2.3-70-g09d2 From e0b057b406a33501a656dc8d67ea945d7bcdad61 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 21 Oct 2011 12:37:13 +0900 Subject: TOMOYO: Fix incomplete read after seek. Commit f23571e8 "TOMOYO: Copy directly to userspace buffer." introduced tomoyo_flush() that flushes data to be read as soon as possible. tomoyo_select_domain() (which is called by write()) enqueues data which meant to be read by next read(), but previous read()'s read buffer's size was not cleared. As a result, since 2.6.36, sequence like char *cp = "select global-pid=1\n"; read(fd, buf1, sizeof(buf1)); write(fd, cp, strlen(cp)); read(fd, buf2, sizeof(buf2)); causes enqueued data to be flushed to buf1 rather than buf2. Fix this bug by clearing read buffer's size upon write() request. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.c | 1 + 1 file changed, 1 insertion(+) (limited to 'security/tomoyo/common.c') diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 96b7233a0df..d41900de8a6 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -2591,6 +2591,7 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, return -EFAULT; if (mutex_lock_interruptible(&head->io_sem)) return -EINTR; + head->read_user_buf_avail = 0; idx = tomoyo_read_lock(); /* Read a line and dispatch it to the policy handler. */ while (avail_len > 0) { -- cgit v1.2.3-70-g09d2