[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <200904151951.GEI34847.OLVFJFMtHSOFOQ@I-love.SAKURA.ne.jp>
Date: Wed, 15 Apr 2009 19:51:39 +0900
From: Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>
To: paul.moore@...com
Cc: linux-security-module@...r.kernel.org, netdev@...r.kernel.org
Subject: [PATCH 2/2] tomoyo: Add network access control support.
Subject: tomoyo: Add network access control support.
TOMOYO checks permissions for below IPv4/IPv6 network operations.
Binding TCP/UDP/RAW sockets.
Listening TCP sockets.
Accepting TCP sockets.
Connecting TCP/UDP/RAW sockets.
Sending UDP/RAW packets.
Receiving UDP/RAW packets.
TOMOYO uses security_socket_post_accept() and
security_socket_post_recv_datagram() in order to implement a packet filtering
with interactive enforcement. (Interactive enforcement is not implemented yet.)
Signed-off-by: Kentaro Takeda <takedakn@...data.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>
Signed-off-by: Toshiharu Harada <haradats@...data.co.jp>
---
security/tomoyo/Kconfig | 1
security/tomoyo/Makefile | 2
security/tomoyo/common.c | 118 +++++
security/tomoyo/common.h | 68 +++
security/tomoyo/network.c | 930 ++++++++++++++++++++++++++++++++++++++++++++++
security/tomoyo/tomoyo.c | 46 ++
security/tomoyo/tomoyo.h | 17
7 files changed, 1178 insertions(+), 4 deletions(-)
--- security-testing-2.6.git.orig/security/tomoyo/Kconfig
+++ security-testing-2.6.git/security/tomoyo/Kconfig
@@ -3,6 +3,7 @@ config SECURITY_TOMOYO
depends on SECURITY
select SECURITYFS
select SECURITY_PATH
+ select SECURITY_NETWORK
default n
help
This selects TOMOYO Linux, pathname-based access control.
--- security-testing-2.6.git.orig/security/tomoyo/Makefile
+++ security-testing-2.6.git/security/tomoyo/Makefile
@@ -1 +1 @@
-obj-y = common.o realpath.o tomoyo.o domain.o file.o
+obj-y = common.o realpath.o tomoyo.o domain.o file.o network.o
--- security-testing-2.6.git.orig/security/tomoyo/common.c
+++ security-testing-2.6.git/security/tomoyo/common.c
@@ -12,6 +12,7 @@
#include <linux/uaccess.h>
#include <linux/security.h>
#include <linux/hardirq.h>
+#include <linux/kernel.h>
#include "realpath.h"
#include "common.h"
#include "tomoyo.h"
@@ -35,6 +36,7 @@ static struct {
const unsigned int max_value;
} tomoyo_control_array[TOMOYO_MAX_CONTROL_INDEX] = {
[TOMOYO_MAC_FOR_FILE] = { "MAC_FOR_FILE", 0, 3 },
+ [TOMOYO_MAC_FOR_NETWORK] = { "MAC_FOR_NETWORK", 0, 3 },
[TOMOYO_MAX_ACCEPT_ENTRY] = { "MAX_ACCEPT_ENTRY", 2048, INT_MAX },
[TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 },
};
@@ -836,6 +838,9 @@ bool tomoyo_domain_quota_is_ok(struct to
if (perm & (1 << TOMOYO_TYPE_RENAME_ACL))
count++;
break;
+ case TOMOYO_TYPE_IP_NETWORK_ACL:
+ count++;
+ break;
}
}
up_read(&tomoyo_domain_acl_info_list_lock);
@@ -1290,6 +1295,8 @@ static int tomoyo_write_domain_policy(st
TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ);
return 0;
}
+ if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_NETWORK))
+ return tomoyo_write_network_policy(data, domain, is_delete);
return tomoyo_write_file_policy(data, domain, is_delete);
}
@@ -1378,6 +1385,107 @@ static bool tomoyo_print_double_path_acl
}
/**
+ * tomoyo_print_ipv4_entry - Print IPv4 address of a network ACL entry.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr: Pointer to "struct tomoyo_ip_network_acl_record".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_print_ipv4_entry(struct tomoyo_io_buffer *head,
+ struct tomoyo_ip_network_acl_record *ptr)
+{
+ const u32 min_address = htonl(ptr->u.ipv4.min);
+ const u32 max_address = htonl(ptr->u.ipv4.max);
+ if (!tomoyo_io_printf(head, "%pI4", &min_address))
+ return false;
+ if (min_address != max_address
+ && !tomoyo_io_printf(head, "-%pI4", &max_address))
+ return false;
+ return true;
+}
+
+/**
+ * tomoyo_print_ipv6_entry - Print IPv6 address of a network ACL entry.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr: Pointer to "struct tomoyo_ip_network_acl_record".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_print_ipv6_entry(struct tomoyo_io_buffer *head,
+ struct tomoyo_ip_network_acl_record *ptr)
+{
+ char buf[64];
+ const struct in6_addr *min_address = ptr->u.ipv6.min;
+ const struct in6_addr *max_address = ptr->u.ipv6.max;
+ tomoyo_print_ipv6(buf, sizeof(buf), min_address);
+ if (!tomoyo_io_printf(head, "%s", buf))
+ return false;
+ if (min_address != max_address) {
+ tomoyo_print_ipv6(buf, sizeof(buf), max_address);
+ if (!tomoyo_io_printf(head, "-%s", buf))
+ return false;
+ }
+ return true;
+}
+
+/**
+ * tomoyo_print_port_entry - Print port number of a network ACL entry.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr: Pointer to "struct tomoyo_ip_network_acl_record".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_print_port_entry(struct tomoyo_io_buffer *head,
+ struct tomoyo_ip_network_acl_record *ptr)
+{
+ const u16 min_port = ptr->min_port;
+ const u16 max_port = ptr->max_port;
+ if (!tomoyo_io_printf(head, " %u", min_port))
+ return false;
+ if (min_port != max_port && !tomoyo_io_printf(head, "-%u", max_port))
+ return false;
+ if (!tomoyo_io_printf(head, "\n"))
+ return false;
+ return true;
+}
+
+/**
+ * tomoyo_print_network_acl - Print a network ACL entry.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr: Pointer to "struct tomoyo_ip_network_acl_record".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_print_network_acl(struct tomoyo_io_buffer *head,
+ struct tomoyo_ip_network_acl_record *ptr)
+{
+ int pos = head->read_avail;
+ if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_NETWORK "%s ",
+ tomoyo_net2keyword(ptr->operation_type)))
+ goto out;
+ switch (ptr->record_type) {
+ case TOMOYO_IP_RECORD_TYPE_IPv4:
+ if (!tomoyo_print_ipv4_entry(head, ptr))
+ goto out;
+ break;
+ case TOMOYO_IP_RECORD_TYPE_IPv6:
+ if (!tomoyo_print_ipv6_entry(head, ptr))
+ goto out;
+ break;
+ }
+ if (!tomoyo_print_port_entry(head, ptr))
+ goto out;
+ return true;
+ out:
+ head->read_avail = pos;
+ return false;
+}
+
+/**
* tomoyo_print_entry - Print an ACL entry.
*
* @head: Pointer to "struct tomoyo_io_buffer".
@@ -1406,6 +1514,13 @@ static bool tomoyo_print_entry(struct to
head);
return tomoyo_print_double_path_acl(head, acl);
}
+ if (acl_type == TOMOYO_TYPE_IP_NETWORK_ACL) {
+ struct tomoyo_ip_network_acl_record *acl
+ = container_of(ptr,
+ struct tomoyo_ip_network_acl_record,
+ head);
+ return tomoyo_print_network_acl(head, acl);
+ }
BUG(); /* This must not happen. */
return false;
}
@@ -2068,6 +2183,9 @@ void *tomoyo_alloc_acl_element(const u8
case TOMOYO_TYPE_DOUBLE_PATH_ACL:
len = sizeof(struct tomoyo_double_path_acl_record);
break;
+ case TOMOYO_TYPE_IP_NETWORK_ACL:
+ len = sizeof(struct tomoyo_ip_network_acl_record);
+ break;
default:
return NULL;
}
--- security-testing-2.6.git.orig/security/tomoyo/common.h
+++ security-testing-2.6.git/security/tomoyo/common.h
@@ -130,8 +130,59 @@ struct tomoyo_double_path_acl_record {
const struct tomoyo_path_info *filename2;
};
+/* Structure for "allow_network" directive. */
+struct tomoyo_ip_network_acl_record {
+ struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_IP_NETWORK_ACL */
+ /*
+ * operation_type takes one of the following constants.
+ * NETWORK_ACL_UDP_BIND for UDP's bind() operation.
+ * NETWORK_ACL_UDP_CONNECT for UDP's connect()/send()/recv()
+ * operation.
+ * NETWORK_ACL_TCP_BIND for TCP's bind() operation.
+ * NETWORK_ACL_TCP_LISTEN for TCP's listen() operation.
+ * NETWORK_ACL_TCP_CONNECT for TCP's connect() operation.
+ * NETWORK_ACL_TCP_ACCEPT for TCP's accept() operation.
+ * NETWORK_ACL_RAW_BIND for IP's bind() operation.
+ * NETWORK_ACL_RAW_CONNECT for IP's connect()/send()/recv()
+ * operation.
+ */
+ u8 operation_type;
+ /*
+ * record_type takes one of the following constants.
+ * TOMOYO_IP_RECORD_TYPE_IPv4
+ * if u points to an IPv4 address.
+ * TOMOYO_IP_RECORD_TYPE_IPv6
+ * if u points to an IPv6 address.
+ */
+ u8 record_type;
+ /* Start of port number range. */
+ u16 min_port;
+ /* End of port number range. */
+ u16 max_port;
+ union {
+ struct {
+ /* Start of IPv4 address range. Host endian. */
+ u32 min;
+ /* End of IPv4 address range. Host endian. */
+ u32 max;
+ } ipv4;
+ struct {
+ /* Start of IPv6 address range. Big endian. */
+ const struct in6_addr *min;
+ /* End of IPv6 address range. Big endian. */
+ const struct in6_addr *max;
+ } ipv6;
+ } u;
+};
+
+enum tomoyo_ip_record_type {
+ TOMOYO_IP_RECORD_TYPE_IPv4,
+ TOMOYO_IP_RECORD_TYPE_IPv6
+};
+
/* Keywords for ACLs. */
#define TOMOYO_KEYWORD_ALIAS "alias "
+#define TOMOYO_KEYWORD_ALLOW_NETWORK "allow_network "
#define TOMOYO_KEYWORD_ALLOW_READ "allow_read "
#define TOMOYO_KEYWORD_DELETE "delete "
#define TOMOYO_KEYWORD_DENY_REWRITE "deny_rewrite "
@@ -149,9 +200,10 @@ struct tomoyo_double_path_acl_record {
/* Index numbers for Access Controls. */
#define TOMOYO_MAC_FOR_FILE 0 /* domain_policy.conf */
-#define TOMOYO_MAX_ACCEPT_ENTRY 1
-#define TOMOYO_VERBOSE 2
-#define TOMOYO_MAX_CONTROL_INDEX 3
+#define TOMOYO_MAC_FOR_NETWORK 1
+#define TOMOYO_MAX_ACCEPT_ENTRY 2
+#define TOMOYO_VERBOSE 3
+#define TOMOYO_MAX_CONTROL_INDEX 4
/* Structure for reading/writing policy via securityfs interfaces. */
struct tomoyo_io_buffer {
@@ -204,6 +256,9 @@ bool tomoyo_is_domain_def(const unsigned
/* Check whether the given filename matches the given pattern. */
bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
const struct tomoyo_path_info *pattern);
+/* Print an IPv6 address. */
+void tomoyo_print_ipv6(char *buffer, const int buffer_len,
+ const struct in6_addr *ip);
/* Read "alias" entry in exception policy. */
bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head);
/*
@@ -275,6 +330,13 @@ void tomoyo_load_policy(const char *file
/* Change "struct tomoyo_domain_info"->flags. */
void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
const bool is_delete, const u8 flags);
+/* Read "allow_network" entry in domain policy. */
+bool tomoyo_read_network_policy(struct tomoyo_io_buffer *head);
+/* Create "allow_network" entry in domain policy. */
+int tomoyo_write_network_policy(char *data, struct tomoyo_domain_info *domain,
+ const bool is_delete);
+/* Convert network operation index to network operation name. */
+const char *tomoyo_net2keyword(const u8 operation);
/* strcmp() for "struct tomoyo_path_info" structure. */
static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a,
--- /dev/null
+++ security-testing-2.6.git/security/tomoyo/network.c
@@ -0,0 +1,930 @@
+/*
+ * security/tomoyo/network.c
+ *
+ * Implementation of the Domain-Based Mandatory Access Control.
+ *
+ * Copyright (C) 2005-2009 NTT DATA CORPORATION
+ *
+ * Version: 2.3.0-pre 2009/04/15
+ *
+ */
+
+#include "common.h"
+#include "tomoyo.h"
+#include "realpath.h"
+
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/udp.h>
+
+/* Index numbers for Network Controls. */
+enum tomoyo_network_acl_index {
+ NETWORK_ACL_UDP_BIND,
+ NETWORK_ACL_UDP_CONNECT,
+ NETWORK_ACL_TCP_BIND,
+ NETWORK_ACL_TCP_LISTEN,
+ NETWORK_ACL_TCP_CONNECT,
+ NETWORK_ACL_TCP_ACCEPT,
+ NETWORK_ACL_RAW_BIND,
+ NETWORK_ACL_RAW_CONNECT
+};
+
+/**
+ * tomoyo_save_ipv6_address - Keep the given IPv6 address on the RAM.
+ *
+ * @addr: Pointer to "struct in6_addr".
+ *
+ * Returns pointer to "struct in6_addr" on success, NULL otherwise.
+ *
+ * The RAM is shared, so NEVER try to modify or kfree() the returned address.
+ */
+static const struct in6_addr *tomoyo_save_ipv6_address(const struct in6_addr *
+ addr)
+{
+ static const u8 tomoyo_block_size = 16;
+ struct tomoyo_addr_list {
+ /* Workaround for gcc 4.3's bug. */
+ struct in6_addr addr[16]; /* = tomoyo_block_size */
+ struct list_head list;
+ u32 in_use_count;
+ };
+ static LIST_HEAD(tomoyo_address_list);
+ struct tomoyo_addr_list *ptr;
+ static DEFINE_MUTEX(lock);
+ u8 i = tomoyo_block_size;
+ if (!addr)
+ return NULL;
+ /*
+ * Since reader calls down_read(&tomoyo_domain_acl_info_list_lock),
+ * this lock can remain as local lock.
+ */
+ mutex_lock(&lock);
+ list_for_each_entry(ptr, &tomoyo_address_list, list) {
+ for (i = 0; i < ptr->in_use_count; i++) {
+ if (!memcmp(&ptr->addr[i], addr, sizeof(*addr)))
+ goto ok;
+ }
+ if (i < tomoyo_block_size)
+ break;
+ }
+ if (i == tomoyo_block_size) {
+ ptr = tomoyo_alloc_element(sizeof(*ptr));
+ if (!ptr)
+ goto ok;
+ list_add_tail(&ptr->list, &tomoyo_address_list);
+ i = 0;
+ }
+ ptr->addr[ptr->in_use_count++] = *addr;
+ ok:
+ mutex_unlock(&lock);
+ return ptr ? &ptr->addr[i] : NULL;
+}
+
+/**
+ * tomoyo_parse_ip_address - Parse an IP address.
+ *
+ * @address: String to parse.
+ * @min: Pointer to store min address.
+ * @max: Pointer to store max address.
+ *
+ * Returns 2 if @address is an IPv6, 1 if @address is an IPv4, 0 otherwise.
+ */
+static int tomoyo_parse_ip_address(char *address, u16 *min, u16 *max)
+{
+ /* "%pI6" is not supported for sscanf(). */
+ int count = sscanf(address, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"
+ "-%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
+ &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) {
+ u8 i;
+ if (count == 8)
+ memmove(max, min, sizeof(u16) * 8);
+ for (i = 0; i < 8; i++) {
+ min[i] = htons(min[i]);
+ max[i] = htons(max[i]);
+ }
+ return 2;
+ }
+ /* "%pI4" is not supported for sscanf(). */
+ count = sscanf(address, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu",
+ &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]);
+ memmove(min, &ip, sizeof(ip));
+ if (count == 8)
+ ip = htonl((((u8) max[0]) << 24) + (((u8) max[1]) << 16)
+ + (((u8) max[2]) << 8) + (u8) max[3]);
+ memmove(max, &ip, sizeof(ip));
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * tomoyo_print_ipv6 - Print an IPv6 address.
+ *
+ * @buffer: Buffer to write to.
+ * @buffer_len: Size of @buffer.
+ * @ip: Pointer to "struct in6_addr".
+ *
+ * To make output shortest, TOMOYO doesn't use "%pI6".
+ *
+ * Returns nothing.
+ */
+void tomoyo_print_ipv6(char *buffer, const int buffer_len,
+ const struct in6_addr *ip)
+{
+ memset(buffer, 0, buffer_len);
+ snprintf(buffer, buffer_len - 1, "%x:%x:%x:%x:%x:%x:%x:%x",
+ ntohs(ip->s6_addr16[0]), ntohs(ip->s6_addr16[1]),
+ ntohs(ip->s6_addr16[2]), ntohs(ip->s6_addr16[3]),
+ ntohs(ip->s6_addr16[4]), ntohs(ip->s6_addr16[5]),
+ ntohs(ip->s6_addr16[6]), ntohs(ip->s6_addr16[7]));
+}
+
+/**
+ * tomoyo_net2keyword - Convert network operation index to network operation name.
+ *
+ * @operation: Type of operation.
+ *
+ * Returns the name of operation.
+ */
+const char *tomoyo_net2keyword(const u8 operation)
+{
+ const char *keyword = "unknown";
+ switch (operation) {
+ case NETWORK_ACL_UDP_BIND:
+ keyword = "UDP bind";
+ break;
+ case NETWORK_ACL_UDP_CONNECT:
+ keyword = "UDP connect";
+ break;
+ case NETWORK_ACL_TCP_BIND:
+ keyword = "TCP bind";
+ break;
+ case NETWORK_ACL_TCP_LISTEN:
+ keyword = "TCP listen";
+ break;
+ case NETWORK_ACL_TCP_CONNECT:
+ keyword = "TCP connect";
+ break;
+ case NETWORK_ACL_TCP_ACCEPT:
+ keyword = "TCP accept";
+ break;
+ case NETWORK_ACL_RAW_BIND:
+ keyword = "RAW bind";
+ break;
+ case NETWORK_ACL_RAW_CONNECT:
+ keyword = "RAW connect";
+ break;
+ }
+ return keyword;
+}
+
+/**
+ * tomoyo_update_network_entry - Update "struct tomoyo_ip_network_acl_record" list.
+ *
+ * @operation: Type of operation.
+ * @record_type: Type of address.
+ * @min_address: Start of IPv4 or IPv6 address range.
+ * @max_address: End of IPv4 or IPv6 address range.
+ * @min_port: Start of port number range.
+ * @max_port: End of port number range.
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_update_network_entry(const u8 operation, const u8 record_type,
+ const u32 *min_address,
+ const u32 *max_address,
+ const u16 min_port, const u16 max_port,
+ struct tomoyo_domain_info *domain,
+ const bool is_delete)
+{
+ struct tomoyo_acl_info *ptr;
+ struct tomoyo_ip_network_acl_record *acl;
+ 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);
+ const struct in6_addr *saved_min_address = NULL;
+ const struct in6_addr *saved_max_address = NULL;
+ if (!domain)
+ return -EINVAL;
+ if (record_type != TOMOYO_IP_RECORD_TYPE_IPv6)
+ goto not_ipv6;
+ saved_min_address = tomoyo_save_ipv6_address((struct in6_addr *)
+ min_address);
+ saved_max_address = tomoyo_save_ipv6_address((struct in6_addr *)
+ max_address);
+ if (!saved_min_address || !saved_max_address)
+ return -ENOMEM;
+ not_ipv6:
+ /***** EXCLUSIVE SECTION START *****/
+ down_write(&tomoyo_domain_acl_info_list_lock);
+ if (is_delete)
+ goto delete;
+ list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_IP_NETWORK_ACL)
+ continue;
+ acl = container_of(ptr, struct tomoyo_ip_network_acl_record,
+ head);
+ if (acl->operation_type != operation ||
+ acl->record_type != record_type ||
+ acl->min_port != min_port || max_port != acl->max_port)
+ continue;
+ if (record_type == TOMOYO_IP_RECORD_TYPE_IPv4) {
+ if (acl->u.ipv4.min != min_ip ||
+ max_ip != acl->u.ipv4.max)
+ continue;
+ } else if (record_type == TOMOYO_IP_RECORD_TYPE_IPv6) {
+ if (acl->u.ipv6.min != saved_min_address ||
+ saved_max_address != acl->u.ipv6.max)
+ continue;
+ }
+ ptr->type &= ~TOMOYO_ACL_DELETED;
+ error = 0;
+ goto out;
+ }
+ /* Not found. Append it to the tail. */
+ acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_IP_NETWORK_ACL);
+ if (!acl)
+ goto out;
+ acl->operation_type = operation;
+ acl->record_type = record_type;
+ if (record_type == TOMOYO_IP_RECORD_TYPE_IPv4) {
+ acl->u.ipv4.min = min_ip;
+ acl->u.ipv4.max = max_ip;
+ } else {
+ acl->u.ipv6.min = saved_min_address;
+ acl->u.ipv6.max = saved_max_address;
+ }
+ acl->min_port = min_port;
+ acl->max_port = max_port;
+ list_add_tail(&acl->head.list, &domain->acl_info_list);
+ error = 0;
+ goto out;
+ delete:
+ error = -ENOENT;
+ list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_IP_NETWORK_ACL)
+ continue;
+ acl = container_of(ptr, struct tomoyo_ip_network_acl_record,
+ head);
+ if (acl->operation_type != operation ||
+ acl->record_type != record_type ||
+ acl->min_port != min_port || max_port != acl->max_port)
+ continue;
+ if (record_type == TOMOYO_IP_RECORD_TYPE_IPv4) {
+ if (acl->u.ipv4.min != min_ip ||
+ max_ip != acl->u.ipv4.max)
+ continue;
+ } else if (record_type == TOMOYO_IP_RECORD_TYPE_IPv6) {
+ if (acl->u.ipv6.min != saved_min_address ||
+ saved_max_address != acl->u.ipv6.max)
+ continue;
+ }
+ ptr->type |= TOMOYO_ACL_DELETED;
+ error = 0;
+ break;
+ }
+ out:
+ up_write(&tomoyo_domain_acl_info_list_lock);
+ /***** EXCLUSIVE SECTION START *****/
+ return error;
+}
+
+/**
+ * tomoyo_check_network_entry - Check permission for network operation.
+ *
+ * @is_ipv6: True if @address is an IPv6 address.
+ * @operation: Type of operation.
+ * @address: An IPv4 or IPv6 address.
+ * @port: Port number.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_check_network_entry(const bool is_ipv6, const u8 operation,
+ const u32 *address, const u16 port)
+{
+ struct tomoyo_acl_info *ptr;
+ const char *keyword = tomoyo_net2keyword(operation);
+ struct tomoyo_domain_info *domain = tomoyo_domain();
+ const int mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_NETWORK);
+ const bool is_enforce = (mode == 3);
+ /* using host byte order to allow u32 comparison than memcmp().*/
+ const u32 ip = ntohl(*address);
+ bool found = false;
+ char buf[64];
+ if (!mode)
+ return 0;
+ down_read(&tomoyo_domain_acl_info_list_lock);
+ list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ struct tomoyo_ip_network_acl_record *acl;
+ if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_IP_NETWORK_ACL)
+ continue;
+ acl = container_of(ptr, struct tomoyo_ip_network_acl_record,
+ head);
+ if (acl->operation_type != operation || port < acl->min_port ||
+ acl->max_port < port)
+ continue;
+ if (acl->record_type == TOMOYO_IP_RECORD_TYPE_IPv4) {
+ if (is_ipv6 ||
+ ip < acl->u.ipv4.min || acl->u.ipv4.max < ip)
+ continue;
+ } else {
+ if (!is_ipv6 ||
+ memcmp(acl->u.ipv6.min, address, 16) > 0 ||
+ memcmp(address, acl->u.ipv6.max, 16) > 0)
+ continue;
+ }
+ found = true;
+ break;
+ }
+ up_read(&tomoyo_domain_acl_info_list_lock);
+ if (found)
+ return 0;
+ memset(buf, 0, sizeof(buf));
+ if (is_ipv6)
+ tomoyo_print_ipv6(buf, sizeof(buf),
+ (const struct in6_addr *) address);
+ else
+ snprintf(buf, sizeof(buf) - 1, "%pI4", address);
+ if (tomoyo_verbose_mode(domain))
+ printk(KERN_WARNING "TOMOYO-%s: %s to %s %u denied for %s\n",
+ tomoyo_get_msg(is_enforce), keyword, buf, port,
+ tomoyo_get_last_name(domain));
+ if (is_enforce)
+ return -EPERM;
+ if (mode == 1 && tomoyo_domain_quota_is_ok(domain))
+ tomoyo_update_network_entry(operation, is_ipv6 ?
+ TOMOYO_IP_RECORD_TYPE_IPv6 :
+ TOMOYO_IP_RECORD_TYPE_IPv4,
+ address, address, port, port,
+ domain, false);
+ return 0;
+}
+
+/**
+ * tomoyo_write_network_policy - Write "struct tomoyo_ip_network_acl_record" list.
+ *
+ * @data: String to parse.
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_network_policy(char *data, struct tomoyo_domain_info *domain,
+ const bool is_delete)
+{
+ u8 sock_type;
+ u8 operation;
+ u8 record_type;
+ u16 min_address[8];
+ u16 max_address[8];
+ u16 min_port;
+ u16 max_port;
+ u8 count;
+ char *cp1 = strchr(data, ' ');
+ char *cp2;
+ if (!cp1)
+ goto out;
+ cp1++;
+ if (!strncmp(data, "TCP ", 4))
+ sock_type = SOCK_STREAM;
+ else if (!strncmp(data, "UDP ", 4))
+ sock_type = SOCK_DGRAM;
+ else if (!strncmp(data, "RAW ", 4))
+ sock_type = SOCK_RAW;
+ else
+ goto out;
+ cp2 = strchr(cp1, ' ');
+ if (!cp2)
+ goto out;
+ cp2++;
+ if (!strncmp(cp1, "bind ", 5))
+ switch (sock_type) {
+ case SOCK_STREAM:
+ operation = NETWORK_ACL_TCP_BIND;
+ break;
+ case SOCK_DGRAM:
+ operation = NETWORK_ACL_UDP_BIND;
+ break;
+ default:
+ operation = NETWORK_ACL_RAW_BIND;
+ }
+ else if (!strncmp(cp1, "connect ", 8))
+ switch (sock_type) {
+ case SOCK_STREAM:
+ operation = NETWORK_ACL_TCP_CONNECT;
+ break;
+ case SOCK_DGRAM:
+ operation = NETWORK_ACL_UDP_CONNECT;
+ break;
+ default:
+ operation = NETWORK_ACL_RAW_CONNECT;
+ }
+ else if (sock_type == SOCK_STREAM && !strncmp(cp1, "listen ", 7))
+ operation = NETWORK_ACL_TCP_LISTEN;
+ else if (sock_type == SOCK_STREAM && !strncmp(cp1, "accept ", 7))
+ operation = NETWORK_ACL_TCP_ACCEPT;
+ else
+ goto out;
+ cp1 = strchr(cp2, ' ');
+ if (!cp1)
+ goto out;
+ *cp1++ = '\0';
+ switch (tomoyo_parse_ip_address(cp2, min_address, max_address)) {
+ case 2:
+ record_type = TOMOYO_IP_RECORD_TYPE_IPv6;
+ break;
+ case 1:
+ record_type = TOMOYO_IP_RECORD_TYPE_IPv4;
+ break;
+ default:
+ goto out;
+ }
+ 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 tomoyo_update_network_entry(operation, record_type,
+ (u32 *) min_address,
+ (u32 *) max_address,
+ min_port, max_port, domain,
+ is_delete);
+ out:
+ return -EINVAL;
+}
+
+/**
+ * tomoyo_check_network_listen_acl - Check permission for listen() operation.
+ *
+ * @is_ipv6: True if @address is an IPv6 address.
+ * @address: An IPv4 or IPv6 address.
+ * @port: Port number.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static inline int tomoyo_check_network_listen_acl(const bool is_ipv6,
+ const u8 *address,
+ const u16 port)
+{
+ return tomoyo_check_network_entry(is_ipv6, NETWORK_ACL_TCP_LISTEN,
+ (const u32 *) address, ntohs(port));
+}
+
+/**
+ * tomoyo_check_network_connect_acl - Check permission for connect() operation.
+ *
+ * @is_ipv6: True if @address is an IPv6 address.
+ * @sock_type: Type of socket. (TCP or UDP or RAW)
+ * @address: An IPv4 or IPv6 address.
+ * @port: Port number.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static inline int tomoyo_check_network_connect_acl(const bool is_ipv6,
+ const int sock_type,
+ const u8 *address,
+ const u16 port)
+{
+ u8 operation;
+ switch (sock_type) {
+ case SOCK_STREAM:
+ operation = NETWORK_ACL_TCP_CONNECT;
+ break;
+ case SOCK_DGRAM:
+ operation = NETWORK_ACL_UDP_CONNECT;
+ break;
+ default:
+ operation = NETWORK_ACL_RAW_CONNECT;
+ }
+ return tomoyo_check_network_entry(is_ipv6, operation,
+ (const u32 *) address, ntohs(port));
+}
+
+/**
+ * tomoyo_check_network_bind_acl - Check permission for bind() operation.
+ *
+ * @is_ipv6: True if @address is an IPv6 address.
+ * @sock_type: Type of socket. (TCP or UDP or RAW)
+ * @address: An IPv4 or IPv6 address.
+ * @port: Port number.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_check_network_bind_acl(const bool is_ipv6,
+ const int sock_type,
+ const u8 *address, const u16 port)
+{
+ u8 operation;
+ switch (sock_type) {
+ case SOCK_STREAM:
+ operation = NETWORK_ACL_TCP_BIND;
+ break;
+ case SOCK_DGRAM:
+ operation = NETWORK_ACL_UDP_BIND;
+ break;
+ default:
+ operation = NETWORK_ACL_RAW_BIND;
+ }
+ return tomoyo_check_network_entry(is_ipv6, operation,
+ (const u32 *) address, ntohs(port));
+}
+
+/**
+ * tomoyo_check_network_accept_acl - Check permission for accept() operation.
+ *
+ * @is_ipv6: True if @address is an IPv6 address.
+ * @address: An IPv4 or IPv6 address.
+ * @port: Port number.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static inline int tomoyo_check_network_accept_acl(const bool is_ipv6,
+ const u8 *address,
+ const u16 port)
+{
+ return tomoyo_check_network_entry(is_ipv6, NETWORK_ACL_TCP_ACCEPT,
+ (const u32 *) address, ntohs(port));
+}
+
+/**
+ * tomoyo_check_network_sendmsg_acl - Check permission for sendmsg() operation.
+ *
+ * @is_ipv6: True if @address is an IPv6 address.
+ * @sock_type: Type of socket. (UDP or RAW)
+ * @address: An IPv4 or IPv6 address.
+ * @port: Port number.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static inline int tomoyo_check_network_sendmsg_acl(const bool is_ipv6,
+ const int sock_type,
+ const u8 *address,
+ const u16 port)
+{
+ u8 operation;
+ if (sock_type == SOCK_DGRAM)
+ operation = NETWORK_ACL_UDP_CONNECT;
+ else
+ operation = NETWORK_ACL_RAW_CONNECT;
+ return tomoyo_check_network_entry(is_ipv6, operation,
+ (const u32 *) address, ntohs(port));
+}
+
+/**
+ * tomoyo_check_network_recvmsg_acl - Check permission for recvmsg() operation.
+ *
+ * @is_ipv6: True if @address is an IPv6 address.
+ * @sock_type: Type of socket. (UDP or RAW)
+ * @address: An IPv4 or IPv6 address.
+ * @port: Port number.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static inline int tomoyo_check_network_recvmsg_acl(const bool is_ipv6,
+ const int sock_type,
+ const u8 *address,
+ const u16 port)
+{
+ const u8 operation
+ = (sock_type == SOCK_DGRAM) ?
+ NETWORK_ACL_UDP_CONNECT : NETWORK_ACL_RAW_CONNECT;
+ return tomoyo_check_network_entry(is_ipv6, operation,
+ (const u32 *) address, ntohs(port));
+}
+
+#define MAX_SOCK_ADDR 128 /* net/socket.c */
+
+/**
+ * tomoyo_socket_listen_permission - Check permission for listening a TCP socket.
+ *
+ * @sock: Pointer to "struct socket".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_socket_listen_permission(struct socket *sock)
+{
+ int error = 0;
+ char addr[MAX_SOCK_ADDR];
+ int addr_len;
+ /* Nothing to do if I am a kernel service. */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return 0;
+ if (sock->type != SOCK_STREAM)
+ return 0;
+ switch (sock->sk->sk_family) {
+ case PF_INET:
+ case PF_INET6:
+ break;
+ default:
+ return 0;
+ }
+ if (sock->ops->getname(sock, (struct sockaddr *) addr, &addr_len, 0))
+ return -EPERM;
+ switch (((struct sockaddr *) addr)->sa_family) {
+ struct sockaddr_in6 *addr6;
+ struct sockaddr_in *addr4;
+ case AF_INET6:
+ addr6 = (struct sockaddr_in6 *) addr;
+ error = tomoyo_check_network_listen_acl(true, addr6->sin6_addr.
+ s6_addr,
+ addr6->sin6_port);
+ break;
+ case AF_INET:
+ addr4 = (struct sockaddr_in *) addr;
+ error = tomoyo_check_network_listen_acl(false,
+ (u8 *) &addr4->sin_addr,
+ addr4->sin_port);
+ break;
+ }
+ return error;
+}
+
+/**
+ * tomoyo_socket_connect_permission - Check permission for setting the remote IP address/port pair of a socket.
+ *
+ * @sock: Pointer to "struct socket".
+ * @addr: Pointer to "struct sockaddr".
+ * @len: Size of @addr in bytes.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_socket_connect_permission(struct socket *sock, struct sockaddr *addr,
+ int addr_len)
+{
+ int error = 0;
+ const unsigned int type = sock->type;
+ /* Nothing to do if I am a kernel service. */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return 0;
+ switch (type) {
+ case SOCK_STREAM:
+ case SOCK_DGRAM:
+ case SOCK_RAW:
+ break;
+ default:
+ return 0;
+ }
+ switch (addr->sa_family) {
+ struct sockaddr_in6 *addr6;
+ struct sockaddr_in *addr4;
+ u16 port;
+ case AF_INET6:
+ if (addr_len < SIN6_LEN_RFC2133)
+ break;
+ addr6 = (struct sockaddr_in6 *) addr;
+ if (type != SOCK_RAW)
+ port = addr6->sin6_port;
+ else
+ port = htons(sock->sk->sk_protocol);
+ error = tomoyo_check_network_connect_acl(true, type,
+ addr6->sin6_addr.
+ s6_addr, port);
+ break;
+ case AF_INET:
+ if (addr_len < sizeof(struct sockaddr_in))
+ break;
+ addr4 = (struct sockaddr_in *) addr;
+ if (type != SOCK_RAW)
+ port = addr4->sin_port;
+ else
+ port = htons(sock->sk->sk_protocol);
+ error = tomoyo_check_network_connect_acl(false, type, (u8 *)
+ &addr4->sin_addr,
+ port);
+ break;
+ }
+ return error;
+}
+
+/**
+ * tomoyo_socket_bind_permission - Check permission for setting the local IP address/port pair of a socket.
+ *
+ * @sock: Pointer to "struct socket".
+ * @addr: Pointer to "struct sockaddr".
+ * @len: Size of @addr in bytes.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr,
+ int addr_len)
+{
+ int error = 0;
+ const unsigned int type = sock->type;
+ /* Nothing to do if I am a kernel service. */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return 0;
+ switch (type) {
+ case SOCK_STREAM:
+ case SOCK_DGRAM:
+ case SOCK_RAW:
+ break;
+ default:
+ return 0;
+ }
+ switch (addr->sa_family) {
+ struct sockaddr_in6 *addr6;
+ struct sockaddr_in *addr4;
+ u16 port;
+ case AF_INET6:
+ if (addr_len < SIN6_LEN_RFC2133)
+ break;
+ addr6 = (struct sockaddr_in6 *) addr;
+ if (type != SOCK_RAW)
+ port = addr6->sin6_port;
+ else
+ port = htons(sock->sk->sk_protocol);
+ error = tomoyo_check_network_bind_acl(true, type,
+ addr6->sin6_addr.s6_addr,
+ port);
+ break;
+ case AF_INET:
+ if (addr_len < sizeof(struct sockaddr_in))
+ break;
+ addr4 = (struct sockaddr_in *) addr;
+ if (type != SOCK_RAW)
+ port = addr4->sin_port;
+ else
+ port = htons(sock->sk->sk_protocol);
+ error = tomoyo_check_network_bind_acl(false, type,
+ (u8 *) &addr4->sin_addr,
+ port);
+ break;
+ }
+ return error;
+}
+
+/**
+ * tomoyo_socket_accept_permission - Check permission for accepting a TCP socket.
+ *
+ * @sock: Pointer to "struct socket".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_socket_accept_permission(struct socket *sock)
+{
+ int error = 0;
+ struct sockaddr_storage addr;
+ int addr_len;
+ /* Nothing to do if I am a kernel service. */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return 0;
+ switch (sock->sk->sk_family) {
+ case PF_INET:
+ case PF_INET6:
+ break;
+ default:
+ return 0;
+ }
+ error = sock->ops->getname(sock, (struct sockaddr *) &addr, &addr_len,
+ 2);
+ if (error)
+ return error;
+ switch (((struct sockaddr *) &addr)->sa_family) {
+ struct sockaddr_in6 *addr6;
+ struct sockaddr_in *addr4;
+ case AF_INET6:
+ addr6 = (struct sockaddr_in6 *) &addr;
+ error = tomoyo_check_network_accept_acl(true, addr6->sin6_addr.
+ s6_addr,
+ addr6->sin6_port);
+ break;
+ case AF_INET:
+ addr4 = (struct sockaddr_in *) &addr;
+ error = tomoyo_check_network_accept_acl(false, (u8 *) &addr4->
+ sin_addr,
+ addr4->sin_port);
+ break;
+ }
+ if (error)
+ error = -ECONNABORTED; /* Hope less harmful than -EPERM. */
+ return error;
+}
+
+/**
+ * tomoyo_socket_sendmsg_permission - Check permission for sending a datagram via a UDP or RAW socket.
+ *
+ * @sock: Pointer to "struct socket".
+ * @addr: Pointer to "struct sockaddr".
+ * @addr_len: Size of @addr in bytes.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_socket_sendmsg_permission(struct socket *sock, struct sockaddr *addr,
+ int addr_len)
+{
+ int error = 0;
+ const int type = sock->type;
+ /* Nothing to do if I am a kernel service. */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return 0;
+ if (!addr || (type != SOCK_DGRAM && type != SOCK_RAW))
+ return 0;
+ switch (addr->sa_family) {
+ struct sockaddr_in6 *addr6;
+ struct sockaddr_in *addr4;
+ u16 port;
+ case AF_INET6:
+ if (addr_len < SIN6_LEN_RFC2133)
+ break;
+ addr6 = (struct sockaddr_in6 *) addr;
+ if (type == SOCK_DGRAM)
+ port = addr6->sin6_port;
+ else
+ port = htons(sock->sk->sk_protocol);
+ error = tomoyo_check_network_sendmsg_acl(true, type,
+ addr6->sin6_addr.
+ s6_addr, port);
+ break;
+ case AF_INET:
+ if (addr_len < sizeof(struct sockaddr_in))
+ break;
+ addr4 = (struct sockaddr_in *) addr;
+ if (type == SOCK_DGRAM)
+ port = addr4->sin_port;
+ else
+ port = htons(sock->sk->sk_protocol);
+ error = tomoyo_check_network_sendmsg_acl(false, type, (u8 *)
+ &addr4->sin_addr,
+ port);
+ break;
+ }
+ return error;
+}
+
+/**
+ * tomoyo_socket_recv_datagram_permission - Check permission for receiving a datagram via a UDP or RAW socket.
+ *
+ * @sk: Pointer to "struct sock".
+ * @skb: Pointer to "struct sk_buff".
+ * @flags: Flags for recvmsg().
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_socket_recv_datagram_permission(struct sock *sk, struct sk_buff *skb,
+ const unsigned int flags)
+{
+ int error = 0;
+ const unsigned int type = sk->sk_type;
+ /* Nothing to do if I can't sleep. */
+ if (in_atomic())
+ return 0;
+ /* Nothing to do if I am a kernel service. */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return 0;
+ if (type != SOCK_DGRAM && type != SOCK_RAW)
+ return 0;
+
+ switch (sk->sk_family) {
+ struct in6_addr sin6;
+ struct in_addr sin4;
+ u16 port;
+ case PF_INET6:
+ if (type == SOCK_DGRAM) { /* UDP IPv6 */
+ if (skb->protocol == htons(ETH_P_IP)) {
+ ipv6_addr_set(&sin6, 0, 0, htonl(0xffff),
+ ip_hdr(skb)->saddr);
+ } else {
+ ipv6_addr_copy(&sin6, &ipv6_hdr(skb)->saddr);
+ }
+ port = udp_hdr(skb)->source;
+ } else { /* RAW IPv6 */
+ ipv6_addr_copy(&sin6, &ipv6_hdr(skb)->saddr);
+ port = htons(sk->sk_protocol);
+ }
+ error = tomoyo_check_network_recvmsg_acl(true, type,
+ (u8 *) &sin6, port);
+ break;
+ case PF_INET:
+ if (type == SOCK_DGRAM) { /* UDP IPv4 */
+ sin4.s_addr = ip_hdr(skb)->saddr;
+ port = udp_hdr(skb)->source;
+ } else { /* RAW IPv4 */
+ sin4.s_addr = ip_hdr(skb)->saddr;
+ port = htons(sk->sk_protocol);
+ }
+ error = tomoyo_check_network_recvmsg_acl(false, type,
+ (u8 *) &sin4, port);
+ break;
+ }
+ if (!error)
+ return 0;
+ /* Hope less harmful than -EPERM. */
+ return -EAGAIN;
+}
--- security-testing-2.6.git.orig/security/tomoyo/tomoyo.c
+++ security-testing-2.6.git/security/tomoyo/tomoyo.c
@@ -10,6 +10,7 @@
*/
#include <linux/security.h>
+#include <linux/socket.h>
#include "common.h"
#include "tomoyo.h"
#include "realpath.h"
@@ -256,6 +257,45 @@ static int tomoyo_dentry_open(struct fil
return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags);
}
+static int tomoyo_socket_bind(struct socket *sock, struct sockaddr *address,
+ int addrlen)
+{
+ return tomoyo_socket_bind_permission(sock, address, addrlen);
+}
+
+static int tomoyo_socket_connect(struct socket *sock, struct sockaddr *address,
+ int addrlen)
+{
+ return tomoyo_socket_connect_permission(sock, address, addrlen);
+}
+
+static int tomoyo_socket_listen(struct socket *sock, int backlog)
+{
+ return tomoyo_socket_listen_permission(sock);
+}
+
+static int tomoyo_socket_post_accept(struct socket *sock,
+ struct socket *newsock)
+{
+ return tomoyo_socket_accept_permission(newsock);
+}
+
+static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg,
+ int size)
+{
+ return tomoyo_socket_sendmsg_permission(sock, (struct sockaddr *)
+ msg->msg_name,
+ msg->msg_namelen);
+}
+
+
+static int tomoyo_socket_post_recv_datagram(struct sock *sk,
+ struct sk_buff *skb,
+ unsigned int flags)
+{
+ return tomoyo_socket_recv_datagram_permission(sk, skb, flags);
+}
+
static struct security_operations tomoyo_security_ops = {
.name = "tomoyo",
.cred_prepare = tomoyo_cred_prepare,
@@ -274,6 +314,12 @@ static struct security_operations tomoyo
.path_mknod = tomoyo_path_mknod,
.path_link = tomoyo_path_link,
.path_rename = tomoyo_path_rename,
+ .socket_bind = tomoyo_socket_bind,
+ .socket_listen = tomoyo_socket_listen,
+ .socket_connect = tomoyo_socket_connect,
+ .socket_sendmsg = tomoyo_socket_sendmsg,
+ .socket_post_recv_datagram = tomoyo_socket_post_recv_datagram,
+ .socket_post_accept = tomoyo_socket_post_accept,
};
static int __init tomoyo_init(void)
--- security-testing-2.6.git.orig/security/tomoyo/tomoyo.h
+++ security-testing-2.6.git/security/tomoyo/tomoyo.h
@@ -36,10 +36,27 @@ int tomoyo_check_rewrite_permission(stru
int tomoyo_find_next_domain(struct linux_binprm *bprm,
struct tomoyo_domain_info **next_domain);
+struct sock;
+struct sk_buff;
+struct socket;
+struct sockaddr;
+int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr,
+ int addr_len);
+int tomoyo_socket_connect_permission(struct socket *sock, struct sockaddr *addr,
+ int addr_len);
+int tomoyo_socket_listen_permission(struct socket *sock);
+int tomoyo_socket_accept_permission(struct socket *sock);
+int tomoyo_socket_sendmsg_permission(struct socket *sock, struct sockaddr *addr,
+ int addr_len);
+int tomoyo_socket_recv_datagram_permission(struct sock *sk, struct sk_buff *skb,
+ const unsigned int flags);
+
+
/* Index numbers for Access Controls. */
#define TOMOYO_TYPE_SINGLE_PATH_ACL 0
#define TOMOYO_TYPE_DOUBLE_PATH_ACL 1
+#define TOMOYO_TYPE_IP_NETWORK_ACL 2
/* Index numbers for File Controls. */
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists