オープンソース・ソフトウェアの開発とダウンロード

Subversion リポジトリの参照

Diff of /trunk/1.8.x/ccs-patch/security/ccsecurity/network.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/1.6.x/ccs-patch/fs/tomoyo_network.c revision 1719 by kumaneko, Mon Oct 20 05:22:50 2008 UTC trunk/1.8.x/ccs-patch/security/ccsecurity/network.c revision 3875 by kumaneko, Sun Aug 1 11:39:42 2010 UTC
# Line 1  Line 1 
1  /*  /*
2   * fs/tomoyo_network.c   * security/ccsecurity/network.c
3   *   *
4   * Implementation of the Domain-Based Mandatory Access Control.   * Copyright (C) 2005-2010  NTT DATA CORPORATION
5   *   *
6   * Copyright (C) 2005-2008  NTT DATA CORPORATION   * Version: 1.8.0-pre   2010/08/01
  *  
  * Version: 1.6.5-pre   2008/10/20  
7   *   *
8   * This file is applicable to both 2.4.30 and 2.6.11 and later.   * This file is applicable to both 2.4.30 and 2.6.11 and later.
9   * See README.ccs for ChangeLog.   * See README.ccs for ChangeLog.
10   *   *
11   */   */
12    
 #include <linux/ccs_common.h>  
 #include <linux/tomoyo.h>  
 #include <linux/realpath.h>  
13  #include <linux/net.h>  #include <linux/net.h>
14  #include <linux/inet.h>  #include <linux/inet.h>
15  #include <linux/in.h>  #include <linux/in.h>
16  #include <linux/in6.h>  #include <linux/in6.h>
17    #include <net/ip.h>
18    #include <net/ipv6.h>
19    #include <net/udp.h>
20    #include "internal.h"
21    
22  /**  struct ccs_addr_info {
23   * audit_network_log - Audit network log.          u8 protocol;
24   *          u8 operation;
25   * @r:          Pointer to "struct ccs_request_info".          u16 port;           /* In network byte order. */
26   * @operation:  The name of operation.          const u32 *address; /* In network byte order. */
27   * @address:    An IPv4 or IPv6 address.          bool is_ipv6;
28   * @port:       Port number.  };
  * @is_granted: True if this is a granted log.  
  *  
  * Returns 0 on success, negative value otherwise.  
  */  
 static int audit_network_log(struct ccs_request_info *r, const char *operation,  
                              const char *address, const u16 port,  
                              const bool is_granted)  
 {  
         return ccs_write_audit_log(is_granted, r, KEYWORD_ALLOW_NETWORK  
                                    "%s %s %u\n", operation, address, port);  
 }  
29    
30  /**  const char *ccs_net_protocol_keyword[CCS_MAX_NETWORK_PROTOCOL] = {
31   * save_ipv6_address - Keep the given IPv6 address on the RAM.          [CCS_NETWORK_TCP_PROTOCOL] = "TCP",
32   *          [CCS_NETWORK_UDP_PROTOCOL] = "UDP",
33   * @addr: Pointer to "struct in6_addr".          [CCS_NETWORK_RAW_PROTOCOL] = "RAW",
34   *  };
  * 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 *save_ipv6_address(const struct in6_addr *addr)  
 {  
         static const u8 block_size = 16;  
         struct addr_list {  
                 /* Workaround for gcc 4.3's bug. */  
                 struct in6_addr addr[16]; /* = block_size */  
                 struct list1_head list;  
                 u32 in_use_count;  
         };  
         static LIST1_HEAD(address_list);  
         struct addr_list *ptr;  
         static DEFINE_MUTEX(lock);  
         u8 i = block_size;  
         if (!addr)  
                 return NULL;  
         mutex_lock(&lock);  
         list1_for_each_entry(ptr, &address_list, list) {  
                 for (i = 0; i < ptr->in_use_count; i++) {  
                         if (!memcmp(&ptr->addr[i], addr, sizeof(*addr)))  
                                 goto ok;  
                 }  
                 if (i < block_size)  
                         break;  
         }  
         if (i == block_size) {  
                 ptr = ccs_alloc_element(sizeof(*ptr));  
                 if (!ptr)  
                         goto ok;  
                 list1_add_tail_mb(&ptr->list, &address_list);  
                 i = 0;  
         }  
         ptr->addr[ptr->in_use_count++] = *addr;  
  ok:  
         mutex_unlock(&lock);  
         return ptr ? &ptr->addr[i] : NULL;  
 }  
