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

Subversion リポジトリの参照

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

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

revision 2918 by kumaneko, Tue Aug 18 05:21:21 2009 UTC revision 3871 by kumaneko, Sun Aug 1 01:42:05 2010 UTC
# Line 1  Line 1 
1  /*  /*
2   * security/ccsecurity/network.c   * security/ccsecurity/network.c
3   *   *
4   * Copyright (C) 2005-2009  NTT DATA CORPORATION   * Copyright (C) 2005-2010  NTT DATA CORPORATION
5   *   *
6   * Version: 1.7.0-pre   2009/08/08   * Version: 1.8.0-pre   2010/08/01
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.
# Line 19  Line 19 
19  #include <net/udp.h>  #include <net/udp.h>
20  #include "internal.h"  #include "internal.h"
21    
22    struct ccs_addr_info {
23            u8 protocol;
24            u8 operation;
25            u16 port;           /* In network byte order. */
26            const u32 *address; /* In network byte order. */
27            bool is_ipv6;
28    };
29    
30    const char *ccs_net_protocol_keyword[CCS_MAX_NETWORK_PROTOCOL] = {
31            [CCS_NETWORK_TCP_PROTOCOL] = "TCP",
32            [CCS_NETWORK_UDP_PROTOCOL] = "UDP",
33            [CCS_NETWORK_RAW_PROTOCOL] = "RAW",
34    };
35    
36    const char *ccs_net_keyword[CCS_MAX_NETWORK_OPERATION] = {
37            [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   * ccs_audit_network_log - Audit network log.   * ccs_audit_network_log - Audit network log.
47   *   *
48   * @r:          Pointer to "struct ccs_request_info".   * @r: Pointer to "struct ccs_request_info".
  * @operation:  The name of operation.  
  * @address:    An IPv4 or IPv6 address.  
  * @port:       Port number.  
  * @is_granted: True if this is a granted log.  
49   *   *
50   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
51   */   */
52  static int ccs_audit_network_log(struct ccs_request_info *r,  static int ccs_audit_network_log(struct ccs_request_info *r)
53                                   const char *operation, const char *address,  {
54                                   const u16 port, const bool is_granted)          char buf[128];
55  {          const char *protocol =
56          if (!is_granted && ccs_verbose_mode(r->domain))                  ccs_net_protocol_keyword[r->param.network.protocol];
57                  printk(KERN_WARNING "%s: %s to %s %u denied for %s\n",          const char *operation = ccs_net_keyword[r->param.network.operation];
58                         ccs_get_msg(r->mode == 3), operation, address, port,          const u32 *address = r->param.network.address;
59                         ccs_get_last_name(r->domain));          const u16 port = r->param.network.port;
60          return ccs_write_audit_log(is_granted, r, CCS_KEYWORD_ALLOW_NETWORK          if (r->param.network.is_ipv6)
61                                     "%s %s %u\n", operation, address, port);                  ccs_print_ipv6(buf, sizeof(buf), (const struct in6_addr *)
62                                   address, (const struct in6_addr *) address);
63            else
64                    ccs_print_ipv4(buf, sizeof(buf), r->param.network.ip,
65                                   r->param.network.ip);
66            ccs_write_log(r, "network %s %s %s %u\n", protocol, operation, buf,
67                          port);
68            if (r->granted)
69                    return 0;
70            ccs_warn_log(r, "network %s %s %s %u", protocol, operation, buf, port);
71            return ccs_supervisor(r, "network %s %s %s %u\n", protocol, operation,
72                                  buf, port);
73  }  }
74    
75  /**  /**
# Line 49  static int ccs_audit_network_log(struct Line 79  static int ccs_audit_network_log(struct
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  int ccs_parse_ip_address(char *address, u16 *min, u16 *max)  int ccs_parse_ip_address(char *address, u16 *min, u16 *max)
87  {  {
# Line 67  int ccs_parse_ip_address(char *address, Line 99  int ccs_parse_ip_address(char *address,
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 77  int ccs_parse_ip_address(char *address, Line 109  int ccs_parse_ip_address(char *address,
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;
117          }          }
118          return 0;          return CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP;
119  }  }
120    
 #if !defined(NIP6)  
 #define NIP6(addr)      \  
         ntohs((addr).s6_addr16[0]), ntohs((addr).s6_addr16[1]), \  
         ntohs((addr).s6_addr16[2]), ntohs((addr).s6_addr16[3]), \  
         ntohs((addr).s6_addr16[4]), ntohs((addr).s6_addr16[5]), \  
         ntohs((addr).s6_addr16[6]), ntohs((addr).s6_addr16[7])  
 #endif  
   
121  /**  /**
122   * ccs_print_ipv6 - Print an IPv6 address.   * ccs_print_ipv4 - Print an IPv4 address.
123   *   *
124   * @buffer:     Buffer to write to.   * @buffer:     Buffer to write to.
125   * @buffer_len: Size of @buffer.   * @buffer_len: Size of @buffer.
126   * @ip:         Pointer to "struct in6_addr".   * @min_ip:     Min address in host byte order.
127     * @max_ip:     Max address in host byte order.
128   *   *
129   * Returns nothing.   * Returns nothing.
130   */   */
131  void ccs_print_ipv6(char *buffer, const int buffer_len,  void ccs_print_ipv4(char *buffer, const int buffer_len,
132                      const struct in6_addr *ip)                      const u32 min_ip, const u32 max_ip)
133  {  {
134          memset(buffer, 0, buffer_len);          memset(buffer, 0, buffer_len);
135          snprintf(buffer, buffer_len - 1, "%x:%x:%x:%x:%x:%x:%x:%x", NIP6(*ip));          snprintf(buffer, buffer_len - 1, "%u.%u.%u.%u%c%u.%u.%u.%u",
136                     HIPQUAD(min_ip), min_ip == max_ip ? '\0' : '-',
137                     HIPQUAD(max_ip));
138  }  }
139    
140    #if !defined(NIP6)
141    #define NIP6(addr)                                                      \
142            ntohs((addr).s6_addr16[0]), ntohs((addr).s6_addr16[1]),         \
143                    ntohs((addr).s6_addr16[2]), ntohs((addr).s6_addr16[3]), \
144                    ntohs((addr).s6_addr16[4]), ntohs((addr).s6_addr16[5]), \
145                    ntohs((addr).s6_addr16[6]), ntohs((addr).s6_addr16[7])
146    #endif
147    
148  /**  /**
149   * ccs_net2keyword - Convert network operation index to network operation name.   * ccs_print_ipv6 - Print an IPv6 address.
150   *   *
151   * @operation: Type of operation.   * @buffer:     Buffer to write to.
152     * @buffer_len: Size of @buffer.
153     * @min_ip:     Pointer to "struct in6_addr".
154     * @max_ip:     Pointer to "struct in6_addr".
155   *   *
156   * Returns the name of operation.   * Returns nothing.
157   */   */
158  const char *ccs_net2keyword(const u8 operation)  void ccs_print_ipv6(char *buffer, const int buffer_len,
159                        const struct in6_addr *min_ip,
160                        const struct in6_addr *max_ip)
161  {  {
162          const char *keyword = "unknown";          memset(buffer, 0, buffer_len);
163          switch (operation) {          snprintf(buffer, buffer_len - 1,
164          case CCS_NETWORK_UDP_BIND:                   "%x:%x:%x:%x:%x:%x:%x:%x%c%x:%x:%x:%x:%x:%x:%x:%x",
165                  keyword = "UDP bind";                   NIP6(*min_ip), min_ip == max_ip ? '\0' : '-',
166                  break;                   NIP6(*max_ip));
167          case CCS_NETWORK_UDP_CONNECT:  }
168                  keyword = "UDP connect";  
169                  break;  static bool ccs_check_network_acl(struct ccs_request_info *r,
170          case CCS_NETWORK_TCP_BIND:                                    const struct ccs_acl_info *ptr)
171                  keyword = "TCP bind";  {
172                  break;          const struct ccs_ip_network_acl *acl =
173          case CCS_NETWORK_TCP_LISTEN:                  container_of(ptr, typeof(*acl), head);
174                  keyword = "TCP listen";          bool ret;
175                  break;          if (!(acl->perm & (1 << r->param.network.operation)) ||
176          case CCS_NETWORK_TCP_CONNECT:              !ccs_compare_number_union(r->param.network.port, &acl->port))
177                  keyword = "TCP connect";                  return false;
178                  break;          switch (acl->address_type) {
179          case CCS_NETWORK_TCP_ACCEPT:          case CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP:
180                  keyword = "TCP accept";                  ret = ccs_address_matches_group(r->param.network.is_ipv6,
181                  break;                                                  r->param.network.address,
182          case CCS_NETWORK_RAW_BIND:                                                  acl->address.group);
183                  keyword = "RAW bind";                  break;
184                  break;          case CCS_IP_ADDRESS_TYPE_IPv4:
185          case CCS_NETWORK_RAW_CONNECT:                  ret = !r->param.network.is_ipv6 &&
186                  keyword = "RAW connect";                          acl->address.ipv4.min <= r->param.network.ip &&
187                            r->param.network.ip <= acl->address.ipv4.max;
188                  break;                  break;
189          }          default:
190          return keyword;                  ret = r->param.network.is_ipv6 &&
191  }                          memcmp(acl->address.ipv6.min, r->param.network.address,
192                                   16) <= 0 &&
193                            memcmp(r->param.network.address, acl->address.ipv6.max,
194                                   16) <= 0;
195                    break;
196            }
197            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   * ccs_check_network_entry2 - Check permission for network operation.   * ccs_network_entry - Check permission for network operation.
224   *   *
225   * @is_ipv6:   True if @address is an IPv6 address.   * @address: Pointer to "struct ccs_ip_address".
  * @operation: Type of operation.  
  * @address:   An IPv4 or IPv6 address.  
  * @port:      Port number.  
226   *   *
227   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
  *  
  * Caller holds ccs_read_lock().  
228   */   */
229  static int ccs_check_network_entry2(const bool is_ipv6, const u8 operation,  static int ccs_network_entry(const struct ccs_addr_info *address)
                                     const u32 *address, const u16 port)  
230  {  {
231            const int idx = ccs_read_lock();
232          struct ccs_request_info r;          struct ccs_request_info r;
233          struct ccs_acl_info *ptr;          int error = 0;
234          const char *keyword = ccs_net2keyword(operation);          const u8 type = ccs_net2mac[address->protocol][address->operation];
235          bool is_enforce;          if (!type || ccs_init_request_info(&r, type) != CCS_CONFIG_DISABLED) {
236          const u16 perm = 1 << operation;                  r.param_type = CCS_TYPE_IP_NETWORK_ACL;
237          /* using host byte order to allow u32 comparison than memcmp().*/                  r.param.network.protocol = address->protocol;
238          const u32 ip = ntohl(*address);                  r.param.network.operation = address->operation;
239          int error;                  r.param.network.is_ipv6 = address->is_ipv6;
240          char buf[64];                  r.param.network.address = address->address;
241          ccs_check_read_lock();                  r.param.network.port = ntohs(address->port);
242          if (!ccs_can_sleep() ||                  /* use host byte order to allow u32 comparison than memcmp().*/
243              !ccs_init_request_info(&r, NULL, CCS_MAC_NETWORK))                  r.param.network.ip = ntohl(*address->address);
244                  return 0;                  do {
245          is_enforce = (r.mode == 3);                          ccs_check_acl(&r, ccs_check_network_acl);
246   retry:                          error = ccs_audit_network_log(&r);
247          error = -EPERM;                  } while (error == CCS_RETRY_REQUEST);
         list_for_each_entry_rcu(ptr, &r.domain->acl_info_list, list) {  
                 struct ccs_ip_network_acl *acl;  
                 if (ptr->is_deleted || ptr->type != CCS_TYPE_IP_NETWORK_ACL)  
                         continue;  
                 acl = container_of(ptr, struct ccs_ip_network_acl, head);  
                 if (!(acl->perm & perm))  
                         continue;  
                 if (!ccs_compare_number_union(port, &acl->port) ||  
                     !ccs_check_condition(&r, ptr))  
                         continue;  
                 if (acl->address_type == CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP) {  
                         if (!ccs_address_matches_group(is_ipv6, address,  
                                                        acl->address.group))  
                                 continue;  
                 } else if (acl->address_type == CCS_IP_ADDRESS_TYPE_IPv4) {  
                         if (is_ipv6 ||  
                             ip < acl->address.ipv4.min ||  
                             acl->address.ipv4.max < ip)  
                                 continue;  
                 } else {  
                         if (!is_ipv6 ||  
                             memcmp(acl->address.ipv6.min, address, 16) > 0 ||  
                             memcmp(address, acl->address.ipv6.max, 16) > 0)  
                                 continue;  
                 }  
                 r.cond = ptr->cond;  
                 error = 0;  
                 break;  
248          }          }
249          memset(buf, 0, sizeof(buf));          ccs_read_unlock(idx);
         if (is_ipv6)  
                 ccs_print_ipv6(buf, sizeof(buf),  
                                (const struct in6_addr *) address);  
         else  
                 snprintf(buf, sizeof(buf) - 1, "%u.%u.%u.%u", HIPQUAD(ip));  
         ccs_audit_network_log(&r, keyword, buf, port, !error);  
         if (error)  
                 error = ccs_check_supervisor(&r, CCS_KEYWORD_ALLOW_NETWORK  
                                              "%s %s %u\n", keyword, buf, port);  
         if (error == 1)  
                 goto retry;  
         if (!is_enforce)  
                 error = 0;  
250          return error;          return error;
251  }  }
252    
253  /**  static bool ccs_same_ip_network_acl(const struct ccs_acl_info *a,
254   * ccs_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 ccs_check_network_entry(const bool is_ipv6, const u8 operation,  
                                    const u32 *address, const u16 port)  
255  {  {
256          const int idx = ccs_read_lock();          const struct ccs_ip_network_acl *p1 = container_of(a, typeof(*p1),
257          const int error = ccs_check_network_entry2(is_ipv6, operation,                                                             head);
258                                                     address, port);          const struct ccs_ip_network_acl *p2 = container_of(b, typeof(*p2),
259          ccs_read_unlock(idx);                                                             head);
260          return error;          return ccs_same_acl_head(&p1->head, &p2->head)
261                    && p1->protocol == p2->protocol
262                    && p1->address_type == p2->address_type &&
263                    p1->address.ipv4.min == p2->address.ipv4.min &&
264                    p1->address.ipv6.min == p2->address.ipv6.min &&
265                    p1->address.ipv4.max == p2->address.ipv4.max &&
266                    p1->address.ipv6.max == p2->address.ipv6.max &&
267                    p1->address.group == p2->address.group &&
268                    ccs_same_number_union(&p1->port, &p2->port);
269    }
270    
271    static bool ccs_merge_ip_network_acl(struct ccs_acl_info *a,
272                                         struct ccs_acl_info *b,
273                                         const bool is_delete)
274    {
275            u8 * const a_perm = &container_of(a, struct ccs_ip_network_acl, head)
276                    ->perm;
277            u8 perm = *a_perm;
278            const u8 b_perm = container_of(b, struct ccs_ip_network_acl, head)
279                    ->perm;
280            if (is_delete)
281                    perm &= ~b_perm;
282            else
283                    perm |= b_perm;
284            *a_perm = perm;
285            return !perm;
286  }  }
287    
288  /**  /**
289   * ccs_write_network_policy - Write "struct ccs_ip_network_acl" 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 ccs_domain_info".   * @domain:    Pointer to "struct ccs_domain_info".
293   * @condition: Pointer to "struct ccs_condition". 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 ccs_domain_info *domain,  int ccs_write_network(char *data, struct ccs_domain_info *domain,
299                               struct ccs_condition *condition,                        struct ccs_condition *condition, const bool is_delete)
                              const bool is_delete)  
300  {  {
         struct ccs_ip_network_acl *entry = NULL;  
         struct ccs_acl_info *ptr;  
301          struct ccs_ip_network_acl e = {          struct ccs_ip_network_acl e = {
302                  .head.type = CCS_TYPE_IP_NETWORK_ACL,                  .head.type = CCS_TYPE_IP_NETWORK_ACL,
303                  .head.cond = condition,                  .head.cond = condition,
# Line 268  int ccs_write_network_policy(char *data, Line 305  int ccs_write_network_policy(char *data,
305          u16 min_address[8];          u16 min_address[8];
306          u16 max_address[8];          u16 max_address[8];
307          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
308          u8 sock_type;          u8 type;
309          char *w[4];          char *w[4];
310          if (!ccs_tokenize(data, w, sizeof(w)) || !w[3][0])          if (!ccs_tokenize(data, w, sizeof(w)) || !w[3][0])
311                  return -EINVAL;                  return -EINVAL;
312          if (!strcmp(w[0], "TCP"))          for (e.protocol = 0; e.protocol < CCS_MAX_NETWORK_PROTOCOL;
313                  sock_type = SOCK_STREAM;               e.protocol++)
314          else if (!strcmp(w[0], "UDP"))                  if (!strcmp(w[0], ccs_net_protocol_keyword[e.protocol]))
315                  sock_type = SOCK_DGRAM;                          break;
316          else if (!strcmp(w[0], "RAW"))          for (type = 0; type < CCS_MAX_NETWORK_OPERATION; type++)
317                  sock_type = SOCK_RAW;                  if (ccs_permstr(w[1], ccs_net_keyword[type]))
318          else                          e.perm |= 1 << type;
319                  return -EINVAL;          if (e.protocol == CCS_MAX_NETWORK_PROTOCOL || !e.perm)
         if (!strcmp(w[1], "bind"))  
                 switch (sock_type) {  
                 case SOCK_STREAM:  
                         e.perm = 1 << CCS_NETWORK_TCP_BIND;  
                         break;  
                 case SOCK_DGRAM:  
                         e.perm = 1 << CCS_NETWORK_UDP_BIND;  
                         break;  
                 default:  
                         e.perm = 1 << CCS_NETWORK_RAW_BIND;  
                         break;  
                 }  
         else if (!strcmp(w[1], "connect"))  
                 switch (sock_type) {  
                 case SOCK_STREAM:  
                         e.perm = 1 << CCS_NETWORK_TCP_CONNECT;  
                         break;  
                 case SOCK_DGRAM:  
                         e.perm = 1 << CCS_NETWORK_UDP_CONNECT;  
                         break;  
                 default:  
                         e.perm = 1 << CCS_NETWORK_RAW_CONNECT;  
                         break;  
                 }  
         else if (sock_type == SOCK_STREAM && !strcmp(w[1], "listen"))  
                 e.perm = 1 << CCS_NETWORK_TCP_LISTEN;  
         else if (sock_type == SOCK_STREAM && !strcmp(w[1], "accept"))  
                 e.perm = 1 << CCS_NETWORK_TCP_ACCEPT;  
         else  
320                  return -EINVAL;                  return -EINVAL;
321          switch (ccs_parse_ip_address(w[2], min_address, max_address)) {          switch (ccs_parse_ip_address(w[2], min_address, max_address)) {
322          case 2:          case CCS_IP_ADDRESS_TYPE_IPv6:
323                  e.address_type = CCS_IP_ADDRESS_TYPE_IPv6;                  e.address_type = CCS_IP_ADDRESS_TYPE_IPv6;
324                  e.address.ipv6.min = ccs_get_ipv6_address((struct in6_addr *)                  e.address.ipv6.min = ccs_get_ipv6_address((struct in6_addr *)
325                                                            min_address);                                                            min_address);
# Line 320  int ccs_write_network_policy(char *data, Line 328  int ccs_write_network_policy(char *data,
328                  if (!e.address.ipv6.min || !e.address.ipv6.max)                  if (!e.address.ipv6.min || !e.address.ipv6.max)
329                          goto out;                          goto out;
330                  break;                  break;
331          case 1:          case CCS_IP_ADDRESS_TYPE_IPv4:
332                  e.address_type = CCS_IP_ADDRESS_TYPE_IPv4;                  e.address_type = CCS_IP_ADDRESS_TYPE_IPv4;
333                  /* use host byte order to allow u32 comparison.*/                  /* use host byte order to allow u32 comparison.*/
334                  e.address.ipv4.min = ntohl(* (u32 *) min_address);                  e.address.ipv4.min = ntohl(*(u32 *) min_address);
335                  e.address.ipv4.max = ntohl(* (u32 *) max_address);                  e.address.ipv4.max = ntohl(*(u32 *) max_address);
336                  break;                  break;
337          default:          default:
338                  if (w[2][0] != '@')                  if (w[2][0] != '@')
339                          return -EINVAL;                          return -EINVAL;
340                  e.address_type = CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP;                  e.address_type = CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP;
341                  e.address.group = ccs_get_address_group(w[2] + 1);                  e.address.group = ccs_get_group(w[2] + 1, CCS_ADDRESS_GROUP);
342                  if (!e.address.group)                  if (!e.address.group)
343                          return -ENOMEM;                          return -ENOMEM;
344                  break;                  break;
345          }          }
346          if (!ccs_parse_number_union(w[3], &e.port))          if (!ccs_parse_number_union(w[3], &e.port))
347                  goto out;                  goto out;
348          if (!is_delete)          error = ccs_update_domain(&e.head, sizeof(e), is_delete, domain,
349                  entry = kmalloc(sizeof(e), GFP_KERNEL);                                    ccs_same_ip_network_acl,
350          mutex_lock(&ccs_policy_lock);                                    ccs_merge_ip_network_acl);
         list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {  
                 struct ccs_ip_network_acl *acl =  
                         container_of(ptr, struct ccs_ip_network_acl,  
                                      head);  
                 if (ptr->type != CCS_TYPE_IP_NETWORK_ACL ||  
                     ptr->cond != condition ||  
                     ccs_memcmp(acl, &e, offsetof(typeof(e), address_type),  
                                sizeof(e)))  
                         continue;  
                 if (is_delete) {  
                         acl->perm &= ~e.perm;  
                         if (!acl->perm)  
                                 ptr->is_deleted = true;  
                 } else {  
                         if (ptr->is_deleted)  
                                 acl->perm = 0;  
                         acl->perm |= e.perm;  
                         ptr->is_deleted = false;  
                 }  
                 error = 0;  
                 break;  
         }  
         if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {  
                 ccs_add_domain_acl(domain, &entry->head);  
                 entry = NULL;  
                 error = 0;  
         }  
         mutex_unlock(&ccs_policy_lock);  
351   out:   out:
352          if (w[2][0] == '@')          if (e.address_type == CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP)
353                  ccs_put_address_group(e.address.group);                  ccs_put_group(e.address.group);
354          else if (e.address_type == CCS_IP_ADDRESS_TYPE_IPv6) {          else if (e.address_type == CCS_IP_ADDRESS_TYPE_IPv6) {
355                  ccs_put_ipv6_address(e.address.ipv6.min);                  ccs_put_ipv6_address(e.address.ipv6.min);
356                  ccs_put_ipv6_address(e.address.ipv6.max);                  ccs_put_ipv6_address(e.address.ipv6.max);
357          }          }
358          ccs_put_number_union(&e.port);          ccs_put_number_union(&e.port);
         kfree(entry);  
359          return error;          return error;
360  }  }
361    
362  /**  #ifndef CONFIG_NET
  * ccs_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 ccs_check_network_listen_acl(const bool is_ipv6,  
                                                const u8 *address,  
                                                const u16 port)  
 {  
         return ccs_check_network_entry(is_ipv6, CCS_NETWORK_TCP_LISTEN,  
                                        (const u32 *) address, ntohs(port));  
 }  
363    
364  /**  void __init ccs_network_init(void)
  * ccs_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 ccs_check_network_connect_acl(const bool is_ipv6,  
                                                 const int sock_type,  
                                                 const u8 *address,  
                                                 const u16 port)  
365  {  {
         u8 operation;  
         switch (sock_type) {  
         case SOCK_STREAM:  
                 operation = CCS_NETWORK_TCP_CONNECT;  
                 break;  
         case SOCK_DGRAM:  
                 operation = CCS_NETWORK_UDP_CONNECT;  
                 break;  
         default:  
                 operation = CCS_NETWORK_RAW_CONNECT;  
         }  
         return ccs_check_network_entry(is_ipv6, operation,  
                                        (const u32 *) address, ntohs(port));  
366  }  }
367    
368  /**  #else
369   * ccs_check_network_bind_acl - Check permission for bind() 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)
  * @address:   An IPv4 or IPv6 address.  
  * @port:      Port number.  
  *  
  * Returns 0 on success, negative value otherwise.  
  */  
 static int ccs_check_network_bind_acl(const bool is_ipv6, const int sock_type,  
                                       const u8 *address, const u16 port)  
