From: Kentaro Takeda <k.takeda26@gmail.com>
To: linux-kernel@vger.kernel.org,
linux-security-module@vger.kernel.org, chrisw@sous-sol.org
Subject: [TOMOYO 10/15] Networking access control functions.
Date: Fri, 24 Aug 2007 21:54:31 +0900 [thread overview]
Message-ID: <46CED507.8010203@gmail.com> (raw)
In-Reply-To: <46CED214.6050505@gmail.com>
Network access control functions for TOMOYO Linux.
TOMOYO Linux checks permission by the following four parameters.
* protocol type (TCP, UDP, RAW)
* access type (bind, listen, connect, accept)
* IP address (Both IPv4 and IPv6 are available)
* port number
In order to check 'TCP accept' and 'UDP accept'(recv),
LSM expansion patch ([TOMOYO /]) is needed.
Each permission can be automatically accumulated into
the policy of each domain using 'learning mode'.
Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
security/tomoyo/net.c | 983 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 983 insertions(+)
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/security/tomoyo/net.c 2007-08-24 15:51:37.000000000 +0900
@@ -0,0 +1,983 @@
+/*
+ * security/tomoyo/net.c
+ *
+ * Network access control functions for TOMOYO Linux.
+ */
+
+#include "tomoyo.h"
+#include "realpath.h"
+#include <net/ip.h>
+
+/************************* AUDIT FUNCTIONS *************************/
+
+static int tmy_audit_network_log(const int is_ipv6,
+ const char *operation,
+ const u32 *address,
+ const u16 port,
+ const int is_granted,
+ const int is_enforce)
+{
+ char *buf;
+ int len = 256;
+
+ if (is_granted) {
+ if (!tmy_audit_grant())
+ return 0;
+ } else {
+ if (!tmy_audit_reject())
+ return 0;
+ }
+
+ buf = tmy_init_audit_log(&len);
+ if (!buf)
+ return -ENOMEM;
+
+ snprintf(buf + strlen(buf), len - strlen(buf) - 1,
+ TMY_ALLOW_NETWORK "%s ", operation);
+
+ if (is_ipv6)
+ tmy_print_ipv6(buf + strlen(buf), len - strlen(buf),
+ (const u16 *) address);
+ else {
+ u32 ip = *address;
+ snprintf(buf + strlen(buf), len - strlen(buf) - 1,
+ NIPQUAD_FMT, NIPQUAD(ip));
+ }
+
+ snprintf(buf + strlen(buf), len - strlen(buf) - 1, " %u", port);
+
+ return tmy_write_audit_log(buf, is_granted, is_enforce);
+}
+
+/************************* ADDRESS GROUP HANDLER *************************/
+
+/* List of address group. */
+static struct addr_group_entry *group_list;
+
+static int tmy_add_addr_group_entry(const char *group_name,
+ const u8 is_ipv6,
+ const u16 *min_address,
+ const u16 *max_address,
+ const int is_delete)
+{
+ static DECLARE_MUTEX(lock);
+ struct addr_group_entry *new_group;
+ struct addr_group_entry *group;
+ struct addr_group_member *new_member;
+ struct addr_group_member *member;
+ const struct path_info *saved_group_name;
+ int error = -ENOMEM;
+
+ if (!tmy_correct_path(group_name, 0, 0, 0, __FUNCTION__) ||
+ !group_name[0])
+ return -EINVAL;
+
+ saved_group_name = tmy_save_name(group_name);
+ if (!saved_group_name)
+ return -ENOMEM;
+
+ down(&lock);
+
+ for (group = group_list; group; group = group->next) {
+
+ if (saved_group_name != group->group_name)
+ continue;
+
+ for (member = group->first_member;
+ member;
+ member = member->next) {
+
+ if (member->is_ipv6 != is_ipv6)
+ continue;
+
+ if (is_ipv6) {
+ if (memcmp(member->min.ipv6, min_address, 16) ||
+ memcmp(member->max.ipv6, max_address, 16))
+ continue;
+ } else {
+ if (member->min.ipv4 != * (u32 *) min_address ||
+ member->max.ipv4 != * (u32 *) max_address)
+ continue;
+ }
+
+ member->is_deleted = is_delete;
+ error = 0;
+ goto out;
+ }
+ break;
+ }
+
+ if (is_delete) {
+ error = -ENOENT;
+ goto out;
+ }
+
+ if (!group) {
+ new_group = tmy_alloc_element(sizeof(*new_group));
+ if (!new_group)
+ goto out;
+ new_group->group_name = saved_group_name;
+ mb(); /* Instead of using spinlock. */
+ group = group_list;
+ if (group) {
+ while (group->next)
+ group = group->next;
+ group->next = new_group;
+ } else
+ group_list = new_group;
+ group = new_group;
+ }
+
+ new_member = tmy_alloc_element(sizeof(*new_member));
+ if (!new_member)
+ goto out;
+
+ new_member->is_ipv6 = is_ipv6;
+
+ if (is_ipv6) {
+ memmove(new_member->min.ipv6, min_address, 16);
+ memmove(new_member->max.ipv6, max_address, 16);
+ } else {
+ new_member->min.ipv4 = * (u32 *) min_address;
+ new_member->max.ipv4 = * (u32 *) max_address;
+ }
+
+ mb(); /* Instead of using spinlock. */
+
+ member = group->first_member;
+ if (member) {
+ while (member->next)
+ member = member->next;
+ member->next = new_member;
+ } else
+ group->first_member = new_member;
+
+ error = 0;
+out: ;
+ up(&lock);
+
+ return error;
+}
+
+/**
+ * tmy_add_addr_group_policy - add or delete address group policy.
+ * @data: a line to parse.
+ * @is_delete: is this delete request?
+ *
+ * Returns zero on success.
+ * Returns nonzero on failure.
+ */
+int tmy_add_addr_group_policy(char *data, const int is_delete)
+{
+ int count;
+ int is_ipv6;
+ u16 min_address[8];
+ u16 max_address[8];
+ unsigned int min[8];
+ unsigned int max[8];
+ char *cp = strchr(data, ' ');
+
+ if (!cp)
+ return -EINVAL;
+
+ *cp++ = '\0';
+ count = sscanf(cp,
+ NIP6_FMT "-" NIP6_FMT,
+ &min[0], &min[1], &min[2], &min[3],
+ &min[4], &min[5], &min[6], &min[7],
+ &max[0], &max[1], &max[2], &max[3],
+ &max[4], &max[5], &max[6], &max[7]);
+
+ if (count == 8 || count == 16) {
+
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ min_address[i] = htons((u16) min[i]);
+ max_address[i] = htons((u16) max[i]);
+ }
+ if (count == 8)
+ memmove(max_address, min_address, sizeof(min_address));
+ is_ipv6 = 1;
+
+ goto ok;
+
+ }
+
+ count = sscanf(cp,
+ NIPQUAD_FMT "-" NIPQUAD_FMT,
+ &min[0], &min[1],
+ &min[2], &min[3],
+ &max[0], &max[1],
+ &max[2], &max[3]);
+
+ if (count == 4 || count == 8) {
+ u32 ip = ((((u8) min[0]) << 24) +
+ (((u8) min[1]) << 16) +
+ (((u8) min[2]) << 8) +
+ (u8) min[3]);
+
+ * (u32 *) min_address = ip;
+
+ if (count == 8)
+ ip = ((((u8) max[0]) << 24) +
+ (((u8) max[1]) << 16) +
+ (((u8) max[2]) << 8) +
+ (u8) max[3]);
+
+ * (u32 *) max_address = ip;
+ is_ipv6 = 0;
+
+ goto ok;
+
+ }
+
+ return -EINVAL;
+
+ok: ;
+ return tmy_add_addr_group_entry(data, is_ipv6, min_address, max_address,
+ is_delete);
+}
+
+static struct addr_group_entry *tmy_new_addr_group(const char *name)
+{
+ int i;
+ struct addr_group_entry *group;
+
+ for (i = 0; i <= 1; i++) {
+ for (group = group_list; group; group = group->next) {
+
+ if (strcmp(name, group->group_name->name) == 0)
+ return group;
+
+ }
+
+ if (i == 0) {
+ /*
+ * Add a dummy entry to create new address group
+ * and delete that entry.
+ */
+ const u16 dum[2] = { 0, 0 };
+ tmy_add_addr_group_entry(name, 0, dum, dum, 0);
+ tmy_add_addr_group_entry(name, 0, dum, dum, 1);
+ }
+ }
+
+ return NULL;
+}
+
+static int tmy_address_match_group(const u8 is_ipv6,
+ const u32 *address,
+ const struct addr_group_entry *group)
+{
+ struct addr_group_member *member;
+ const u32 ip = ntohl(*address);
+
+ for (member = group->first_member; member; member = member->next) {
+
+ if (member->is_deleted)
+ continue;
+
+ if (member->is_ipv6) {
+
+ if (is_ipv6 &&
+ memcmp(member->min.ipv6, address, 16) <= 0 &&
+ memcmp(address, member->max.ipv6, 16) <= 0)
+ return 1;
+
+ } else {
+
+ if (!is_ipv6 &&
+ member->min.ipv4 <= ip &&
+ ip <= member->max.ipv4)
+ return 1;
+
+ }
+ }
+
+ return 0;
+}
+
+static int tmy_read_addr_group(struct io_buffer *head,
+ struct addr_group_entry *group,
+ struct addr_group_member *member)
+{
+ char buf[128];
+ if (!member)
+ return 0;
+
+ if (member->is_ipv6) {
+
+ const u16 *min_addr = member->min.ipv6;
+ const u16 *max_addr = member->max.ipv6;
+
+ tmy_print_ipv6(buf, sizeof(buf), min_addr);
+
+ if (memcmp(min_addr, max_addr, 16)) {
+ char *cp = strchr(buf, '\0');
+ int len = sizeof(buf) - strlen(buf);
+
+ *cp++ = '-';
+ tmy_print_ipv6(cp, len, max_addr);
+ }
+
+ } else {
+
+ const u32 min_addr = member->min.ipv4;
+ const u32 max_addr = member->max.ipv4;
+
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf) - 1,
+ NIPQUAD_FMT, HIPQUAD(min_addr));
+
+ if (min_addr != max_addr) {
+ const int len = strlen(buf);
+
+ snprintf(buf + len, sizeof(buf) - 1 - len,
+ "-" NIPQUAD_FMT, HIPQUAD(max_addr));
+ }
+
+ }
+
+ return tmy_io_printf(head, TMY_ADDRESS_GROUP "%s %s\n",
+ group->group_name->name, buf);
+}
+
+/**
+ * tmy_read_addr_group_policy - read address group policy
+ * @head: pointer to "struct io_buffer".
+ *
+ * Returns nonzero if reading incomplete.
+ * Returns zero otherwise.
+ */
+int tmy_read_addr_group_policy(struct io_buffer *head)
+{
+ struct addr_group_entry *group = head->read_var1;
+ struct addr_group_member *member = head->read_var2;
+
+ if (!group)
+ group = group_list;
+
+ while (group) {
+ head->read_var1 = group;
+ if (!member)
+ member = group->first_member;
+ while (member) {
+
+ head->read_var2 = member;
+ if (member->is_deleted) {
+ member = member->next;
+ continue;
+ }
+
+ if (tmy_read_addr_group(head, group, member))
+ break;
+
+ member = member->next;
+ }
+ if (member)
+ break;
+ head->read_var2 = NULL;
+ group = group->next;
+ }
+ return group ? -ENOMEM : 0;
+}
+
+/*********************** NETWORK NETWORK ACL HANDLER ***********************/
+
+/**
+ * tmy_print_ipv6 - print ipv6 address
+ * @buffer: pointer to buffer to save the result.
+ * @buffer_len: sizeof @buffer .
+ * @ip: pointer to an IPv6 address in network byte order.
+ *
+ * Returns @buffer .
+ */
+char *tmy_print_ipv6(char *buffer, const int buffer_len, const u16 *ip)
+{
+ memset(buffer, 0, buffer_len);
+ snprintf(buffer, buffer_len - 1, NIP6_FMT,
+ ntohs(ip[0]), ntohs(ip[1]), ntohs(ip[2]), ntohs(ip[3]),
+ ntohs(ip[4]), ntohs(ip[5]), ntohs(ip[6]), ntohs(ip[7]));
+ return buffer;
+}
+
+/**
+ * tmy_network2keyword - get keyword from access control index.
+ * @operation: index number.
+ *
+ * Returns keyword that corresponds with @operation .
+ */
+const char *tmy_network2keyword(const unsigned int operation)
+{
+ const char *keyword = "unknown";
+ switch (operation) {
+ case TMY_NETWORK_ACL_UDP_BIND:
+ keyword = "UDP bind";
+ break;
+ case TMY_NETWORK_ACL_UDP_CONNECT:
+ keyword = "UDP connect";
+ break;
+ case TMY_NETWORK_ACL_TCP_BIND:
+ keyword = "TCP bind";
+ break;
+ case TMY_NETWORK_ACL_TCP_LISTEN:
+ keyword = "TCP listen";
+ break;
+ case TMY_NETWORK_ACL_TCP_CONNECT:
+ keyword = "TCP connect";
+ break;
+ case TMY_NETWORK_ACL_TCP_ACCEPT:
+ keyword = "TCP accept";
+ break;
+ case TMY_NETWORK_ACL_RAW_BIND:
+ keyword = "RAW bind";
+ break;
+ case TMY_NETWORK_ACL_RAW_CONNECT:
+ keyword = "RAW connect";
+ break;
+ }
+ return keyword;
+}
+
+/* Compare IPv4/IPv6 address. */
+static int tmy_cmp_network_entry(const u8 record_type,
+ struct net_acl *acl,
+ const struct addr_group_entry *group,
+ const u32 min_ip,
+ const u32 max_ip,
+ const u32 *min_address,
+ const u32 *max_address)
+{
+ int found = 0;
+
+ switch (record_type) {
+
+ case TMY_TYPE_ADDRESS_GROUP:
+ if (acl->u.group == group)
+ found = 1;
+ break;
+
+ case TMY_TYPE_IPv4:
+ if (acl->u.ipv4.min == min_ip &&
+ max_ip == acl->u.ipv4.max)
+ found = 1;
+ break;
+
+ case TMY_TYPE_IPv6:
+ if (memcmp(acl->u.ipv6.min, min_address, 16) == 0 &&
+ memcmp(max_address, acl->u.ipv6.max, 16) == 0)
+ found = 1;
+ break;
+
+ }
+
+ return found;
+}
+
+/*
+ * @is_add: 1 add this entry if not quota exceeded
+ * -1 always add this entry
+ * 0 remove this entry
+ */
+static int tmy_add_network_entry(const u8 operation,
+ const u8 record_type,
+ const struct addr_group_entry *group,
+ const u32 *min_address,
+ const u32 *max_address,
+ const u16 min_port,
+ const u16 max_port,
+ struct domain_info *domain,
+ const struct condition_list *cond,
+ const u8 is_add)
+{
+ struct acl_info *ptr;
+ int error = -ENOMEM;
+ /* using host byte order to allow u32 comparison than memcmp().*/
+ const u32 min_ip = ntohl(*min_address);
+ const u32 max_ip = ntohl(*max_address);
+
+ if (!domain)
+ return -EINVAL;
+
+ down(&domain_acl_lock);
+
+ if (!is_add)
+ goto remove;
+
+ ptr = domain->first_acl_ptr;
+ if (!ptr)
+ goto first_entry;
+
+ while (1) {
+ struct net_acl *acl = (struct net_acl *) ptr;
+
+ if (ptr->type == TMY_TYPE_IP_NETWORK_ACL &&
+ ptr->cond == cond &&
+ acl->operation_type == operation &&
+ acl->record_type == record_type &&
+ acl->min_port == min_port &&
+ max_port == acl->max_port &&
+ tmy_cmp_network_entry(record_type, acl,
+ group, min_ip, max_ip,
+ min_address,
+ max_address)) {
+ ptr->is_deleted = 0;
+ error = 0;
+ break;
+ }
+
+ if (ptr->next) {
+ ptr = ptr->next;
+ continue;
+ }
+first_entry: ;
+ if (is_add == 1 && tmy_too_many_acl(domain))
+ break;
+
+ /* Not found. Append it to the tail. */
+ acl = tmy_alloc_element(sizeof(*acl));
+ if (!acl)
+ break;
+
+ acl->head.type = TMY_TYPE_IP_NETWORK_ACL;
+ acl->head.cond = cond;
+ acl->operation_type = operation;
+ acl->record_type = record_type;
+
+ if (record_type == TMY_TYPE_ADDRESS_GROUP)
+ acl->u.group = group;
+ else if (record_type == TMY_TYPE_IPv4) {
+ acl->u.ipv4.min = min_ip;
+ acl->u.ipv4.max = max_ip;
+ } else {
+ memmove(acl->u.ipv6.min, min_address, 16);
+ memmove(acl->u.ipv6.max, max_address, 16);
+ }
+
+ acl->min_port = min_port;
+ acl->max_port = max_port;
+ error = tmy_add_acl(ptr, domain,
+ (struct acl_info *) acl);
+ break;
+ }
+ goto ok;
+remove: ;
+ error = -ENOENT;
+ for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) {
+ struct net_acl *acl = (struct net_acl *) ptr;
+ if (ptr->type != TMY_TYPE_IP_NETWORK_ACL ||
+ ptr->cond != cond ||
+ ptr->is_deleted ||
+ acl->operation_type != operation ||
+ acl->record_type != record_type ||
+ acl->min_port != min_port ||
+ acl->max_port != max_port ||
+ !tmy_cmp_network_entry(record_type, acl,
+ group, min_ip, max_ip,
+ min_address,
+ max_address))
+ continue;
+
+ error = tmy_del_acl(ptr);
+ break;
+ }
+ok: ;
+ up(&domain_acl_lock);
+
+ return error;
+}
+
+/* Check network permission. */
+static int tmy_network_entry(const int is_ipv6,
+ const int operation,
+ const u32 *address,
+ const u16 port)
+{
+ struct domain_info * const domain = TMY_SECURITY->domain;
+ struct acl_info *ptr;
+ const char *keyword = tmy_network2keyword(operation);
+ const int is_enforce = tmy_enforce(TMY_MAC_FOR_NETWORK);
+ /* using host byte order to allow u32 comparison than memcmp().*/
+ const u32 ip = ntohl(*address);
+
+ if (!tmy_flags(TMY_MAC_FOR_NETWORK))
+ return 0;
+
+ for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) {
+ struct net_acl *acl = (struct net_acl *) ptr;
+
+ if (ptr->type != TMY_TYPE_IP_NETWORK_ACL ||
+ ptr->is_deleted ||
+ acl->operation_type != operation ||
+ port < acl->min_port ||
+ acl->max_port < port ||
+ tmy_check_condition(ptr->cond, NULL))
+ continue;
+
+ if (acl->record_type == TMY_TYPE_ADDRESS_GROUP &&
+ tmy_address_match_group(is_ipv6, address, acl->u.group))
+ break;
+
+ else if (acl->record_type == TMY_TYPE_IPv4 && !is_ipv6 &&
+ (acl->u.ipv4.min <= ip && ip <= acl->u.ipv4.max))
+ break;
+
+ else if (acl->record_type == TMY_TYPE_IPv6 && is_ipv6 &&
+ memcmp(acl->u.ipv6.min, address, 16) <= 0 &&
+ memcmp(address, acl->u.ipv6.max, 16) <= 0)
+ break;
+
+ }
+
+ tmy_audit_network_log(is_ipv6, keyword, address,
+ port, ptr != 0, is_enforce);
+
+ if (ptr)
+ return 0;
+
+ if (is_enforce) {
+
+ if (is_ipv6) {
+
+ char buf[64];
+
+ tmy_print_ipv6(buf, sizeof(buf), (const u16 *) address);
+ return tmy_supervisor("%s\n" TMY_ALLOW_NETWORK
+ "%s %s %u\n",
+ domain->domainname->name, keyword,
+ buf, port);
+
+ }
+
+ return tmy_supervisor("%s\n" TMY_ALLOW_NETWORK
+ "%s " NIPQUAD_FMT " %u\n",
+ domain->domainname->name, keyword,
+ HIPQUAD(ip), port);
+
+ }
+
+ if (tmy_accept(TMY_MAC_FOR_NETWORK))
+ tmy_add_network_entry(operation,
+ is_ipv6 ? TMY_TYPE_IPv6 : TMY_TYPE_IPv4,
+ NULL, address, address,
+ port, port, domain, NULL, 1);
+
+ return 0;
+}
+
+/**
+ * tmy_add_signal_policy - add or delete signal policy.
+ * @data: a line to parse.
+ * @domain: pointer to "struct domain_info".
+ * @cond: pointer to "struct condition_list". May be NULL.
+ * @is_delete: is this delete request?
+ *
+ * Returns zero on success.
+ * Returns nonzero on failure.
+ */
+int tmy_add_network_policy(char *data,
+ struct domain_info *domain,
+ const struct condition_list *cond,
+ const int is_delete)
+{
+ u8 sock_type;
+ u8 operation;
+ u8 record_type;
+ u16 min_address[8];
+ u16 max_address[8];
+ unsigned int min[8];
+ unsigned int max[8];
+ struct addr_group_entry *group = NULL;
+ u16 min_port;
+ u16 max_port;
+ int count;
+ char *cp1 = NULL;
+ char *cp2 = NULL;
+
+ cp1 = strchr(data, ' ');
+ if (!cp1)
+ goto out;
+ cp1++;
+
+ if (strncmp(data, "TCP ", 4) == 0)
+ sock_type = SOCK_STREAM;
+ else if (strncmp(data, "UDP ", 4) == 0)
+ sock_type = SOCK_DGRAM;
+ else if (strncmp(data, "RAW ", 4) == 0)
+ sock_type = SOCK_RAW;
+ else
+ goto out;
+
+ cp2 = strchr(cp1, ' ');
+ if (!cp2)
+ goto out;
+ cp2++;
+
+ if (strncmp(cp1, "bind ", 5) == 0) {
+ switch (sock_type) {
+ case SOCK_STREAM:
+ operation = TMY_NETWORK_ACL_TCP_BIND;
+ break;
+ case SOCK_DGRAM:
+ operation = TMY_NETWORK_ACL_UDP_BIND;
+ break;
+ default:
+ operation = TMY_NETWORK_ACL_RAW_BIND;
+ break;
+ }
+ } else if (strncmp(cp1, "connect ", 8) == 0) {
+ switch (sock_type) {
+ case SOCK_STREAM:
+ operation = TMY_NETWORK_ACL_TCP_CONNECT;
+ break;
+ case SOCK_DGRAM:
+ operation = TMY_NETWORK_ACL_UDP_CONNECT;
+ break;
+ default:
+ operation = TMY_NETWORK_ACL_RAW_CONNECT;
+ break;
+ }
+ } else if (sock_type == SOCK_STREAM &&
+ strncmp(cp1, "listen ", 7) == 0)
+ operation = TMY_NETWORK_ACL_TCP_LISTEN;
+
+ else if (sock_type == SOCK_STREAM &&
+ strncmp(cp1, "accept ", 7) == 0)
+ operation = TMY_NETWORK_ACL_TCP_ACCEPT;
+
+ else
+ goto out;
+
+ cp1 = strchr(cp2, ' ');
+ if (!cp1)
+ goto out;
+ *cp1++ = '\0';
+
+ count = sscanf(cp2,
+ NIP6_FMT "-" NIP6_FMT,
+ &min[0], &min[1], &min[2], &min[3],
+ &min[4], &min[5], &min[6], &min[7],
+ &max[0], &max[1], &max[2], &max[3],
+ &max[4], &max[5], &max[6], &max[7]);
+
+ if (count == 8 || count == 16) {
+
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ min_address[i] = htons((u16) min[i]);
+ max_address[i] = htons((u16) max[i]);
+ }
+
+ if (count == 8)
+ memmove(max_address, min_address, sizeof(min_address));
+ record_type = TMY_TYPE_IPv6;
+
+ goto ok;
+
+ }
+
+ count = sscanf(cp2,
+ NIPQUAD_FMT "-" NIPQUAD_FMT,
+ &min[0], &min[1], &min[2], &min[3],
+ &max[0], &max[1], &max[2], &max[3]);
+
+ if (count == 4 || count == 8) {
+
+ u32 ip = htonl((((u8) min[0]) << 24) +
+ (((u8) min[1]) << 16) +
+ (((u8) min[2]) << 8) +
+ (u8) min[3]);
+ * (u32 *) min_address = ip;
+
+ if (count == 8)
+ ip = htonl((((u8) max[0]) << 24) +
+ (((u8) max[1]) << 16) +
+ (((u8) max[2]) << 8) +
+ (u8) max[3]);
+ * (u32 *) max_address = ip;
+ record_type = TMY_TYPE_IPv4;
+
+ goto ok;
+
+ }
+
+ if (*cp2 == '@') {
+
+ group = tmy_new_addr_group(cp2 + 1);
+ if (!group)
+ return -ENOMEM;
+ record_type = TMY_TYPE_ADDRESS_GROUP;
+
+ goto ok;
+ }
+
+ goto out;
+
+ok: ;
+ if (strchr(cp1, ' '))
+ goto out;
+
+ count = sscanf(cp1, "%hu-%hu", &min_port, &max_port);
+ if (count != 1 && count != 2)
+ goto out;
+
+ if (count == 1)
+ max_port = min_port;
+
+ return tmy_add_network_entry(operation, record_type, group,
+ (u32 *) min_address,
+ (u32 *) max_address,
+ min_port, max_port, domain,
+ cond, is_delete ? 0 : -1);
+
+out: ;
+ return -EINVAL;
+}
+
+/**
+ * tmy_network_listen_acl - check permission for listen(2) operation.
+ * @is_ipv6: is @address an IPv6 address?
+ * @address: pointer to IPv4/IPv6 address in network byte order.
+ * @port: TCP or UDP's port number.
+ *
+ * Returns zero if permission granted.
+ * Returns nonzero if permission denied.
+ */
+int tmy_network_listen_acl(const int is_ipv6,
+ const u8 *address,
+ const u16 port)
+{
+ return tmy_network_entry(is_ipv6,
+ TMY_NETWORK_ACL_TCP_LISTEN,
+ (const u32 *) address,
+ ntohs(port));
+}
+
+/**
+ * tmy_network_connect_acl - check permission for connect(2) operation.
+ * @is_ipv6: is @address an IPv6 address?
+ * @sock_type: socket type (TCP, UDP or IP).
+ * @address: pointer to IPv4/IPv6 address in network byte order.
+ * @port: TCP or UDP's port number or IP's protocol number.
+ *
+ * Returns zero if permission granted.
+ * Returns nonzero if permission denied.
+ */
+int tmy_network_connect_acl(const int is_ipv6,
+ const int sock_type,
+ const u8 *address,
+ const u16 port)
+{
+ int type;
+
+ switch (sock_type) {
+ case SOCK_STREAM:
+ type = TMY_NETWORK_ACL_TCP_CONNECT;
+ break;
+ case SOCK_DGRAM:
+ type = TMY_NETWORK_ACL_UDP_CONNECT;
+ break;
+ default:
+ type = TMY_NETWORK_ACL_RAW_CONNECT;
+ break;
+ }
+
+ return tmy_network_entry(is_ipv6, type,
+ (const u32 *) address, ntohs(port));
+}
+
+/**
+ * tmy_network_bind_acl - check permission for bind(2) operation.
+ * @is_ipv6: is @address an IPv6 address?
+ * @sock_type: socket type (TCP, UDP or IP).
+ * @address: pointer to IPv4/IPv6 address in network byte order.
+ * @port: TCP or UDP's port number or IP's protocol number.
+ *
+ * Returns zero if permission granted.
+ * Returns nonzero if permission denied.
+ */
+int tmy_network_bind_acl(const int is_ipv6,
+ const int sock_type,
+ const u8 *address,
+ const u16 port)
+{
+ int type;
+
+ switch (sock_type) {
+ case SOCK_STREAM:
+ type = TMY_NETWORK_ACL_TCP_BIND;
+ break;
+ case SOCK_DGRAM:
+ type = TMY_NETWORK_ACL_UDP_BIND;
+ break;
+ default:
+ type = TMY_NETWORK_ACL_RAW_BIND;
+ break;
+ }
+
+ return tmy_network_entry(is_ipv6, type,
+ (const u32 *) address, ntohs(port));
+}
+
+/**
+ * tmy_network_sendmsg_acl - check permission for sendmsg(2) operation.
+ * @is_ipv6: is @address an IPv6 address?
+ * @sock_type: socket type (UDP or IP).
+ * @address: pointer to IPv4/IPv6 address in network byte order.
+ * @port: UDP's port number or IP's protocol number.
+ *
+ * Returns zero if permission granted.
+ * Returns nonzero if permission denied.
+ */
+int tmy_network_sendmsg_acl(const int is_ipv6,
+ const int sock_type,
+ const u8 *address,
+ const u16 port)
+{
+ int type;
+
+ if (sock_type == SOCK_DGRAM)
+ type = SOCK_DGRAM;
+ else
+ type = TMY_NETWORK_ACL_RAW_CONNECT;
+
+ return tmy_network_entry(is_ipv6, type,
+ (const u32 *) address, ntohs(port));
+}
+
+/**
+ * tmy_network_accept_acl - check permission for accept(2) operation.
+ * @is_ipv6: is @address an IPv6 address?
+ * @address: pointer to IPv4/IPv6 address in network byte order.
+ * @port: TCP client's port number.
+ *
+ * Returns zero if permission granted.
+ * Returns nonzero if permission denied.
+ */
+int tmy_network_accept_acl(const int is_ipv6, const u8 *address,
+ const u16 port)
+{
+ return tmy_network_entry(is_ipv6, TMY_NETWORK_ACL_TCP_ACCEPT,
+ (const u32 *) address, ntohs(port));
+}
+
+/**
+ * tmy_network_recvmsg_acl - check permission for recvmsg(2) operation.
+ * @is_ipv6: is @address an IPv6 address?
+ * @sock_type: socket type (UDP or IP).
+ * @address: pointer to IPv4/IPv6 address in network byte order.
+ * @port: UDP's port number or IP's protocol number.
+ *
+ * Returns zero if permission granted.
+ * Returns nonzero if permission denied.
+ */
+int tmy_network_recvmsg_acl(const int is_ipv6, const int sock_type,
+ const u8 *address, const u16 port)
+{
+ return tmy_network_entry(is_ipv6, sock_type == SOCK_DGRAM ?
+ TMY_NETWORK_ACL_UDP_CONNECT :
+ TMY_NETWORK_ACL_RAW_CONNECT,
+ (const u32 *) address, ntohs(port));
+}
next prev parent reply other threads:[~2007-08-24 12:54 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-08-24 12:41 [TOMOYO 00/15] TOMOYO Linux - MAC based on process invocation histroy Kentaro Takeda
2007-08-24 12:44 ` [TOMOYO 01/15] Allow use of namespace_sem from LSM module Kentaro Takeda
2007-08-24 12:45 ` [TOMOYO 02/15] Kconfig and Makefile for TOMOYO Linux Kentaro Takeda
2007-08-24 12:50 ` Jiri Kosina
2007-08-24 12:46 ` [TOMOYO 03/15] Data structures and prototypes definition Kentaro Takeda
2007-08-24 12:48 ` [TOMOYO 04/15] Memory and pathname management functions Kentaro Takeda
2007-08-24 12:49 ` [TOMOYO 05/15] Utility functions and /proc interface for policy manipulation Kentaro Takeda
2007-08-24 12:50 ` [TOMOYO 06/15] Domain transition handler functions Kentaro Takeda
2007-08-24 12:52 ` [TOMOYO 07/15] Auditing interface Kentaro Takeda
2007-08-24 12:53 ` [TOMOYO 08/15] File access control functions Kentaro Takeda
2007-08-24 12:53 ` [TOMOYO 09/15] Argv[0] " Kentaro Takeda
2007-08-24 12:54 ` Kentaro Takeda [this message]
2007-08-24 12:55 ` [TOMOYO 11/15] Namespace manipulation " Kentaro Takeda
2007-08-24 12:56 ` [TOMOYO 12/15] Signal transmission " Kentaro Takeda
2007-08-24 12:56 ` [TOMOYO 13/15] LSM adapter for TOMOYO Kentaro Takeda
2007-08-24 12:57 ` [TOMOYO 14/15] Conditional permission support Kentaro Takeda
2007-08-25 11:08 ` Pavel Machek
2007-08-25 22:46 ` Toshiharu Harada
2007-08-26 2:13 ` Tetsuo Handa
2007-08-27 12:11 ` Kyle Moffett
2007-08-28 13:00 ` Tetsuo Handa
2007-08-24 12:58 ` [TOMOYO 15/15] LSM expansion for TOMOYO Linux Kentaro Takeda
2007-08-27 14:49 ` Paul Moore
2007-08-28 10:39 ` Tetsuo Handa
2007-08-28 13:21 ` Paul Moore
2007-09-03 13:15 ` Tetsuo Handa
2007-09-04 11:53 ` Paul Moore
2007-09-04 14:02 ` Tetsuo Handa
2007-09-04 14:13 ` Kyle Moffett
2007-09-05 14:06 ` Paul Moore
2007-09-06 13:04 ` Tetsuo Handa
2007-09-06 15:25 ` Paul Moore
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=46CED507.8010203@gmail.com \
--to=k.takeda26@gmail.com \
--cc=chrisw@sous-sol.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.