35    
36  /* The list for "struct address_group_entry". */  const char *ccs_net_keyword[CCS_MAX_NETWORK_OPERATION] = {
37  static LIST1_HEAD(address_group_list);          [CCS_NETWORK_BIND]    = "bind",
38            [CCS_NETWORK_LISTEN]  = "listen",
39            [CCS_NETWORK_CONNECT] = "connect",
40            [CCS_NETWORK_ACCEPT]  = "accept",
41            [CCS_NETWORK_SEND]    = "send",
42            [CCS_NETWORK_RECV]    = "recv",
43    };
44    
45  /**  /**
46   * update_address_group_entry - Update "struct address_group_entry" list.   * ccs_audit_network_log - Audit network log.
47   *   *
48   * @group_name:  The name of address group.   * @r: Pointer to "struct ccs_request_info".
  * @is_ipv6:     True if @min_address and @max_address are IPv6 addresses.  
  * @min_address: Start of IPv4 or IPv6 address range.  
  * @max_address: End of IPv4 or IPv6 address range.  
  * @is_delete:   True if it is a delete request.  
49   *   *
50   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
51   */   */
52  static int update_address_group_entry(const char *group_name,  static int ccs_audit_network_log(struct ccs_request_info *r)
53                                        const bool is_ipv6,  {
54                                        const u16 *min_address,          char buf[128];
55                                        const u16 *max_address,          const char *protocol =
56                                        const bool is_delete)                  ccs_net_protocol_keyword[r->param.network.protocol];
57  {          const char *operation = ccs_net_keyword[r->param.network.operation];
58          static DEFINE_MUTEX(lock);          const u32 *address = r->param.network.address;
59          struct address_group_entry *new_group;          const u16 port = r->param.network.port;
60          struct address_group_entry *group;          if (r->param.network.is_ipv6)
61          struct address_group_member *new_member;                  ccs_print_ipv6(buf, sizeof(buf), (const struct in6_addr *)
62          struct address_group_member *member;                                 address, (const struct in6_addr *) address);
63          const struct path_info *saved_group_name;          else
64          const struct in6_addr *saved_min_address = NULL;                  ccs_print_ipv4(buf, sizeof(buf), r->param.network.ip,
65          const struct in6_addr *saved_max_address = NULL;                                 r->param.network.ip);
66          int error = -ENOMEM;          ccs_write_log(r, "network %s %s %s %u\n", protocol, operation, buf,
67          bool found = false;                        port);
68          if (!ccs_is_correct_path(group_name, 0, 0, 0, __func__) ||          if (r->granted)
69              !group_name[0])                  return 0;
70                  return -EINVAL;          ccs_warn_log(r, "network %s %s %s %u", protocol, operation, buf, port);
71          saved_group_name = ccs_save_name(group_name);          return ccs_supervisor(r, "network %s %s %s %u\n", protocol, operation,
72          if (!saved_group_name)                                buf, port);
                 return -ENOMEM;  
         if (!is_ipv6)  
                 goto not_ipv6;  
         saved_min_address  
                 = save_ipv6_address((struct in6_addr *) min_address);  
         saved_max_address  
                 = save_ipv6_address((struct in6_addr *) max_address);  
         if (!saved_min_address || !saved_max_address)  
                 return -ENOMEM;  
  not_ipv6:  
         mutex_lock(&lock);  
         list1_for_each_entry(group, &address_group_list, list) {  
                 if (saved_group_name != group->group_name)  
                         continue;  
                 list1_for_each_entry(member, &group->address_group_member_list,  
                                      list) {  
                         if (member->is_ipv6 != is_ipv6)  
                                 continue;  
                         if (is_ipv6) {  
                                 if (member->min.ipv6 != saved_min_address ||  
                                     member->max.ipv6 != saved_max_address)  
                                         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;  
                 }  
                 found = true;  
                 break;  
         }  
         if (is_delete) {  
                 error = -ENOENT;  
                 goto out;  
         }  
         if (!found) {  
                 new_group = ccs_alloc_element(sizeof(*new_group));  
                 if (!new_group)  
                         goto out;  
                 INIT_LIST1_HEAD(&new_group->address_group_member_list);  
                 new_group->group_name = saved_group_name;  
                 list1_add_tail_mb(&new_group->list, &address_group_list);  
                 group = new_group;  
         }  
         new_member = ccs_alloc_element(sizeof(*new_member));  
         if (!new_member)  
                 goto out;  
         new_member->is_ipv6 = is_ipv6;  
         if (is_ipv6) {  
                 new_member->min.ipv6 = saved_min_address;  
                 new_member->max.ipv6 = saved_max_address;  
         } else {  
                 new_member->min.ipv4 = *(u32 *) min_address;  
                 new_member->max.ipv4 = *(u32 *) max_address;  
         }  
         list1_add_tail_mb(&new_member->list, &group->address_group_member_list);  
         error = 0;  
  out:  
         mutex_unlock(&lock);  
         ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);  
         return error;  
73  }  }
74    
75  /**  /**
76   * parse_ip_address - Parse an IP address.   * ccs_parse_ip_address - Parse an IP address.
77   *   *
78   * @address: String to parse.   * @address: String to parse.
79   * @min:     Pointer to store min address.   * @min:     Pointer to store min address.
80   * @max:     Pointer to store max address.   * @max:     Pointer to store max address.
81   *   *
82   * Returns 2 if @address is an IPv6, 1 if @address is an IPv4, 0 otherwise.   * Returns CCS_IP_ADDRESS_TYPE_IPv6 if @address is an IPv6,
83     * CCS_IP_ADDRESS_TYPE_IPv4 if @address is an IPv4,
84     * CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP otherwise.
85   */   */
86  static int parse_ip_address(char *address, u16 *min, u16 *max)  int ccs_parse_ip_address(char *address, u16 *min, u16 *max)
87  {  {
88          int count = sscanf(address, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"          int count = sscanf(address, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"
89                             "-%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",                             "-%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
# Line 211  static int parse_ip_address(char *addres Line 99  static int parse_ip_address(char *addres
99                          min[i] = htons(min[i]);                          min[i] = htons(min[i]);
100                          max[i] = htons(max[i]);                          max[i] = htons(max[i]);
101                  }                  }
102                  return 2;                  return CCS_IP_ADDRESS_TYPE_IPv6;
103          }          }
104          count = sscanf(address, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu",          count = sscanf(address, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu",
105                         &min[0], &min[1], &min[2], &min[3],                         &min[0], &min[1], &min[2], &min[3],
# Line 221  static int parse_ip_address(char *addres Line 109  static int parse_ip_address(char *addres
109                                 + (((u8) min[2]) << 8) + (u8) min[3]);                                 + (((u8) min[2]) << 8) + (u8) min[3]);
110                  memmove(min, &ip, sizeof(ip));                  memmove(min, &ip, sizeof(ip));
111                  if (count == 8)                  if (count == 8)
112                          ip = htonl((((u8) max[0]) << 24) + (((u8) max[1]) << 16)                          ip = htonl((((u8) max[0]) << 24)
113                                       + (((u8) max[1]) << 16)
114                                     + (((u8) max[2]) << 8) + (u8) max[3]);                                     + (((u8) max[2]) << 8) + (u8) max[3]);
115                  memmove(max, &ip, sizeof(ip));                  memmove(max, &ip, sizeof(ip));
116                  return 1;                  return CCS_IP_ADDRESS_TYPE_IPv4;
         }  
         return 0;  
 }  
   
 /**  
  * ccs_write_address_group_policy - Write "struct address_group_entry" list.  
  *  
  * @data:      String to parse.  
  * @is_delete: True if it is a delete request.  
  *  
  * Returns 0 on success, negative value otherwise.  
  */  
 int ccs_write_address_group_policy(char *data, const bool is_delete)  
 {  
         bool is_ipv6;  
         u16 min_address[8];  
         u16 max_address[8];  
         char *cp = strchr(data, ' ');  
         if (!cp)  
                 return -EINVAL;  
         *cp++ = '\0';  
         switch (parse_ip_address(cp, min_address, max_address)) {  
         case 2:  
                 is_ipv6 = true;  
                 break;  
         case 1:  
                 is_ipv6 = false;  
                 break;  
         default:  
                 return -EINVAL;  
         }  
         return update_address_group_entry(data, is_ipv6,  
                                           min_address, max_address, is_delete);  
 }  
   
 /**  
  * find_or_assign_new_address_group - Create address group.  
  *  
  * @group_name: The name of address group.  
  *  
  * Returns pointer to "struct address_group_entry" on success, NULL otherwise.  
  */  
 static struct address_group_entry *  
 find_or_assign_new_address_group(const char *group_name)  
 {  
         u8 i;  
         struct address_group_entry *group;  
         for (i = 0; i <= 1; i++) {  
                 list1_for_each_entry(group, &address_group_list, list) {  
                         if (!strcmp(group_name, group->group_name->name))  
                                 return group;  
                 }  
                 if (!i) {  
                         const u16 dummy[2] = { 0, 0 };  
                         update_address_group_entry(group_name, false,  
                                                    dummy, dummy, false);  
                         update_address_group_entry(group_name, false,  
                                                    dummy, dummy, true);  
                 }  
         }  
         return NULL;  
 }  
   
 /**  
  * address_matches_to_group - Check whether the given address matches members of the given address group.  
  *  
  * @is_ipv6: True if @address is an IPv6 address.  
  * @address: An IPv4 or IPv6 address.  
  * @group:   Pointer to "struct address_group_entry".  
  *  
  * Returns true if @address matches addresses in @group group, false otherwise.  
  */  
 static bool address_matches_to_group(const bool is_ipv6, const u32 *address,  
                                      const struct address_group_entry *group)  
 {  
         struct address_group_member *member;  
         const u32 ip = ntohl(*address);  
         list1_for_each_entry(member, &group->address_group_member_list, list) {  
                 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 true;  
                 } else {  
                         if (!is_ipv6 &&  
                             member->min.ipv4 <= ip && ip <= member->max.ipv4)  
                                 return true;  
                 }  
117          }          }
118          return false;          return CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP;
119  }  }
120    
121  /**  /**
122   * ccs_read_address_group_policy - Read "struct address_group_entry" list.   * ccs_print_ipv4 - Print an IPv4 address.
123   *   *
124   * @head: Pointer to "struct ccs_io_buffer".   * @buffer:     Buffer to write to.
125     * @buffer_len: Size of @buffer.
126     * @min_ip:     Min address in host byte order.
127     * @max_ip:     Max address in host byte order.
128   *   *
129   * Returns true on success, false otherwise.   * Returns nothing.
130   */   */
131  bool ccs_read_address_group_policy(struct ccs_io_buffer *head)  void ccs_print_ipv4(char *buffer, const int buffer_len,
132                        const u32 min_ip, const u32 max_ip)
133  {  {
134          struct list1_head *gpos;          memset(buffer, 0, buffer_len);
135          struct list1_head *mpos;          snprintf(buffer, buffer_len - 1, "%u.%u.%u.%u%c%u.%u.%u.%u",
136          list1_for_each_cookie(gpos, head->read_var1, &address_group_list) {                   HIPQUAD(min_ip), min_ip == max_ip ? '\0' : '-',
137                  struct address_group_entry *group;                   HIPQUAD(max_ip));
                 group = list1_entry(gpos, struct address_group_entry, list);  
                 list1_for_each_cookie(mpos, head->read_var2,  
                                       &group->address_group_member_list) {  
                         char buf[128];  
                         struct address_group_member *member;  
                         member = list1_entry(mpos, struct address_group_member,  
                                              list);  
                         if (member->is_deleted)  
                                 continue;  
                         if (member->is_ipv6) {  
                                 const struct in6_addr *min_address  
                                         = member->min.ipv6;  
                                 const struct in6_addr *max_address  
                                         = member->max.ipv6;  
                                 ccs_print_ipv6(buf, sizeof(buf), min_address);  
                                 if (min_address != max_address) {  
                                         int len;  
                                         char *cp = strchr(buf, '\0');  
                                         *cp++ = '-';  
                                         len = strlen(buf);  
                                         ccs_print_ipv6(cp, sizeof(buf) - len,  
                                                        max_address);  
                                 }  
                         } else {  
                                 const u32 min_address = member->min.ipv4;  
                                 const u32 max_address = member->max.ipv4;  
                                 memset(buf, 0, sizeof(buf));  
                                 snprintf(buf, sizeof(buf) - 1, "%u.%u.%u.%u",  
                                          HIPQUAD(min_address));  
                                 if (min_address != max_address) {  
                                         const int len = strlen(buf);  
                                         snprintf(buf + len,  
                                                  sizeof(buf) - 1 - len,  
                                                  "-%u.%u.%u.%u",  
                                                  HIPQUAD(max_address));  
                                 }  
                         }  
                         if (!ccs_io_printf(head, KEYWORD_ADDRESS_GROUP  
                                            "%s %s\n", group->group_name->name,  
                                            buf))  
                                 goto out;  
                 }  
         }  
         return true;  
  out:  
         return false;  
138  }  }
139    
140  #if !defined(NIP6)  #if !defined(NIP6)
141  #define NIP6(addr)      \  #define NIP6(addr)                                                      \
142          ntohs((addr).s6_addr16[0]), ntohs((addr).s6_addr16[1]), \          ntohs((addr).s6_addr16[0]), ntohs((addr).s6_addr16[1]),         \
143          ntohs((addr).s6_addr16[2]), ntohs((addr).s6_addr16[3]), \                  ntohs((addr).s6_addr16[2]), ntohs((addr).s6_addr16[3]), \
144          ntohs((addr).s6_addr16[4]), ntohs((addr).s6_addr16[5]), \                  ntohs((addr).s6_addr16[4]), ntohs((addr).s6_addr16[5]), \
145          ntohs((addr).s6_addr16[6]), ntohs((addr).s6_addr16[7])                  ntohs((addr).s6_addr16[6]), ntohs((addr).s6_addr16[7])
146  #endif  #endif
147    
148  /**  /**
# Line 393  bool ccs_read_address_group_policy(struc Line 150  bool ccs_read_address_group_policy(struc
150   *   *
151   * @buffer:     Buffer to write to.   * @buffer:     Buffer to write to.
152   * @buffer_len: Size of @buffer.   * @buffer_len: Size of @buffer.
153   * @ip:         Pointer to "struct in6_addr".   * @min_ip:     Pointer to "struct in6_addr".
154     * @max_ip:     Pointer to "struct in6_addr".
155   *   *
156   * Returns nothing.   * Returns nothing.
157   */   */
158  void ccs_print_ipv6(char *buffer, const int buffer_len,  void ccs_print_ipv6(char *buffer, const int buffer_len,
159                      const struct in6_addr *ip)                      const struct in6_addr *min_ip,
160                        const struct in6_addr *max_ip)
161  {  {
162          memset(buffer, 0, buffer_len);          memset(buffer, 0, buffer_len);
163          snprintf(buffer, buffer_len - 1, "%x:%x:%x:%x:%x:%x:%x:%x", NIP6(*ip));          snprintf(buffer, buffer_len - 1,
164  }                   "%x:%x:%x:%x:%x:%x:%x:%x%c%x:%x:%x:%x:%x:%x:%x:%x",
165                     NIP6(*min_ip), min_ip == max_ip ? '\0' : '-',
166  /**                   NIP6(*max_ip));
167   * ccs_net2keyword - Convert network operation index to network operation name.  }
168   *  
169   * @operation: Type of operation.  static bool ccs_check_network_acl(struct ccs_request_info *r,
170   *                                    const struct ccs_acl_info *ptr)
171   * Returns the name of operation.  {
172   */          const struct ccs_ip_network_acl *acl =
173  const char *ccs_net2keyword(const u8 operation)                  container_of(ptr, typeof(*acl), head);
174  {          bool ret;
175          const char *keyword = "unknown";          if (!(acl->perm & (1 << r->param.network.operation)) ||
176          switch (operation) {              !ccs_compare_number_union(r->param.network.port, &acl->port))
177          case NETWORK_ACL_UDP_BIND:                  return false;
178                  keyword = "UDP bind";          switch (acl->address_type) {
179                  break;          case CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP:
180          case NETWORK_ACL_UDP_CONNECT:                  ret = ccs_address_matches_group(r->param.network.is_ipv6,
181                  keyword = "UDP connect";                                                  r->param.network.address,
182                  break;                                                  acl->address.group);
183          case NETWORK_ACL_TCP_BIND:                  break;
184                  keyword = "TCP bind";          case CCS_IP_ADDRESS_TYPE_IPv4:
185                    ret = !r->param.network.is_ipv6 &&
186                            acl->address.ipv4.min <= r->param.network.ip &&
187                            r->param.network.ip <= acl->address.ipv4.max;
188                  break;                  break;
189          case NETWORK_ACL_TCP_LISTEN:          default:
190                  keyword = "TCP listen";                  ret = r->param.network.is_ipv6 &&
191                  break;                          memcmp(acl->address.ipv6.min, r->param.network.address,
192          case NETWORK_ACL_TCP_CONNECT:                                 16) <= 0 &&
193                  keyword = "TCP connect";                          memcmp(r->param.network.address, acl->address.ipv6.max,
194                  break;                                 16) <= 0;
         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";  
195                  break;                  break;
196          }          }
197          return keyword;          return ret;
198  }  }
199    
200    static const u8
201    ccs_net2mac[CCS_MAX_NETWORK_PROTOCOL][CCS_MAX_NETWORK_OPERATION] = {
202            [CCS_NETWORK_TCP_PROTOCOL] = {
203                    [CCS_NETWORK_BIND]    = CCS_MAC_NETWORK_TCP_BIND,
204                    [CCS_NETWORK_LISTEN]  = CCS_MAC_NETWORK_TCP_LISTEN,
205                    [CCS_NETWORK_CONNECT] = CCS_MAC_NETWORK_TCP_CONNECT,
206                    [CCS_NETWORK_ACCEPT]  = CCS_MAC_NETWORK_TCP_ACCEPT,
207            },
208            [CCS_NETWORK_UDP_PROTOCOL] = {
209                    [CCS_NETWORK_BIND]    = CCS_MAC_NETWORK_UDP_BIND,
210                    [CCS_NETWORK_CONNECT] = CCS_MAC_NETWORK_UDP_SEND,
211                    [CCS_NETWORK_SEND]    = CCS_MAC_NETWORK_UDP_SEND,
212                    [CCS_NETWORK_RECV]    = CCS_MAC_NETWORK_UDP_RECV,
213            },
214            [CCS_NETWORK_RAW_PROTOCOL]    = {
215                    [CCS_NETWORK_BIND]    = CCS_MAC_NETWORK_RAW_BIND,
216                    [CCS_NETWORK_CONNECT] = CCS_MAC_NETWORK_RAW_SEND,
217                    [CCS_NETWORK_SEND]    = CCS_MAC_NETWORK_RAW_SEND,
218                    [CCS_NETWORK_RECV]    = CCS_MAC_NETWORK_RAW_RECV,
219            },
220    };
221    
222  /**  /**
223   * update_network_entry - Update "struct ip_network_acl_record" list.   * ccs_network_entry - Check permission for network operation.
224   *   *
225   * @operation:   Type of operation.   * @address: Pointer to "struct ccs_ip_address".
  * @record_type: Type of address.  
  * @group:       Pointer to "struct address_group_entry". May be NULL.  
  * @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 domain_info".  
  * @condition:   Pointer to "struct condition_list". May be NULL.  
  * @is_delete:   True if it is a delete request.  
226   *   *
227   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
228   */   */
229  static int update_network_entry(const u8 operation, const u8 record_type,  static int ccs_network_entry(const struct ccs_addr_info *address)
230                                  const struct address_group_entry *group,  {
231                                  const u32 *min_address, const u32 *max_address,          const int idx = ccs_read_lock();
232                                  const u16 min_port, const u16 max_port,          struct ccs_request_info r;
233                                  struct domain_info *domain,          int error = 0;
234                                  const struct condition_list *condition,          const u8 type = ccs_net2mac[address->protocol][address->operation];
235                                  const bool is_delete)          if (!type || ccs_init_request_info(&r, type) != CCS_CONFIG_DISABLED) {
236  {                  r.param_type = CCS_TYPE_IP_NETWORK_ACL;
237          static DEFINE_MUTEX(lock);                  r.param.network.protocol = address->protocol;
238          struct acl_info *ptr;                  r.param.network.operation = address->operation;
239          struct ip_network_acl_record *acl;                  r.param.network.is_ipv6 = address->is_ipv6;
240          int error = -ENOMEM;                  r.param.network.address = address->address;
241          /* using host byte order to allow u32 comparison than memcmp().*/                  r.param.network.port = ntohs(address->port);
242          const u32 min_ip = ntohl(*min_address);                  /* use host byte order to allow u32 comparison than memcmp().*/
243          const u32 max_ip = ntohl(*max_address);                  r.param.network.ip = ntohl(*address->address);
244          const struct in6_addr *saved_min_address = NULL;                  do {
245          const struct in6_addr *saved_max_address = NULL;                          ccs_check_acl(&r, ccs_check_network_acl);
246          if (!domain)                          error = ccs_audit_network_log(&r);
247                  return -EINVAL;                  } while (error == CCS_RETRY_REQUEST);
         if (record_type != IP_RECORD_TYPE_IPv6)  
                 goto not_ipv6;  
         saved_min_address = save_ipv6_address((struct in6_addr *) min_address);  
         saved_max_address = save_ipv6_address((struct in6_addr *) max_address);  
         if (!saved_min_address || !saved_max_address)  
                 return -ENOMEM;  
  not_ipv6:  
         mutex_lock(&lock);  
         if (is_delete)  
                 goto delete;  
         list1_for_each_entry(ptr, &domain->acl_info_list, list) {  
                 if (ccs_acl_type1(ptr) != TYPE_IP_NETWORK_ACL)  
                         continue;  
                 if (ccs_get_condition_part(ptr) != condition)  
                         continue;  
                 acl = container_of(ptr, struct 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 == IP_RECORD_TYPE_ADDRESS_GROUP) {  
                         if (acl->u.group != group)  
                                 continue;  
                 } else if (record_type == IP_RECORD_TYPE_IPv4) {  
                         if (acl->u.ipv4.min != min_ip ||  
                             max_ip != acl->u.ipv4.max)  
                                 continue;  
                 } else if (record_type == IP_RECORD_TYPE_IPv6) {  
                         if (acl->u.ipv6.min != saved_min_address ||  
                             saved_max_address != acl->u.ipv6.max)  
                                 continue;  
                 }  
                 error = ccs_add_domain_acl(NULL, ptr);  
                 goto out;  
         }  
         /* Not found. Append it to the tail. */  
         acl = ccs_alloc_acl_element(TYPE_IP_NETWORK_ACL, condition);  
         if (!acl)  
                 goto out;  
         acl->operation_type = operation;  
         acl->record_type = record_type;  
         if (record_type == IP_RECORD_TYPE_ADDRESS_GROUP) {  
                 acl->u.group = group;  
         } else if (record_type == 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;  
         error = ccs_add_domain_acl(domain, &acl->head);  
         goto out;  
  delete:  
         error = -ENOENT;  
         list1_for_each_entry(ptr, &domain->acl_info_list, list) {  
                 if (ccs_acl_type2(ptr) != TYPE_IP_NETWORK_ACL)  
                         continue;  
                 if (ccs_get_condition_part(ptr) != condition)  
                         continue;  
                 acl = container_of(ptr, struct 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 == IP_RECORD_TYPE_ADDRESS_GROUP) {  
                         if (acl->u.group != group)  
                                 continue;  
                 } else if (record_type == IP_RECORD_TYPE_IPv4) {  
                         if (acl->u.ipv4.min != min_ip ||  
                             max_ip != acl->u.ipv4.max)  
                                 continue;  
                 } else if (record_type == IP_RECORD_TYPE_IPv6) {  
                         if (acl->u.ipv6.min != saved_min_address ||  
                             saved_max_address != acl->u.ipv6.max)  
                                 continue;  
                 }  
                 error = ccs_del_domain_acl(ptr);  
                 break;  
248          }          }
249   out:          ccs_read_unlock(idx);
         mutex_unlock(&lock);  
250          return error;          return error;
251  }  }
252    
253  /**  static bool ccs_same_ip_network_acl(const struct ccs_acl_info *a,
254   * check_network_entry - Check permission for network operation.                                      const struct ccs_acl_info *b)
  *  
  * @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 check_network_entry(const bool is_ipv6, const u8 operation,  
                                const u32 *address, const u16 port)  
255  {  {
256          struct ccs_request_info r;          const struct ccs_ip_network_acl *p1 = container_of(a, typeof(*p1),
257          struct acl_info *ptr;                                                             head);
258          const char *keyword = ccs_net2keyword(operation);          const struct ccs_ip_network_acl *p2 = container_of(b, typeof(*p2),
259          bool is_enforce;                                                             head);
260          /* using host byte order to allow u32 comparison than memcmp().*/          return ccs_same_acl_head(&p1->head, &p2->head)
261          const u32 ip = ntohl(*address);                  && p1->protocol == p2->protocol
262          bool found = false;                  && p1->address_type == p2->address_type &&
263          char buf[64];                  p1->address.ipv4.min == p2->address.ipv4.min &&
264          if (!ccs_can_sleep())                  p1->address.ipv6.min == p2->address.ipv6.min &&
265                  return 0;                  p1->address.ipv4.max == p2->address.ipv4.max &&
266          ccs_init_request_info(&r, NULL, CCS_TOMOYO_MAC_FOR_NETWORK);                  p1->address.ipv6.max == p2->address.ipv6.max &&
267          is_enforce = (r.mode == 3);                  p1->address.group == p2->address.group &&
268          if (!r.mode)                  ccs_same_number_union(&p1->port, &p2->port);
269                  return 0;  }
270  retry:  
271          list1_for_each_entry(ptr, &r.domain->acl_info_list, list) {  static bool ccs_merge_ip_network_acl(struct ccs_acl_info *a,
272                  struct ip_network_acl_record *acl;                                       struct ccs_acl_info *b,
273                  if (ccs_acl_type2(ptr) != TYPE_IP_NETWORK_ACL)                                       const bool is_delete)
274                          continue;  {
275                  acl = container_of(ptr, struct ip_network_acl_record, head);          u8 * const a_perm = &container_of(a, struct ccs_ip_network_acl, head)
276                  if (acl->operation_type != operation || port < acl->min_port ||                  ->perm;
277                      acl->max_port < port || !ccs_check_condition(&r, ptr))          u8 perm = *a_perm;
278                          continue;          const u8 b_perm = container_of(b, struct ccs_ip_network_acl, head)
279                  if (acl->record_type == IP_RECORD_TYPE_ADDRESS_GROUP) {                  ->perm;
280                          if (!address_matches_to_group(is_ipv6, address,          if (is_delete)
281                                                        acl->u.group))                  perm &= ~b_perm;
                                 continue;  
                 } else if (acl->record_type == 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;  
                 }  
                 ccs_update_condition(ptr);  
                 found = true;  
                 break;  
         }  
         memset(buf, 0, sizeof(buf));  
         if (is_ipv6)  
                 ccs_print_ipv6(buf, sizeof(buf),  
                                (const struct in6_addr *) address);  
282          else          else
283                  snprintf(buf, sizeof(buf) - 1, "%u.%u.%u.%u", HIPQUAD(ip));                  perm |= b_perm;
284          audit_network_log(&r, keyword, buf, port, found);          *a_perm = perm;
285          if (found)          return !perm;
                 return 0;  
         if (ccs_verbose_mode(r.domain))  
                 printk(KERN_WARNING "TOMOYO-%s: %s to %s %u denied for %s\n",  
                        ccs_get_msg(is_enforce), keyword, buf, port,  
                        ccs_get_last_name(r.domain));  
         if (is_enforce) {  
                 int error = ccs_check_supervisor(&r, KEYWORD_ALLOW_NETWORK  
                                                  "%s %s %u\n", keyword, buf,  
                                                  port);  
                 if (error == 1) {  
                         r.retry++;  
                         goto retry;  
                 }  
                 return error;  
         }  
         if (r.mode == 1 && ccs_check_domain_quota(r.domain))  
                 update_network_entry(operation, is_ipv6 ?  
                                      IP_RECORD_TYPE_IPv6 : IP_RECORD_TYPE_IPv4,  
                                      NULL, address, address, port, port,  
                                      r.domain, NULL, 0);  
         return 0;  
286  }  }
287    
288  /**  /**
289   * ccs_write_network_policy - Write "struct ip_network_acl_record" list.   * ccs_write_network - Write "struct ccs_ip_network_acl" list.
290   *   *
291   * @data:      String to parse.   * @data:      String to parse.
292   * @domain:    Pointer to "struct domain_info".   * @domain:    Pointer to "struct ccs_domain_info".
293   * @condition: Pointer to "struct condition_list". May be NULL.   * @condition: Pointer to "struct ccs_condition". Maybe NULL.
294   * @is_delete: True if it is a delete request.   * @is_delete: True if it is a delete request.
295   *   *
296   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
297   */   */
298  int ccs_write_network_policy(char *data, struct domain_info *domain,  int ccs_write_network(char *data, struct ccs_domain_info *domain,
299                               const struct condition_list *condition,                        struct ccs_condition *condition, const bool is_delete)
                              const bool is_delete)  