373  {  {
374          u8 operation;          switch (addr->sa_family) {
375          switch (sock_type) {          case AF_INET6:
376          case SOCK_STREAM:                  if (addr_len < SIN6_LEN_RFC2133)
377                  operation = CCS_NETWORK_TCP_BIND;                          goto skip;
378                    address->is_ipv6 = true;
379                    address->address = (u32 *)
380                            ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr;
381                    address->port = ((struct sockaddr_in6 *) addr)->sin6_port;
382                  break;                  break;
383          case SOCK_DGRAM:          case AF_INET:
384                  operation = CCS_NETWORK_UDP_BIND;                  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;                  break;
391          default:          default:
392                  operation = CCS_NETWORK_RAW_BIND;                  goto skip;
393          }          }
394          return ccs_check_network_entry(is_ipv6, operation,          return true;
395                                         (const u32 *) address, ntohs(port));   skip:
396            return false;
397  }  }
398    
 /**  
  * ccs_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 ccs_check_network_accept_acl(const bool is_ipv6,  
                                                const u8 *address,  
                                                const u16 port)  
 {  
         int retval;  
         current->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;  
         retval = ccs_check_network_entry(is_ipv6, CCS_NETWORK_TCP_ACCEPT,  
                                          (const u32 *) address, ntohs(port));  
         current->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;  
         return retval;  
 }  
   
 /**  
  * 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.  
  */  
 static inline int ccs_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 = CCS_NETWORK_UDP_CONNECT;  
         else  
                 operation = CCS_NETWORK_RAW_CONNECT;  
         return ccs_check_network_entry(is_ipv6, operation,  
                                        (const u32 *) address, ntohs(port));  
 }  
   
 /**  
  * 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.  
  */  
 static inline int ccs_check_network_recvmsg_acl(const bool is_ipv6,  
                                                 const int sock_type,  
                                                 const u8 *address,  
                                                 const u16 port)  
 {  
         int retval;  
         const u8 operation  
                 = (sock_type == SOCK_DGRAM) ?  
                 CCS_NETWORK_UDP_CONNECT : CCS_NETWORK_RAW_CONNECT;  
         current->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;  
         retval = ccs_check_network_entry(is_ipv6, operation,  
                                          (const u32 *) address, ntohs(port));  
         current->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;  
         return retval;  
 }  
   
 #define MAX_SOCK_ADDR 128 /* net/socket.c */  
   
