diff mbox

[2/2] tomoyo: Add network access control support.

Message ID 200904151951.GEI34847.OLVFJFMtHSOFOQ@I-love.SAKURA.ne.jp
State Not Applicable, archived
Delegated to: David Miller
Headers show

Commit Message

Tetsuo Handa April 15, 2009, 10:51 a.m. UTC
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@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Toshiharu Harada <haradats@nttdata.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(-)

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

--- 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. */