300  {  {
301          u8 sock_type;          struct ccs_ip_network_acl e = {
302          u8 operation;                  .head.type = CCS_TYPE_IP_NETWORK_ACL,
303          u8 record_type;                  .head.cond = condition,
304            };
305          u16 min_address[8];          u16 min_address[8];
306          u16 max_address[8];          u16 max_address[8];
307          struct address_group_entry *group = NULL;          int error = is_delete ? -ENOENT : -ENOMEM;
308          u16 min_port;          u8 type;
309          u16 max_port;          char *w[4];
310          u8 count;          if (!ccs_tokenize(data, w, sizeof(w)) || !w[3][0])
311          char *cp1 = strchr(data, ' ');                  return -EINVAL;
312          char *cp2;          for (e.protocol = 0; e.protocol < CCS_MAX_NETWORK_PROTOCOL;
313          if (!cp1)               e.protocol++)
314                  goto out;                  if (!strcmp(w[0], ccs_net_protocol_keyword[e.protocol]))
         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;  
315                          break;                          break;
316                  default:          for (type = 0; type < CCS_MAX_NETWORK_OPERATION; type++)
317                          operation = NETWORK_ACL_RAW_CONNECT;                  if (ccs_permstr(w[1], ccs_net_keyword[type]))
318                  }                          e.perm |= 1 << type;
319          else if (sock_type == SOCK_STREAM && !strncmp(cp1, "listen ", 7))          if (e.protocol == CCS_MAX_NETWORK_PROTOCOL || !e.perm)
320                  operation = NETWORK_ACL_TCP_LISTEN;                  return -EINVAL;
321          else if (sock_type == SOCK_STREAM && !strncmp(cp1, "accept ", 7))          switch (ccs_parse_ip_address(w[2], min_address, max_address)) {
322                  operation = NETWORK_ACL_TCP_ACCEPT;          case CCS_IP_ADDRESS_TYPE_IPv6:
323          else                  e.address_type = CCS_IP_ADDRESS_TYPE_IPv6;
324                  goto out;                  e.address.ipv6.min = ccs_get_ipv6_address((struct in6_addr *)
325          cp1 = strchr(cp2, ' ');                                                            min_address);
326          if (!cp1)                  e.address.ipv6.max = ccs_get_ipv6_address((struct in6_addr *)
327                  goto out;                                                            max_address);
328          *cp1++ = '\0';                  if (!e.address.ipv6.min || !e.address.ipv6.max)
329          switch (parse_ip_address(cp2, min_address, max_address)) {                          goto out;
         case 2:  
                 record_type = IP_RECORD_TYPE_IPv6;  
330                  break;                  break;
331          case 1:          case CCS_IP_ADDRESS_TYPE_IPv4:
332                  record_type = IP_RECORD_TYPE_IPv4;                  e.address_type = CCS_IP_ADDRESS_TYPE_IPv4;
333                    /* use host byte order to allow u32 comparison.*/
334                    e.address.ipv4.min = ntohl(*(u32 *) min_address);
335                    e.address.ipv4.max = ntohl(*(u32 *) max_address);
336                  break;                  break;
337          default:          default:
338                  if (*cp2 != '@')                  if (w[2][0] != '@')
339                          goto out;                          return -EINVAL;
340                  group = find_or_assign_new_address_group(cp2 + 1);                  e.address_type = CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP;
341                  if (!group)                  e.address.group = ccs_get_group(w[2] + 1, CCS_ADDRESS_GROUP);
342                    if (!e.address.group)
343                          return -ENOMEM;                          return -ENOMEM;
                 record_type = IP_RECORD_TYPE_ADDRESS_GROUP;  
344                  break;                  break;
345          }          }
346          if (strchr(cp1, ' '))          if (!ccs_parse_number_union(w[3], &e.port))
347                  goto out;                  goto out;
348          count = sscanf(cp1, "%hu-%hu", &min_port, &max_port);          error = ccs_update_domain(&e.head, sizeof(e), is_delete, domain,
349          if (count != 1 && count != 2)                                    ccs_same_ip_network_acl,
350                  goto out;                                    ccs_merge_ip_network_acl);
         if (count == 1)  
                 max_port = min_port;  
         return update_network_entry(operation, record_type, group,  
                                     (u32 *) min_address, (u32 *) max_address,  
                                     min_port, max_port, domain, condition,  
                                     is_delete);  
351   out:   out:
352          return -EINVAL;          if (e.address_type == CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP)
353                    ccs_put_group(e.address.group);
354            else if (e.address_type == CCS_IP_ADDRESS_TYPE_IPv6) {
355                    ccs_put_ipv6_address(e.address.ipv6.min);
356                    ccs_put_ipv6_address(e.address.ipv6.max);
357            }
358            ccs_put_number_union(&e.port);
359            return error;
360  }  }
361    
362  /**  #ifndef CONFIG_NET
363   * ccs_check_network_listen_acl - Check permission for listen() operation.  
364   *  void __init ccs_network_init(void)
  * @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.  
  */  
 int ccs_check_network_listen_acl(const _Bool is_ipv6, const u8 *address,  
                                  const u16 port)  