399  /* Check permission for creating a socket. */  /* Check permission for creating a socket. */
400  int ccs_socket_create_permission(int family, int type, int protocol)  static int __ccs_socket_create_permission(int family, int type, int protocol)
401  {  {
         int error = 0;  
402          /* Nothing to do if I am a kernel service. */          /* Nothing to do if I am a kernel service. */
403          if (segment_eq(get_fs(), KERNEL_DS))          if (segment_eq(get_fs(), KERNEL_DS))
404                  return 0;                  return 0;
# Line 539  int ccs_socket_create_permission(int fam Line 406  int ccs_socket_create_permission(int fam
406                  return -EPERM;                  return -EPERM;
407          if (family == PF_ROUTE && !ccs_capable(CCS_USE_ROUTE_SOCKET))          if (family == PF_ROUTE && !ccs_capable(CCS_USE_ROUTE_SOCKET))
408                  return -EPERM;                  return -EPERM;
409          if (family != PF_INET && family != PF_INET6)          return 0;
                 return 0;  
         switch (type) {  
         case SOCK_STREAM:  
                 if (!ccs_capable(CCS_INET_STREAM_SOCKET_CREATE))  
                         error = -EPERM;  
                 break;  
         case SOCK_DGRAM:  
                 if (!ccs_capable(CCS_USE_INET_DGRAM_SOCKET))  
                         error = -EPERM;  
                 break;  
         case SOCK_RAW:  
                 if (!ccs_capable(CCS_USE_INET_RAW_SOCKET))  
                         error = -EPERM;  
                 break;  
         }  
         return error;  
410  }  }
411    
412  /* Check permission for listening a TCP socket. */  /* Check permission for listening a TCP socket. */
413  int ccs_socket_listen_permission(struct socket *sock)  static int __ccs_socket_listen_permission(struct socket *sock)
414  {  {
415            struct sockaddr_storage addr;
416          int error = 0;          int error = 0;
         char addr[MAX_SOCK_ADDR];  
417          int addr_len;          int addr_len;
418            struct ccs_addr_info address;
419          /* Nothing to do if I am a kernel service. */          /* Nothing to do if I am a kernel service. */
420          if (segment_eq(get_fs(), KERNEL_DS))          if (segment_eq(get_fs(), KERNEL_DS))
421                  return 0;                  return 0;
# Line 576  int ccs_socket_listen_permission(struct Line 428  int ccs_socket_listen_permission(struct
428          default:          default:
429                  return 0;                  return 0;
430          }          }
431          if (!ccs_capable(CCS_INET_STREAM_SOCKET_LISTEN))          if (sock->ops->getname(sock, (struct sockaddr *) &addr, &addr_len, 0))
                 return -EPERM;  
         if (sock->ops->getname(sock, (struct sockaddr *) addr, &addr_len, 0))  