365  {  {
         return check_network_entry(is_ipv6, NETWORK_ACL_TCP_LISTEN,  
                                    (const u32 *) address, ntohs(port));  
366  }  }
367    
368  /**  #else
369   * ccs_check_network_connect_acl - Check permission for connect() operation.  
370   *  static bool ccs_check_address(const struct sockaddr *addr,
371   * @is_ipv6:   True if @address is an IPv6 address.                                const unsigned int addr_len,
372   * @sock_type: Type of socket. (TCP or UDP or RAW)                                struct ccs_addr_info *address)
373   * @address:   An IPv4 or IPv6 address.  {
374   * @port:      Port number.          switch (addr->sa_family) {
375   *          case AF_INET6:
376   * Returns 0 on success, negative value otherwise.                  if (addr_len < SIN6_LEN_RFC2133)
377   */                          goto skip;
378  int ccs_check_network_connect_acl(const _Bool is_ipv6, const int sock_type,                  address->is_ipv6 = true;
379                                    const u8 *address, const u16 port)                  address->address = (u32 *)
380                            ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr;
381                    address->port = ((struct sockaddr_in6 *) addr)->sin6_port;
382                    break;
383            case AF_INET:
384                    if (addr_len < sizeof(struct sockaddr_in))
385                            goto skip;
386                    address->is_ipv6 = false;
387                    address->address = (u32 *)
388                            &((struct sockaddr_in *) addr)->sin_addr;
389                    address->port = ((struct sockaddr_in *) addr)->sin_port;
390                    break;
391            default:
392                    goto skip;
393            }
394            return true;
395     skip:
396            return false;
397    }
398    
399    /* Check permission for creating a socket. */
400    static int __ccs_socket_create_permission(int family, int type, int protocol)
401  {  {
402          u8 operation;          /* Nothing to do if I am a kernel service. */
403          switch (sock_type) {          if (segment_eq(get_fs(), KERNEL_DS))
404                    return 0;
405            if (family == PF_PACKET && !ccs_capable(CCS_USE_PACKET_SOCKET))
406                    return -EPERM;
407            if (family == PF_ROUTE && !ccs_capable(CCS_USE_ROUTE_SOCKET))
408                    return -EPERM;
409            return 0;
410    }
411    
412    /* Check permission for listening a TCP socket. */
413    static int __ccs_socket_listen_permission(struct socket *sock)
414    {
415            struct sockaddr_storage addr;
416            int error = 0;
417            int addr_len;
418            struct ccs_addr_info address;
419            /* Nothing to do if I am a kernel service. */
420            if (segment_eq(get_fs(), KERNEL_DS))
421                    return 0;
422            if (sock->type != SOCK_STREAM)
423                    return 0;
424            switch (sock->sk->sk_family) {
425            case PF_INET:
426            case PF_INET6:
427                    break;
428            default:
429                    return 0;
430            }
431            if (sock->ops->getname(sock, (struct sockaddr *) &addr, &addr_len, 0))
432                    return -EPERM;
433            address.protocol = CCS_NETWORK_TCP_PROTOCOL;
434            address.operation = CCS_NETWORK_LISTEN;
435            if (ccs_check_address((struct sockaddr *) &addr, addr_len, &address))
436                    error = ccs_network_entry(&address);
437            return error;
438    }
439    
440    /* Check permission for setting the remote IP address/port pair of a socket. */
441    static int __ccs_socket_connect_permission(struct socket *sock,
442                                               struct sockaddr *addr, int addr_len)
443    {
444            int error = 0;
445            const unsigned int type = sock->type;
446            struct ccs_addr_info address;
447            /* Nothing to do if I am a kernel service. */
448            if (segment_eq(get_fs(), KERNEL_DS))
449                    return 0;
450            switch (type) {
451          case SOCK_STREAM:          case SOCK_STREAM:
452                  operation = NETWORK_ACL_TCP_CONNECT;                  address.protocol = CCS_NETWORK_TCP_PROTOCOL;
453                  break;                  break;
454          case SOCK_DGRAM:          case SOCK_DGRAM:
455                  operation = NETWORK_ACL_UDP_CONNECT;                  address.protocol = CCS_NETWORK_UDP_PROTOCOL;
456                    break;
457            case SOCK_RAW:
458                    address.protocol = CCS_NETWORK_RAW_PROTOCOL;
459                  break;                  break;
460          default:          default:
461                  operation = NETWORK_ACL_RAW_CONNECT;                  return 0;
462          }          }
463          return check_network_entry(is_ipv6, operation, (const u32 *) address,          address.operation = CCS_NETWORK_CONNECT;
464                                     ntohs(port));          if (!ccs_check_address(addr, addr_len, &address))
465                    goto skip;
466            if (type == SOCK_RAW)
467                    address.port = htons(sock->sk->sk_protocol);
468            error = ccs_network_entry(&address);
469     skip:
470            return error;
471  }  }
472    
473  /**  /* Check permission for setting the local IP address/port pair of a socket. */
474   * ccs_check_network_bind_acl - Check permission for bind() operation.  static int __ccs_socket_bind_permission(struct socket *sock,
475   *                                          struct sockaddr *addr, int addr_len)
476   * @is_ipv6:   True if @address is an IPv6 address.  {
477   * @sock_type: Type of socket. (TCP or UDP or RAW)          int error = 0;
478   * @address:   An IPv4 or IPv6 address.          const unsigned int type = sock->type;
479   * @port:      Port number.          struct ccs_addr_info address;
480   *          /* Nothing to do if I am a kernel service. */
481   * Returns 0 on success, negative value otherwise.          if (segment_eq(get_fs(), KERNEL_DS))
482   */                  return 0;
483  int ccs_check_network_bind_acl(const _Bool is_ipv6, const int sock_type,          switch (type) {
                                const u8 *address, const u16 port)  
 {  
         u8 operation;  
         switch (sock_type) {  
484          case SOCK_STREAM:          case SOCK_STREAM:
485                  operation = NETWORK_ACL_TCP_BIND;                  address.protocol = CCS_NETWORK_TCP_PROTOCOL;
486                  break;                  break;
487          case SOCK_DGRAM:          case SOCK_DGRAM:
488                  operation = NETWORK_ACL_UDP_BIND;                  address.protocol = CCS_NETWORK_UDP_PROTOCOL;
489                    break;
490            case SOCK_RAW:
491                    address.protocol = CCS_NETWORK_RAW_PROTOCOL;
492                  break;                  break;
493          default:          default:
494                  operation = NETWORK_ACL_RAW_BIND;                  return 0;
495          }          }
496          return check_network_entry(is_ipv6, operation, (const u32 *) address,          address.operation = CCS_NETWORK_BIND;
497                                     ntohs(port));          if (!ccs_check_address(addr, addr_len, &address))
498                    goto skip;
499            if (type == SOCK_RAW)
500                    address.port = htons(sock->sk->sk_protocol);
501            error = ccs_network_entry(&address);
502     skip:
503            return error;
504  }  }
505    
506  /**  /* Check permission for accepting a TCP socket. */
507   * ccs_check_network_accept_acl - Check permission for accept() operation.  static int __ccs_socket_post_accept_permission(struct socket *sock,
508   *                                                 struct socket *newsock)
509   * @is_ipv6: True if @address is an IPv6 address.  {
510   * @address: An IPv4 or IPv6 address.          struct sockaddr_storage addr;
511   * @port:    Port number.          struct task_struct * const task = current;
512   *          int error = 0;
513   * Returns 0 on success, negative value otherwise.          int addr_len;
514   */          struct ccs_addr_info address;
515  int ccs_check_network_accept_acl(const _Bool is_ipv6, const u8 *address,          /* Nothing to do if I am a kernel service. */
516                                   const u16 port)          if (segment_eq(get_fs(), KERNEL_DS))
517                    return 0;
518            switch (newsock->sk->sk_family) {
519            case PF_INET:
520            case PF_INET6:
521                    break;
522            default:
523                    return 0;
524            }
525            error = newsock->ops->getname(newsock, (struct sockaddr *) &addr,
526                                          &addr_len, 2);
527            if (error)
528                    return error;
529            if (!ccs_check_address((struct sockaddr *) &addr, addr_len,
530                                   &address))
531                    goto skip;
532            address.protocol = CCS_NETWORK_TCP_PROTOCOL;
533            address.operation = CCS_NETWORK_ACCEPT;
534            task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
535            error = ccs_network_entry(&address);
536            task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
537     skip:
538            return error;
539    }
540    
541    /* Check permission for sending a datagram via a UDP or RAW socket. */
542    static int __ccs_socket_sendmsg_permission(struct socket *sock,
543                                               struct msghdr *msg, int size)
544    {
545            int error = 0;
546            const int type = sock->type;
547            struct ccs_addr_info address;
548            if (!msg->msg_name)
549                    return 0;
550            /* Nothing to do if I am a kernel service. */
551            if (segment_eq(get_fs(), KERNEL_DS))
552                    return 0;
553            switch (type) {
554            case SOCK_DGRAM:
555                    address.protocol = CCS_NETWORK_UDP_PROTOCOL;
556                    break;
557            case SOCK_RAW:
558                    address.protocol = CCS_NETWORK_RAW_PROTOCOL;
559                    break;
560            default:
561                    return 0;
562            }
563            address.operation = CCS_NETWORK_SEND;
564            if (!ccs_check_address((struct sockaddr *) msg->msg_name,
565                                   msg->msg_namelen, &address))
566                    goto skip;
567            if (type == SOCK_RAW)
568                    address.port = htons(sock->sk->sk_protocol);
569            error = ccs_network_entry(&address);
570     skip:
571            return error;
572    }
573    
574    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
575    #if !defined(RHEL_MAJOR) || RHEL_MAJOR != 5
576    #if !defined(AX_MAJOR) || AX_MAJOR != 3 || !defined(AX_MINOR) || AX_MINOR < 2
577    
578    static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
579  {  {
580          int retval;          return skb->nh.iph;
         current->tomoyo_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;  
         retval = check_network_entry(is_ipv6, NETWORK_ACL_TCP_ACCEPT,  
                                      (const u32 *) address, ntohs(port));  
         current->tomoyo_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;  
         return retval;  
581  }  }
582    
583  /**  static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
  * ccs_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.  
  */  
 int ccs_check_network_sendmsg_acl(const _Bool is_ipv6, const int sock_type,  
                                   const u8 *address, const u16 port)  
584  {  {
585          u8 operation;          return skb->h.uh;
586          if (sock_type == SOCK_DGRAM)  }
587                  operation = NETWORK_ACL_UDP_CONNECT;  
588    static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb)
589    {
590            return skb->nh.ipv6h;
591    }
592    
593    #endif
594    #endif
595    #endif
596    
597    /* Check permission for receiving a datagram via a UDP or RAW socket. */
598    static int __ccs_socket_post_recvmsg_permission(struct sock *sk,
599                                                    struct sk_buff *skb)
600    {
601            struct task_struct * const task = current;
602            int error = 0;
603            const unsigned int type = sk->sk_type;
604            struct ccs_addr_info address;
605            union {
606                    struct in6_addr sin6;
607                    struct in_addr sin4;
608            } ip_address;
609            switch (type) {
610            case SOCK_DGRAM:
611                    address.protocol = CCS_NETWORK_UDP_PROTOCOL;
612                    break;
613            case SOCK_RAW:
614                    address.protocol = CCS_NETWORK_RAW_PROTOCOL;
615                    break;
616            default:
617                    return 0;
618            }
619            /* Nothing to do if I am a kernel service. */
620            if (segment_eq(get_fs(), KERNEL_DS))
621                    return 0;
622            switch (sk->sk_family) {
623            case PF_INET6:
624                    address.is_ipv6 = true;
625                    if (type == SOCK_DGRAM && skb->protocol == htons(ETH_P_IP))
626                            ipv6_addr_set(&ip_address.sin6, 0, 0, htonl(0xffff),
627                                          ip_hdr(skb)->saddr);
628                    else
629                            ipv6_addr_copy(&ip_address.sin6, &ipv6_hdr(skb)->saddr);
630                    break;
631            case PF_INET:
632                    address.is_ipv6 = false;
633                    ip_address.sin4.s_addr = ip_hdr(skb)->saddr;
634                    break;
635            default:
636                    goto skip;
637            }
638            address.address = (u32 *) &ip_address;
639            if (type == SOCK_DGRAM)
640                    address.port = udp_hdr(skb)->source;
641          else          else
642                  operation = NETWORK_ACL_RAW_CONNECT;                  address.port = htons(sk->sk_protocol);
643          return check_network_entry(is_ipv6, operation, (const u32 *) address,          address.operation = CCS_NETWORK_RECV;
644                                     ntohs(port));          task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
645            error = ccs_network_entry(&address);
646            task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
647     skip:
648            return error;
649  }  }
650    
651  /**  void __init ccs_network_init(void)
  * ccs_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.  
  */  
 int ccs_check_network_recvmsg_acl(const _Bool is_ipv6, const int sock_type,  
                                   const u8 *address, const u16 port)  
652  {  {
653          int retval;          ccsecurity_ops.socket_create_permission =
654          const u8 operation                  __ccs_socket_create_permission;
655                  = (sock_type == SOCK_DGRAM) ?          ccsecurity_ops.socket_listen_permission =
656                  NETWORK_ACL_UDP_CONNECT : NETWORK_ACL_RAW_CONNECT;                  __ccs_socket_listen_permission;
657          current->tomoyo_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;          ccsecurity_ops.socket_connect_permission =
658          retval = check_network_entry(is_ipv6, operation, (const u32 *) address,                  __ccs_socket_connect_permission;
659                                       ntohs(port));          ccsecurity_ops.socket_bind_permission = __ccs_socket_bind_permission;
660          current->tomoyo_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;          ccsecurity_ops.socket_post_accept_permission =
661          return retval;                  __ccs_socket_post_accept_permission;
662            ccsecurity_ops.socket_sendmsg_permission =
663                    __ccs_socket_sendmsg_permission;
664            ccsecurity_ops.socket_post_recvmsg_permission =
665                    __ccs_socket_post_recvmsg_permission;
666  }  }
667    
668    #endif

Legend:
Removed from v.1719  
changed lines
  Added in v.3875

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26