432                  return -EPERM;                  return -EPERM;
433          switch (((struct sockaddr *) addr)->sa_family) {          address.protocol = CCS_NETWORK_TCP_PROTOCOL;
434                  struct sockaddr_in6 *addr6;          address.operation = CCS_NETWORK_LISTEN;
435                  struct sockaddr_in *addr4;          if (ccs_check_address((struct sockaddr *) &addr, addr_len, &address))
436          case AF_INET6:                  error = ccs_network_entry(&address);
437                  addr6 = (struct sockaddr_in6 *) addr;          return error;
                 error = ccs_check_network_listen_acl(true,  
                                                      addr6->sin6_addr.s6_addr,  
                                                      addr6->sin6_port);  
                 break;  
         case AF_INET:  
                 addr4 = (struct sockaddr_in *) addr;  
                 error = ccs_check_network_listen_acl(false,  
                                                      (u8 *) &addr4->sin_addr,  
                                                      addr4->sin_port);  
                 break;  
         }  
         return error;  
438  }  }
439    
440  /* Check permission for setting the remote IP address/port pair of a socket. */  /* Check permission for setting the remote IP address/port pair of a socket. */
441  int ccs_socket_connect_permission(struct socket *sock, struct sockaddr *addr,  static int __ccs_socket_connect_permission(struct socket *sock,
442                                    int addr_len)                                             struct sockaddr *addr, int addr_len)
443  {  {
444          int error = 0;          int error = 0;
445          const unsigned int type = sock->type;          const unsigned int type = sock->type;
446            struct ccs_addr_info address;
447          /* Nothing to do if I am a kernel service. */          /* Nothing to do if I am a kernel service. */
448          if (segment_eq(get_fs(), KERNEL_DS))          if (segment_eq(get_fs(), KERNEL_DS))
449                  return 0;                  return 0;
450          switch (type) {          switch (type) {
451          case SOCK_STREAM:          case SOCK_STREAM:
452                    address.protocol = CCS_NETWORK_TCP_PROTOCOL;
453                    break;
454          case SOCK_DGRAM:          case SOCK_DGRAM:
455                    address.protocol = CCS_NETWORK_UDP_PROTOCOL;
456                    break;
457          case SOCK_RAW:          case SOCK_RAW:
458                    address.protocol = CCS_NETWORK_RAW_PROTOCOL;
459                  break;                  break;
460          default:          default:
461                  return 0;                  return 0;
462          }          }
463          switch (addr->sa_family) {          address.operation = CCS_NETWORK_CONNECT;
464                  struct sockaddr_in6 *addr6;          if (!ccs_check_address(addr, addr_len, &address))
465                  struct sockaddr_in *addr4;                  goto skip;
466                  u16 port;          if (type == SOCK_RAW)
467          case AF_INET6:                  address.port = htons(sock->sk->sk_protocol);
468                  if (addr_len < SIN6_LEN_RFC2133)          error = ccs_network_entry(&address);
469                          break;   skip:
                 addr6 = (struct sockaddr_in6 *) addr;  
                 if (type != SOCK_RAW)  
                         port = addr6->sin6_port;  
                 else  
                         port = htons(sock->sk->sk_protocol);  
                 error = ccs_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 = ccs_check_network_connect_acl(false, type,  
                                                       (u8 *) &addr4->sin_addr,  
                                                       port);  
                 break;  
         }  
         if (type != SOCK_STREAM)  
                 return error;  
         switch (sock->sk->sk_family) {  
         case PF_INET:  
         case PF_INET6:  
                 if (!ccs_capable(CCS_INET_STREAM_SOCKET_CONNECT))  
                         error = -EPERM;  
                 break;  
         }  
470          return error;          return error;
471  }  }
472    
473  /* Check permission for setting the local IP address/port pair of a socket. */  /* Check permission for setting the local IP address/port pair of a socket. */
474  int ccs_socket_bind_permission(struct socket *sock, struct sockaddr *addr,  static int __ccs_socket_bind_permission(struct socket *sock,
475                                 int addr_len)                                          struct sockaddr *addr, int addr_len)
476  {  {
477          int error = 0;          int error = 0;
478          const unsigned int type = sock->type;          const unsigned int type = sock->type;
479            struct ccs_addr_info address;
480          /* Nothing to do if I am a kernel service. */          /* Nothing to do if I am a kernel service. */
481          if (segment_eq(get_fs(), KERNEL_DS))          if (segment_eq(get_fs(), KERNEL_DS))
482                  return 0;                  return 0;
483          switch (type) {          switch (type) {
484          case SOCK_STREAM:          case SOCK_STREAM:
485                    address.protocol = CCS_NETWORK_TCP_PROTOCOL;
486                    break;
487          case SOCK_DGRAM:          case SOCK_DGRAM:
488                    address.protocol = CCS_NETWORK_UDP_PROTOCOL;
489                    break;
490          case SOCK_RAW:          case SOCK_RAW:
491                    address.protocol = CCS_NETWORK_RAW_PROTOCOL;
492                  break;                  break;
493          default:          default:
494                  return 0;                  return 0;
495          }          }
496          switch (addr->sa_family) {          address.operation = CCS_NETWORK_BIND;
497                  struct sockaddr_in6 *addr6;          if (!ccs_check_address(addr, addr_len, &address))
498                  struct sockaddr_in *addr4;                  goto skip;
499                  u16 port;          if (type == SOCK_RAW)
500          case AF_INET6:                  address.port = htons(sock->sk->sk_protocol);
501                  if (addr_len < SIN6_LEN_RFC2133)          error = ccs_network_entry(&address);
502                          break;   skip:
                 addr6 = (struct sockaddr_in6 *) addr;  
                 if (type != SOCK_RAW)  
                         port = addr6->sin6_port;  
                 else  
                         port = htons(sock->sk->sk_protocol);  
                 error = ccs_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 = ccs_check_network_bind_acl(false, type,  
                                                    (u8 *) &addr4->sin_addr,  
                                                    port);  
                 break;  
         }  
503          return error;          return error;
504  }  }
505    
506  /*  /* Check permission for accepting a TCP socket. */
507   * Check permission for accepting a TCP socket.  static int __ccs_socket_post_accept_permission(struct socket *sock,
508   *                                                 struct socket *newsock)
  * Currently, the LSM hook for this purpose is not provided.  
  */  
 int ccs_socket_accept_permission(struct socket *sock, struct sockaddr *addr)  
509  {  {
510            struct sockaddr_storage addr;
511            struct task_struct * const task = current;
512          int error = 0;          int error = 0;
513          int addr_len;          int addr_len;
514            struct ccs_addr_info address;
515          /* Nothing to do if I am a kernel service. */          /* Nothing to do if I am a kernel service. */
516          if (segment_eq(get_fs(), KERNEL_DS))          if (segment_eq(get_fs(), KERNEL_DS))
517                  return 0;                  return 0;
518          switch (sock->sk->sk_family) {          switch (newsock->sk->sk_family) {
519          case PF_INET:          case PF_INET:
520          case PF_INET6:          case PF_INET6:
521                  break;                  break;
522          default:          default:
523                  return 0;                  return 0;
524          }          }
525          error = sock->ops->getname(sock, addr, &addr_len, 2);          error = newsock->ops->getname(newsock, (struct sockaddr *) &addr,
526                                          &addr_len, 2);
527          if (error)          if (error)
528                  return error;                  return error;
529          switch (addr->sa_family) {          if (!ccs_check_address((struct sockaddr *) &addr, addr_len,
530                  struct sockaddr_in6 *addr6;                                 &address))
531                  struct sockaddr_in *addr4;                  goto skip;
532          case AF_INET6:          address.protocol = CCS_NETWORK_TCP_PROTOCOL;
533                  addr6 = (struct sockaddr_in6 *) addr;          address.operation = CCS_NETWORK_ACCEPT;
534                  error = ccs_check_network_accept_acl(true,          task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
535                                                       addr6->sin6_addr.s6_addr,          error = ccs_network_entry(&address);
536                                                       addr6->sin6_port);          task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
537                  break;   skip:
         case AF_INET:  
                 addr4 = (struct sockaddr_in *) addr;  
                 error = ccs_check_network_accept_acl(false,  
                                                      (u8 *) &addr4->sin_addr,  
                                                      addr4->sin_port);  
                 break;  
         }  
538          return error;          return error;
539  }  }
540    
541  /* Check permission for sending a datagram via a UDP or RAW socket. */  /* Check permission for sending a datagram via a UDP or RAW socket. */
542  int ccs_socket_sendmsg_permission(struct socket *sock, struct sockaddr *addr,  static int __ccs_socket_sendmsg_permission(struct socket *sock,
543                                    int addr_len)                                             struct msghdr *msg, int size)
544  {  {
545          int error = 0;          int error = 0;
546          const int type = sock->type;          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. */          /* Nothing to do if I am a kernel service. */
551          if (segment_eq(get_fs(), KERNEL_DS))          if (segment_eq(get_fs(), KERNEL_DS))
552                  return 0;                  return 0;
553          if (!addr || (type != SOCK_DGRAM && type != SOCK_RAW))          switch (type) {
554                  return 0;          case SOCK_DGRAM:
555          switch (addr->sa_family) {                  address.protocol = CCS_NETWORK_UDP_PROTOCOL;
                 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 = ccs_check_network_sendmsg_acl(true, type,  
                                                       addr6->sin6_addr.s6_addr,  
                                                       port);  
556                  break;                  break;
557          case AF_INET:          case SOCK_RAW:
558                  if (addr_len < sizeof(struct sockaddr_in))                  address.protocol = CCS_NETWORK_RAW_PROTOCOL;
                         break;  
                 addr4 = (struct sockaddr_in *) addr;  
                 if (type == SOCK_DGRAM)  
                         port = addr4->sin_port;  
                 else  
                         port = htons(sock->sk->sk_protocol);  
                 error = ccs_check_network_sendmsg_acl(false, type,  
                                                       (u8 *) &addr4->sin_addr,  
                                                       port);  
559                  break;                  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;          return error;
572  }  }
573    
574  #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)  #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
575  #if !defined(RHEL_MAJOR) || RHEL_MAJOR != 5  #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)  static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
579  {  {
# Line 810  static inline struct ipv6hdr *ipv6_hdr(c Line 592  static inline struct ipv6hdr *ipv6_hdr(c
592    
593  #endif  #endif
594  #endif  #endif
   
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)  
 static void skb_kill_datagram(struct sock *sk, struct sk_buff *skb,  
                               unsigned int flags)  
 {  
         /* Clear queue. */  
         if (flags & MSG_PEEK) {  
                 int clear = 0;  
                 spin_lock_irq(&sk->sk_receive_queue.lock);  
                 if (skb == skb_peek(&sk->sk_receive_queue)) {  
                         __skb_unlink(skb, &sk->sk_receive_queue);  
                         clear = 1;  
                 }  
                 spin_unlock_irq(&sk->sk_receive_queue.lock);  
                 if (clear)  
                         kfree_skb(skb);  
         }  
         skb_free_datagram(sk, skb);  
 }  
 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)  
 static void skb_kill_datagram(struct sock *sk, struct sk_buff *skb,  
                               unsigned int flags)  
 {  
         /* Clear queue. */  
         if (flags & MSG_PEEK) {  
                 int clear = 0;  
                 spin_lock_bh(&sk->sk_receive_queue.lock);  
                 if (skb == skb_peek(&sk->sk_receive_queue)) {  
                         __skb_unlink(skb, &sk->sk_receive_queue);  
                         clear = 1;  
                 }  
                 spin_unlock_bh(&sk->sk_receive_queue.lock);  
                 if (clear)  
                         kfree_skb(skb);  
         }  
         skb_free_datagram(sk, skb);  
 }  
595  #endif  #endif
596    
597  /*  /* Check permission for receiving a datagram via a UDP or RAW socket. */
598   * Check permission for receiving a datagram via a UDP or RAW socket.  static int __ccs_socket_post_recvmsg_permission(struct sock *sk,
599   *                                                  struct sk_buff *skb)
  * Currently, the LSM hook for this purpose is not provided.  
  */  
 int ccs_socket_recvmsg_permission(struct sock *sk, struct sk_buff *skb,  
                                   const unsigned int flags)  
600  {  {
601            struct task_struct * const task = current;
602          int error = 0;          int error = 0;
603          const unsigned int type = sk->sk_type;          const unsigned int type = sk->sk_type;
604          if (type != SOCK_DGRAM && type != SOCK_RAW)          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;                  return 0;
618            }
619          /* Nothing to do if I am a kernel service. */          /* Nothing to do if I am a kernel service. */
620          if (segment_eq(get_fs(), KERNEL_DS))          if (segment_eq(get_fs(), KERNEL_DS))
621                  return 0;                  return 0;
   
622          switch (sk->sk_family) {          switch (sk->sk_family) {
                 struct in6_addr sin6;  
                 struct in_addr sin4;  
                 u16 port;  
623          case PF_INET6:          case PF_INET6:
624                  if (type == SOCK_DGRAM) { /* UDP IPv6 */                  address.is_ipv6 = true;
625                          if (skb->protocol == htons(ETH_P_IP)) {                  if (type == SOCK_DGRAM && skb->protocol == htons(ETH_P_IP))
626                                  ipv6_addr_set(&sin6, 0, 0, htonl(0xffff),                          ipv6_addr_set(&ip_address.sin6, 0, 0, htonl(0xffff),
627                                                ip_hdr(skb)->saddr);                                        ip_hdr(skb)->saddr);
628                          } else {                  else
629                                  ipv6_addr_copy(&sin6, &ipv6_hdr(skb)->saddr);                          ipv6_addr_copy(&ip_address.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 = ccs_check_network_recvmsg_acl(true, type,  
                                                       (u8 *) &sin6, port);  
630                  break;                  break;
631          case PF_INET:          case PF_INET:
632                  if (type == SOCK_DGRAM) { /* UDP IPv4 */                  address.is_ipv6 = false;
633                          sin4.s_addr = ip_hdr(skb)->saddr;                  ip_address.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 = ccs_check_network_recvmsg_acl(false, type,  
                                                       (u8 *) &sin4, port);  
634                  break;                  break;
635            default:
636                    goto skip;
637          }          }
638          if (!error)          address.address = (u32 *) &ip_address;
                 return 0;  
         /*  
          * Remove from queue if MSG_PEEK is used so that  
          * the head message from unwanted source in receive queue will not  
          * prevent the caller from picking up next message from wanted source  
          * when the caller is using MSG_PEEK flag for picking up.  
          */  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  
639          if (type == SOCK_DGRAM)          if (type == SOCK_DGRAM)
640                  lock_sock(sk);                  address.port = udp_hdr(skb)->source;
641  #endif          else
642          skb_kill_datagram(sk, skb, flags);                  address.port = htons(sk->sk_protocol);
643  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)          address.operation = CCS_NETWORK_RECV;
644          if (type == SOCK_DGRAM)          task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
645                  release_sock(sk);          error = ccs_network_entry(&address);
646  #endif          task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
647          /* Hope less harmful than -EPERM. */   skip:
648          return -ENOMEM;          return error;
649  }  }
650  EXPORT_SYMBOL(ccs_socket_recvmsg_permission);  
651    void __init ccs_network_init(void)
652    {
653            ccsecurity_ops.socket_create_permission =
654                    __ccs_socket_create_permission;
655            ccsecurity_ops.socket_listen_permission =
656                    __ccs_socket_listen_permission;
657            ccsecurity_ops.socket_connect_permission =
658                    __ccs_socket_connect_permission;
659            ccsecurity_ops.socket_bind_permission = __ccs_socket_bind_permission;
660            ccsecurity_ops.socket_post_accept_permission =
661                    __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.2918  
changed lines
  Added in v.3871

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