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

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/ccs-patch/fs/tomoyo_network.c revision 111 by kumaneko, Wed Feb 28 11:45:08 2007 UTC branches/ccs-patch/security/ccsecurity/network.c revision 2860 by kumaneko, Thu Aug 6 07:57:13 2009 UTC
# Line 1  Line 1 
1  /*  /*
2   * fs/tomoyo_network.c   * fs/ccsecurity/network.c
3   *   *
4   * Implementation of the Domain-Based Mandatory Access Control.   * Copyright (C) 2005-2009  NTT DATA CORPORATION
5   *   *
6   * Copyright (C) 2005-2007  NTT DATA CORPORATION   * Version: 1.7.0-pre   2009/07/03
  *  
  * Version: 1.3.2   2007/02/14  
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   */   */
 /***** TOMOYO Linux start. *****/  
12    
13  #include <linux/ccs_common.h>  #include <linux/net.h>
14  #include <linux/tomoyo.h>  #include <linux/inet.h>
15  #include <linux/realpath.h>  #include <linux/in.h>
16    #include <linux/in6.h>
17  #include <net/ip.h>  #include <net/ip.h>
18    #include <net/ipv6.h>
19    #include <net/udp.h>
20    #include "internal.h"
21    #include <linux/ccsecurity.h>
22    
23    /* Index numbers for Network Controls. */
24    enum ccs_network_acl_index {
25            NETWORK_ACL_UDP_BIND,
26            NETWORK_ACL_UDP_CONNECT,
27            NETWORK_ACL_TCP_BIND,
28            NETWORK_ACL_TCP_LISTEN,
29            NETWORK_ACL_TCP_CONNECT,
30            NETWORK_ACL_TCP_ACCEPT,
31            NETWORK_ACL_RAW_BIND,
32            NETWORK_ACL_RAW_CONNECT
33    };
34    
35  /*************************  VARIABLES  *************************/  /**
36     * ccs_audit_network_log - Audit network log.
37  extern struct semaphore domain_acl_lock;   *
38     * @r:          Pointer to "struct ccs_request_info".
39     * @operation:  The name of operation.
40     * @address:    An IPv4 or IPv6 address.
41     * @port:       Port number.
42     * @is_granted: True if this is a granted log.
43     *
44     * Returns 0 on success, negative value otherwise.
45     */
46    static int ccs_audit_network_log(struct ccs_request_info *r,
47                                     const char *operation, const char *address,
48                                     const u16 port, const bool is_granted)
49    {
50            if (!is_granted && ccs_verbose_mode(r->domain))
51                    printk(KERN_WARNING "TOMOYO-%s: %s to %s %u denied for %s\n",
52                           ccs_get_msg(r->mode == 3), operation, address, port,
53                           ccs_get_last_name(r->domain));
54            return ccs_write_audit_log(is_granted, r, KEYWORD_ALLOW_NETWORK
55                                       "%s %s %u\n", operation, address, port);
56    }
57    
58  /*************************  AUDIT FUNCTIONS  *************************/  /* The list for "struct ccs_address_group_entry". */
59    LIST_HEAD(ccs_address_group_list);
60    
61  #ifdef CONFIG_TOMOYO_AUDIT  /**
62  static int AuditNetworkLog(const int is_ipv6, const char *operation, const u32 *address, const u16 port, const int is_granted)   * ccs_get_address_group - Allocate memory for "struct ccs_address_group_entry".
63     *
64     * @group_name: The name of address group.
65     *
66     * Returns pointer to "struct ccs_address_group_entry" on success,
67     * NULL otherwise.
68     */
69    static struct ccs_address_group_entry *ccs_get_address_group(const char *
70                                                                 group_name)
71  {  {
72          char *buf;          struct ccs_address_group_entry *entry = NULL;
73          int len = 256;          struct ccs_address_group_entry *group;
74          if (CanSaveAuditLog(is_granted) < 0) return -ENOMEM;          const struct ccs_path_info *saved_group_name;
75          if ((buf = InitAuditLog(&len)) == NULL) return -ENOMEM;          int error = -ENOMEM;
76          snprintf(buf + strlen(buf), len - strlen(buf) - 1, KEYWORD_ALLOW_NETWORK "%s ", operation);          if (!ccs_is_correct_path(group_name, 0, 0, 0) ||
77          if (is_ipv6) {              !group_name[0])
78                  print_ipv6(buf + strlen(buf), len - strlen(buf), (const u16 *) address);                  return NULL;
79          } else {          saved_group_name = ccs_get_name(group_name);
80                  u32 ip = *address;          if (!saved_group_name)
81                  snprintf(buf + strlen(buf), len - strlen(buf) - 1, "%u.%u.%u.%u", NIPQUAD(ip));                  return NULL;
82            entry = kzalloc(sizeof(*entry), GFP_KERNEL);
83            mutex_lock(&ccs_policy_lock);
84            list_for_each_entry_rcu(group, &ccs_address_group_list, list) {
85                    if (saved_group_name != group->group_name)
86                            continue;
87                    atomic_inc(&group->users);
88                    error = 0;
89                    break;
90            }
91            if (error && ccs_memory_ok(entry, sizeof(*entry))) {
92                    INIT_LIST_HEAD(&entry->address_group_member_list);
93                    entry->group_name = saved_group_name;
94                    saved_group_name = NULL;
95                    atomic_set(&entry->users, 1);
96                    list_add_tail_rcu(&entry->list, &ccs_address_group_list);
97                    group = entry;
98                    entry = NULL;
99                    error = 0;
100          }          }
101          snprintf(buf + strlen(buf), len - strlen(buf) - 1, " %u\n", port);          mutex_unlock(&ccs_policy_lock);
102          return WriteAuditLog(buf, is_granted);          ccs_put_name(saved_group_name);
103            kfree(entry);
104            return !error ? group : NULL;
105  }  }
 #else  
 static inline void AuditNetworkLog(const int is_ipv6, const char *operation, const u32 *address, const u16 port, const int is_granted) {}  
 #endif  
   
 /*************************  ADDRESS GROUP HANDLER  *************************/  
106    
107  static ADDRESS_GROUP_ENTRY *group_list = NULL;  /**
108     * ccs_update_address_group_entry - Update "struct ccs_address_group_entry" list.
109  static int AddAddressGroupEntry(const char *group_name, const u8 is_ipv6, const u16 *min_address, const u16 *max_address, const int is_delete)   *
110     * @group_name:  The name of address group.
111     * @is_ipv6:     True if @min_address and @max_address are IPv6 addresses.
112     * @min_address: Start of IPv4 or IPv6 address range.
113     * @max_address: End of IPv4 or IPv6 address range.
114     * @is_delete:   True if it is a delete request.
115     *
116     * Returns 0 on success, negative value otherwise.
117     */
118    static int ccs_update_address_group_entry(const char *group_name,
119                                              const bool is_ipv6,
120                                              const u16 *min_address,
121                                              const u16 *max_address,
122                                              const bool is_delete)
123  {  {
124          static DECLARE_MUTEX(lock);          struct ccs_address_group_entry *group;
125          ADDRESS_GROUP_ENTRY *new_group, *group;          struct ccs_address_group_member *entry = NULL;
126          ADDRESS_GROUP_MEMBER *new_member, *member;          struct ccs_address_group_member *member;
127          const struct path_info *saved_group_name;          const struct in6_addr *saved_min_address = NULL;
128          int error = -ENOMEM;          const struct in6_addr *saved_max_address = NULL;
129          if (!IsCorrectPath(group_name, 0, 0, 0, __FUNCTION__) || !group_name[0]) return -EINVAL;          int error = is_delete ? -ENOENT : -ENOMEM;
130          if ((saved_group_name = SaveName(group_name)) == NULL) return -ENOMEM;          const u32 min_ipv4_address = ntohl(*(u32 *) min_address);
131          down(&lock);          const u32 max_ipv4_address = ntohl(*(u32 *) max_address);
132          for (group = group_list; group; group = group->next) {          group = ccs_get_address_group(group_name);
133                  if (saved_group_name != group->group_name) continue;          if (!group)
134                  for (member = group->first_member; member; member = member->next) {                  return -ENOMEM;
135                          if (member->is_ipv6 != is_ipv6) continue;          if (is_ipv6) {
136                          if (is_ipv6) {                  saved_min_address
137                                  if (memcmp(member->min.ipv6, min_address, 16) || memcmp(member->max.ipv6, max_address, 16)) continue;                          = ccs_get_ipv6_address((struct in6_addr *)
138                          } else {                                                 min_address);
139                                  if (member->min.ipv4 != * (u32 *) min_address || member->max.ipv4 != * (u32 *) max_address) continue;                  saved_max_address
140                          }                          = ccs_get_ipv6_address((struct in6_addr *)
141                          member->is_deleted = is_delete;                                                 max_address);
142                          error = 0;                  if (!saved_min_address || !saved_max_address)
143                          goto out;                          goto out;
144            }
145            if (!is_delete)
146                    entry = kzalloc(sizeof(*entry), GFP_KERNEL);
147            mutex_lock(&ccs_policy_lock);
148            list_for_each_entry_rcu(member, &group->address_group_member_list,
149                                    list) {
150                    if (member->is_ipv6 != is_ipv6)
151                            continue;
152                    if (is_ipv6) {
153                            if (member->min.ipv6 != saved_min_address ||
154                                member->max.ipv6 != saved_max_address)
155                                    continue;
156                    } else {
157                            if (member->min.ipv4 != min_ipv4_address ||
158                                member->max.ipv4 != max_ipv4_address)
159                                    continue;
160                  }                  }
161                    member->is_deleted = is_delete;
162                    error = 0;
163                  break;                  break;
164          }          }
165          if (is_delete) {          if (!is_delete && error && ccs_memory_ok(entry, sizeof(*entry))) {
166                  error = -ENOENT;                  entry->is_ipv6 = is_ipv6;
167                  goto out;                  if (is_ipv6) {
168          }                          entry->min.ipv6 = saved_min_address;
169          if (!group) {                          saved_min_address = NULL;
170                  if ((new_group = (ADDRESS_GROUP_ENTRY *) alloc_element(sizeof(ADDRESS_GROUP_ENTRY))) == NULL) goto out;                          entry->max.ipv6 = saved_max_address;
171                  new_group->group_name = saved_group_name;                          saved_max_address = NULL;
                 mb(); /* Instead of using spinlock. */  
                 if ((group = group_list) != NULL) {  
                         while (group->next) group = group->next; group->next = new_group;  
172                  } else {                  } else {
173                          group_list= new_group;                          entry->min.ipv4 = min_ipv4_address;
174                            entry->max.ipv4 = max_ipv4_address;
175                  }                  }
176                  group = new_group;                  list_add_tail_rcu(&entry->list,
177          }                                    &group->address_group_member_list);
178          if ((new_member = (ADDRESS_GROUP_MEMBER *) alloc_element(sizeof(ADDRESS_GROUP_MEMBER))) == NULL) goto out;                  entry = NULL;
179          new_member->is_ipv6 = is_ipv6;                  error = 0;
         if (is_ipv6) {  
                 memmove(new_member->min.ipv6, min_address, 16);  
                 memmove(new_member->max.ipv6, max_address, 16);  
         } else {  
                 new_member->min.ipv4 = * (u32 *) min_address;  
                 new_member->max.ipv4 = * (u32 *) max_address;  
         }  
         mb(); /* Instead of using spinlock. */  
         if ((member = group->first_member) != NULL) {  
                 while (member->next) member = member->next; member->next = new_member;  
         } else {  
                 group->first_member = new_member;  
180          }          }
181          error = 0;          mutex_unlock(&ccs_policy_lock);
182   out:   out:
183          up(&lock);          ccs_put_ipv6_address(saved_min_address);
184            ccs_put_ipv6_address(saved_max_address);
185            ccs_put_address_group(group);
186          return error;          return error;
187  }  }
188    
189  int AddAddressGroupPolicy(char *data, const int is_delete)  /**
190     * ccs_parse_ip_address - Parse an IP address.
191     *
192     * @address: String to parse.
193     * @min:     Pointer to store min address.
194     * @max:     Pointer to store max address.
195     *
196     * Returns 2 if @address is an IPv6, 1 if @address is an IPv4, 0 otherwise.
197     */
198    static int ccs_parse_ip_address(char *address, u16 *min, u16 *max)
199  {  {
200          int count, is_ipv6;          int count = sscanf(address, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"
201          u16 min_address[8], max_address[8];                             "-%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
202          char *cp = strchr(data, ' ');                             &min[0], &min[1], &min[2], &min[3],
203          if (!cp) return -EINVAL;                             &min[4], &min[5], &min[6], &min[7],
204          *cp++ = '\0';                             &max[0], &max[1], &max[2], &max[3],
205          if ((count = sscanf(cp, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx-%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",                             &max[4], &max[5], &max[6], &max[7]);
206                                                  &min_address[0], &min_address[1], &min_address[2], &min_address[3],          if (count == 8 || count == 16) {
207                                                  &min_address[4], &min_address[5], &min_address[6], &min_address[7],                  u8 i;
208                                                  &max_address[0], &max_address[1], &max_address[2], &max_address[3],                  if (count == 8)
209                                                  &max_address[4], &max_address[5], &max_address[6], &max_address[7])) == 8 || count == 16) {                          memmove(max, min, sizeof(u16) * 8);
                 int i;  
210                  for (i = 0; i < 8; i++) {                  for (i = 0; i < 8; i++) {
211                          min_address[i] = htons(min_address[i]);                          min[i] = htons(min[i]);
212                          max_address[i] = htons(max_address[i]);                          max[i] = htons(max[i]);
213                  }                  }
214                  if (count == 8) memmove(max_address, min_address, sizeof(min_address));                  return 2;
                 is_ipv6 = 1;  
         } else if ((count = sscanf(cp, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu",  
                                                            &min_address[0], &min_address[1], &min_address[2], &min_address[3],  
                                                            &max_address[0], &max_address[1], &max_address[2], &max_address[3])) == 4 || count == 8) {  
                 u32 ip = ((((u8) min_address[0]) << 24) + (((u8) min_address[1]) << 16) + (((u8) min_address[2]) << 8) + (u8) min_address[3]);  
                 * (u32 *) min_address = ip;  
                 if (count == 8) ip = ((((u8) max_address[0]) << 24) + (((u8) max_address[1]) << 16) + (((u8) max_address[2]) << 8) + (u8) max_address[3]);  
                 * (u32 *) max_address = ip;  
                 is_ipv6 = 0;  
         } else {  
                 return -EINVAL;  
215          }          }
216          return AddAddressGroupEntry(data, is_ipv6, min_address, max_address, is_delete);          count = sscanf(address, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu",
217                           &min[0], &min[1], &min[2], &min[3],
218                           &max[0], &max[1], &max[2], &max[3]);
219            if (count == 4 || count == 8) {
220                    u32 ip = htonl((((u8) min[0]) << 24) + (((u8) min[1]) << 16)
221                                   + (((u8) min[2]) << 8) + (u8) min[3]);
222                    memmove(min, &ip, sizeof(ip));
223                    if (count == 8)
224                            ip = htonl((((u8) max[0]) << 24) + (((u8) max[1]) << 16)
225                                       + (((u8) max[2]) << 8) + (u8) max[3]);
226                    memmove(max, &ip, sizeof(ip));
227                    return 1;
228            }
229            return 0;
230  }  }
231    
232  static ADDRESS_GROUP_ENTRY *FindOrAssignNewAddressGroup(const char *group_name)  /**
233     * ccs_write_address_group_policy - Write "struct ccs_address_group_entry" list.
234     *
235     * @data:      String to parse.
236     * @is_delete: True if it is a delete request.
237     *
238     * Returns 0 on success, negative value otherwise.
239     */
240    int ccs_write_address_group_policy(char *data, const bool is_delete)
241  {  {
242          int i;          char *w[2];
243          ADDRESS_GROUP_ENTRY *group;          bool is_ipv6;
244          for (i = 0; i <= 1; i++) {          u16 min_address[8];
245                  for (group = group_list; group; group = group->next) {          u16 max_address[8];
246                          if (strcmp(group_name, group->group_name->name) == 0) return group;          if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])
247                  }                  return -EINVAL;
248                  if (i == 0) {          switch (ccs_parse_ip_address(w[1], min_address, max_address)) {
249                          const u16 dummy[2] = { 0, 0 };          case 2:
250                          AddAddressGroupEntry(group_name, 0, dummy, dummy, 0);                  is_ipv6 = true;
251                          AddAddressGroupEntry(group_name, 0, dummy, dummy, 1);                  break;
252                  }          case 1:
253                    is_ipv6 = false;
254                    break;
255            default:
256                    return -EINVAL;
257          }          }
258          return NULL;          return ccs_update_address_group_entry(w[0], is_ipv6, min_address,
259                                                  max_address, is_delete);
260  }  }
261    
262  static int AddressMatchesToGroup(const u8 is_ipv6, const u32 *address, const ADDRESS_GROUP_ENTRY *group)  /**
263     * ccs_address_matches_group - Check whether the given address matches members of the given address group.
264     *
265     * @is_ipv6: True if @address is an IPv6 address.
266     * @address: An IPv4 or IPv6 address.
267     * @group:   Pointer to "struct ccs_address_group_entry".
268     *
269     * Returns true if @address matches addresses in @group group, false otherwise.
270     *
271     * Caller holds ccs_read_lock().
272     */
273    static bool ccs_address_matches_group(const bool is_ipv6, const u32 *address,
274                                          const struct ccs_address_group_entry *
275                                          group)
276  {  {
277          ADDRESS_GROUP_MEMBER *member;          struct ccs_address_group_member *member;
278          const u32 ip = ntohl(*address);          const u32 ip = ntohl(*address);
279          for (member = group->first_member; member; member = member->next) {          bool matched = false;
280                  if (member->is_deleted) continue;          ccs_check_read_lock();
281            list_for_each_entry_rcu(member, &group->address_group_member_list,
282                                    list) {
283                    if (member->is_deleted)
284                            continue;
285                  if (member->is_ipv6) {                  if (member->is_ipv6) {
286                          if (memcmp(member->min.ipv6, address, 16) <= 0 && memcmp(address, member->max.ipv6, 16) <= 0) return 1;                          if (is_ipv6 &&
287                                memcmp(member->min.ipv6, address, 16) <= 0 &&
288                                memcmp(address, member->max.ipv6, 16) <= 0) {
289                                    matched = true;
290                                    break;
291                            }
292                  } else {                  } else {
293                          if (member->min.ipv4 <= ip && ip <= member->max.ipv4) return 1;                          if (!is_ipv6 &&
294                                member->min.ipv4 <= ip && ip <= member->max.ipv4) {
295                                    matched = true;
296                                    break;
297                            }
298                  }                  }
299          }          }
300          return 0;          return matched;
301  }  }
302    
303  int ReadAddressGroupPolicy(IO_BUFFER *head)  /**
304     * ccs_read_address_group_policy - Read "struct ccs_address_group_entry" list.
305     *
306     * @head: Pointer to "struct ccs_io_buffer".
307     *
308     * Returns true on success, false otherwise.
309     *
310     * Caller holds ccs_read_lock().
311     */
312    bool ccs_read_address_group_policy(struct ccs_io_buffer *head)
313  {  {
314          ADDRESS_GROUP_ENTRY *group = (ADDRESS_GROUP_ENTRY *) head->read_var1;          struct list_head *gpos;
315          ADDRESS_GROUP_MEMBER *member = (ADDRESS_GROUP_MEMBER *) head->read_var2;          struct list_head *mpos;
316          if (!group) group = group_list;          bool done = true;
317          while (group) {          ccs_check_read_lock();
318                  head->read_var1 = (struct domain_info *) group;          list_for_each_cookie(gpos, head->read_var1, &ccs_address_group_list) {
319                  if (!member) member = group->first_member;                  struct ccs_address_group_entry *group;
320                  while (member) {                  group = list_entry(gpos, struct ccs_address_group_entry, list);
321                          head->read_var2 = (void *) member;                  list_for_each_cookie(mpos, head->read_var2,
322                          if (!member->is_deleted) {                                       &group->address_group_member_list) {
323                                  char buf[128];                          char buf[128];
324                                  if (member->is_ipv6) {                          struct ccs_address_group_member *member;
325                                          const u16 *min_address = member->min.ipv6, *max_address = member->max.ipv6;                          member = list_entry(mpos,
326                                          print_ipv6(buf, sizeof(buf), min_address);                                               struct ccs_address_group_member,
327                                          if (memcmp(min_address, max_address, 16)) {                                               list);
328                                                  char *cp = strchr(buf, '\0');                          if (member->is_deleted)
329                                                  *cp++ = '-';                                  continue;
330                                                  print_ipv6(cp, sizeof(buf) - strlen(buf), max_address);                          if (member->is_ipv6) {
331                                          }                                  const struct in6_addr *min_address
332                                  } else {                                          = member->min.ipv6;
333                                          const u32 min_address = member->min.ipv4, max_address = member->max.ipv4;                                  const struct in6_addr *max_address
334                                          memset(buf, 0, sizeof(buf));                                          = member->max.ipv6;
335                                          snprintf(buf, sizeof(buf) - 1, "%u.%u.%u.%u", HIPQUAD(min_address));                                  ccs_print_ipv6(buf, sizeof(buf), min_address);
336                                          if (min_address != max_address) {                                  if (min_address != max_address) {
337                                                  const int len = strlen(buf);                                          int len;
338                                                  snprintf(buf + len, sizeof(buf) - 1 - len, "-%u.%u.%u.%u", HIPQUAD(max_address));                                          char *cp = buf + strlen(buf);
339                                          }                                          *cp++ = '-';
340                                            len = strlen(buf);
341                                            ccs_print_ipv6(cp, sizeof(buf) - len,
342                                                           max_address);
343                                    }
344                            } else {
345                                    const u32 min_address = member->min.ipv4;
346                                    const u32 max_address = member->max.ipv4;
347                                    memset(buf, 0, sizeof(buf));
348                                    snprintf(buf, sizeof(buf) - 1, "%u.%u.%u.%u",
349                                             HIPQUAD(min_address));
350                                    if (min_address != max_address) {
351                                            const int len = strlen(buf);
352                                            snprintf(buf + len,
353                                                     sizeof(buf) - 1 - len,
354                                                     "-%u.%u.%u.%u",
355                                                     HIPQUAD(max_address));
356                                  }                                  }
                                 if (io_printf(head, KEYWORD_ADDRESS_GROUP "%s %s\n", group->group_name->name, buf)) break;  
357                          }                          }
358                          member = member->next;                          done = ccs_io_printf(head, KEYWORD_ADDRESS_GROUP
359                                                 "%s %s\n", group->group_name->name,
360                                                 buf);
361                            if (!done)
362                                    break;
363                  }                  }
364                  if (member) break;                  if (!done)
365                  head->read_var2 = NULL;                          break;
                 group = group->next;  
366          }          }
367          return group ? -ENOMEM : 0;          return done;
368  }  }
369    
370  /*************************  NETWORK NETWORK ACL HANDLER  *************************/  #if !defined(NIP6)
371    #define NIP6(addr)      \
372            ntohs((addr).s6_addr16[0]), ntohs((addr).s6_addr16[1]), \
373            ntohs((addr).s6_addr16[2]), ntohs((addr).s6_addr16[3]), \
374            ntohs((addr).s6_addr16[4]), ntohs((addr).s6_addr16[5]), \
375            ntohs((addr).s6_addr16[6]), ntohs((addr).s6_addr16[7])
376    #endif
377    
378  char *print_ipv6(char *buffer, const int buffer_len, const u16 *ip)  /**
379     * ccs_print_ipv6 - Print an IPv6 address.
380     *
381     * @buffer:     Buffer to write to.
382     * @buffer_len: Size of @buffer.
383     * @ip:         Pointer to "struct in6_addr".
384     *
385     * Returns nothing.
386     */
387    void ccs_print_ipv6(char *buffer, const int buffer_len,
388                        const struct in6_addr *ip)
389  {  {
390          memset(buffer, 0, buffer_len);          memset(buffer, 0, buffer_len);
391          snprintf(buffer, buffer_len - 1, "%x:%x:%x:%x:%x:%x:%x:%x", ntohs(ip[0]), ntohs(ip[1]), ntohs(ip[2]), ntohs(ip[3]), ntohs(ip[4]), ntohs(ip[5]), ntohs(ip[6]), ntohs(ip[7]));          snprintf(buffer, buffer_len - 1, "%x:%x:%x:%x:%x:%x:%x:%x", NIP6(*ip));
         return buffer;  
392  }  }
393    
394  const char *network2keyword(const unsigned int operation)  /**
395     * ccs_net2keyword - Convert network operation index to network operation name.
396     *
397     * @operation: Type of operation.
398     *
399     * Returns the name of operation.
400     */
401    const char *ccs_net2keyword(const u8 operation)
402  {  {
403          const char *keyword = "unknown";          const char *keyword = "unknown";
404          switch (operation) {          switch (operation) {
# Line 256  const char *network2keyword(const unsign Line 430  const char *network2keyword(const unsign
430          return keyword;          return keyword;
431  }  }
432    
433  static int AddNetworkEntry(const u8 operation, const u8 record_type, const struct address_group_entry *group, const u32 *min_address, const u32 *max_address, const u16 min_port, const u16 max_port, struct domain_info *domain, const u8 is_delete, const struct condition_list *condition)  /**
434     * ccs_update_network_entry - Update "struct ccs_ip_network_acl_record" list.
435     *
436     * @operation:   Type of operation.
437     * @record_type: Type of address.
438     * @group:       Name of group. May be NULL.
439     * @min_address: Start of IPv4 or IPv6 address range.
440     * @max_address: End of IPv4 or IPv6 address range.
441     * @min_port:    Start of port number range.
442     * @max_port:    End of port number range.
443     * @domain:      Pointer to "struct ccs_domain_info".
444     * @condition:   Pointer to "struct ccs_condition". May be NULL.
445     * @is_delete:   True if it is a delete request.
446     *
447     * Returns 0 on success, negative value otherwise.
448     */
449    static int ccs_update_network_entry(const u8 operation, const u8 record_type,
450                                        const char *group_name,
451                                        const u32 *min_address,
452                                        const u32 *max_address,
453                                        const u16 min_port, const u16 max_port,
454                                        struct ccs_domain_info *domain,
455                                        struct ccs_condition *condition,
456                                        const bool is_delete)
457  {  {
458          struct acl_info *ptr;          struct ccs_ip_network_acl_record *entry = NULL;
459          int error = -ENOMEM;          struct ccs_acl_info *ptr;
460          const u8 type = TYPE_IP_NETWORK_ACL;          int error = is_delete ? -ENOENT : -ENOMEM;
461          const u8 hash = operation;          /* using host byte order to allow u32 comparison than memcmp().*/
462          const u32 min_ip = ntohl(*min_address), max_ip = ntohl(*max_address); /* using host byte order to allow u32 comparison than memcmp().*/          const u32 min_ip = ntohl(*min_address);
463          if (!domain) return -EINVAL;          const u32 max_ip = ntohl(*max_address);
464          down(&domain_acl_lock);          const struct in6_addr *saved_min_address = NULL;
465          if (!is_delete) {          const struct in6_addr *saved_max_address = NULL;
466                  if ((ptr = domain->first_acl_ptr) == NULL) goto first_entry;          struct ccs_address_group_entry *group = NULL;
467                  while (1) {          if (!domain)
468                          IP_NETWORK_ACL_RECORD *new_ptr;                  return -EINVAL;
469                          if (ptr->type == type && ptr->u.b[0] == hash && ptr->cond == condition && ((IP_NETWORK_ACL_RECORD *) ptr)->min_port == min_port && max_port == ((IP_NETWORK_ACL_RECORD *) ptr)->max_port) {          if (group_name) {
470                                  if (record_type == IP_RECORD_TYPE_ADDRESS_GROUP) {                  group = ccs_get_address_group(group_name);
471                                          if (((IP_NETWORK_ACL_RECORD *) ptr)->u.group == group) {                  if (!group)
472                                                  ptr->is_deleted = 0;                          return -ENOMEM;
473                                                  /* Found. Nothing to do. */          } else if (record_type == IP_RECORD_TYPE_IPv6) {
474                                                  error = 0;                  saved_min_address = ccs_get_ipv6_address((struct in6_addr *)
475                                                  break;                                                           min_address);
476                                          }                  saved_max_address = ccs_get_ipv6_address((struct in6_addr *)
477                                  } else if (record_type == IP_RECORD_TYPE_IPv4) {                                                           max_address);
478                                          if (((IP_NETWORK_ACL_RECORD *) ptr)->u.ipv4.min == min_ip && max_ip == ((IP_NETWORK_ACL_RECORD *) ptr)->u.ipv4.max) {                  if (!saved_min_address || !saved_max_address)
479                                                  ptr->is_deleted = 0;                          goto out;
480                                                  /* Found. Nothing to do. */          }
481                                                  error = 0;          if (is_delete)
482                                                  break;                  goto delete;
483                                          }          entry = kzalloc(sizeof(*entry), GFP_KERNEL);
484                                  } else if (record_type == IP_RECORD_TYPE_IPv6) {          mutex_lock(&ccs_policy_lock);
485                                          if (memcmp(((IP_NETWORK_ACL_RECORD *) ptr)->u.ipv6.min, min_address, 16) == 0 && memcmp(max_address, ((IP_NETWORK_ACL_RECORD *) ptr)->u.ipv6.max, 16) == 0) {          list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
486                                                  ptr->is_deleted = 0;                  struct ccs_ip_network_acl_record *acl;
487                                                  /* Found. Nothing to do. */                  if (ccs_acl_type1(ptr) != TYPE_IP_NETWORK_ACL)
488                                                  error = 0;                          continue;
489                                                  break;                  if (ptr->cond != condition)
490                                          }                          continue;
491                                  }                  acl = container_of(ptr, struct ccs_ip_network_acl_record, head);
492                          }                  if (acl->operation_type != operation ||
493                          if (ptr->next) {                      acl->record_type != record_type ||
494                                  ptr = ptr->next;                      acl->min_port != min_port || max_port != acl->max_port)
495                            continue;
496                    if (record_type == IP_RECORD_TYPE_ADDRESS_GROUP) {
497                            if (acl->u.group != group)
498                                    continue;
499                    } else if (record_type == IP_RECORD_TYPE_IPv4) {
500                            if (acl->u.ipv4.min != min_ip ||
501                                max_ip != acl->u.ipv4.max)
502                                    continue;
503                    } else if (record_type == IP_RECORD_TYPE_IPv6) {
504                            if (acl->u.ipv6.min != saved_min_address ||
505                                saved_max_address != acl->u.ipv6.max)
506                                  continue;                                  continue;
                         }  
                 first_entry: ;  
                         /* Not found. Append it to the tail. */  
                         if ((new_ptr = (IP_NETWORK_ACL_RECORD *) alloc_element(sizeof(IP_NETWORK_ACL_RECORD))) == NULL) break;  
                         new_ptr->head.type = type;  
                         new_ptr->head.u.b[0] = hash;  
                         new_ptr->head.u.b[1] = record_type;  
                         new_ptr->head.cond = condition;  
                         if (record_type == IP_RECORD_TYPE_ADDRESS_GROUP) {  
                                 new_ptr->u.group = group;  
                         } else if (record_type == IP_RECORD_TYPE_IPv4) {  
                                 new_ptr->u.ipv4.min = min_ip;  
                                 new_ptr->u.ipv4.max = max_ip;  
                         } else if (record_type == IP_RECORD_TYPE_IPv6) {  
                                 memmove(new_ptr->u.ipv6.min, min_address, 16);  
                                 memmove(new_ptr->u.ipv6.max, max_address, 16);  
                         }  
                         new_ptr->min_port = min_port;  
                         new_ptr->max_port = max_port;  
                         error = AddDomainACL(ptr, domain, (struct acl_info *) new_ptr);  
                         break;  
507                  }                  }
508          } else {                  error = ccs_add_domain_acl(NULL, ptr);
509                  error = -ENOENT;                  break;
510                  for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) {          }
511                          if (ptr->type != type || ptr->is_deleted || ptr->u.b[0] != hash || ptr->u.b[1] != record_type || ptr->cond != condition || ((IP_NETWORK_ACL_RECORD *) ptr)->min_port != min_port || ((IP_NETWORK_ACL_RECORD *) ptr)->max_port != max_port) continue;          if (error && ccs_memory_ok(entry, sizeof(*entry))) {
512                          if (record_type == IP_RECORD_TYPE_ADDRESS_GROUP) {                  entry->head.type = TYPE_IP_NETWORK_ACL;
513                                  if (((IP_NETWORK_ACL_RECORD *) ptr)->u.group != group) continue;                  entry->head.cond = condition;
514                          } else if (record_type == IP_RECORD_TYPE_IPv4) {                  entry->operation_type = operation;
515                                  if (((IP_NETWORK_ACL_RECORD *) ptr)->u.ipv4.min != min_ip || max_ip != ((IP_NETWORK_ACL_RECORD *) ptr)->u.ipv4.max) continue;                  entry->record_type = record_type;
516                          } else if (record_type == IP_RECORD_TYPE_IPv6) {                  if (record_type == IP_RECORD_TYPE_ADDRESS_GROUP) {
517                                  if (memcmp(((IP_NETWORK_ACL_RECORD *) ptr)->u.ipv6.min, min_address, 16) || memcmp(max_address, ((IP_NETWORK_ACL_RECORD *) ptr)->u.ipv6.max, 16)) continue;                          entry->u.group = group;
518                          }                          group = NULL;
519                          error = DelDomainACL(ptr);                  } else if (record_type == IP_RECORD_TYPE_IPv4) {
520                          break;                          entry->u.ipv4.min = min_ip;
521                            entry->u.ipv4.max = max_ip;
522                    } else {
523                            entry->u.ipv6.min = saved_min_address;
524                            saved_min_address = NULL;
525                            entry->u.ipv6.max = saved_max_address;
526                            saved_max_address = NULL;
527                  }                  }
528                    entry->min_port = min_port;
529                    entry->max_port = max_port;
530                    error = ccs_add_domain_acl(domain, &entry->head);
531                    entry = NULL;
532          }          }
533          up(&domain_acl_lock);          mutex_unlock(&ccs_policy_lock);
534            goto out;
535     delete:
536            mutex_lock(&ccs_policy_lock);
537            list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
538                    struct ccs_ip_network_acl_record *acl;
539                    if (ccs_acl_type2(ptr) != TYPE_IP_NETWORK_ACL)
540                            continue;
541                    if (ptr->cond != condition)
542                            continue;
543                    acl = container_of(ptr, struct ccs_ip_network_acl_record, head);
544                    if (acl->operation_type != operation ||
545                        acl->record_type != record_type ||
546                        acl->min_port != min_port || max_port != acl->max_port)
547                            continue;
548                    if (record_type == IP_RECORD_TYPE_ADDRESS_GROUP) {
549                            if (acl->u.group != group)
550                                    continue;
551                    } else if (record_type == IP_RECORD_TYPE_IPv4) {
552                            if (acl->u.ipv4.min != min_ip ||
553                                max_ip != acl->u.ipv4.max)
554                                    continue;
555                    } else if (record_type == IP_RECORD_TYPE_IPv6) {
556                            if (acl->u.ipv6.min != saved_min_address ||
557                                saved_max_address != acl->u.ipv6.max)
558                                    continue;
559                    }
560                    error = ccs_del_domain_acl(ptr);
561                    break;
562            }
563            mutex_unlock(&ccs_policy_lock);
564     out:
565            ccs_put_ipv6_address(saved_min_address);
566            ccs_put_ipv6_address(saved_max_address);
567            ccs_put_address_group(group);
568            kfree(entry);
569          return error;          return error;
570  }  }
571    
572  static int CheckNetworkEntry(const int is_ipv6, const int operation, const u32 *address, const u16 port)  /**
573     * ccs_check_network_entry2 - Check permission for network operation.
574     *
575     * @is_ipv6:   True if @address is an IPv6 address.
576     * @operation: Type of operation.
577     * @address:   An IPv4 or IPv6 address.
578     * @port:      Port number.
579     *
580     * Returns 0 on success, negative value otherwise.
581     *
582     * Caller holds ccs_read_lock().
583     */
584    static int ccs_check_network_entry2(const bool is_ipv6, const u8 operation,
585                                        const u32 *address, const u16 port)
586  {  {
587          struct domain_info * const domain = current->domain_info;          struct ccs_request_info r;
588          struct acl_info *ptr;          struct ccs_acl_info *ptr;
589          const char *keyword = network2keyword(operation);          const char *keyword = ccs_net2keyword(operation);
590          const u8 type = TYPE_IP_NETWORK_ACL;          bool is_enforce;
591          const u8 hash = operation;          /* using host byte order to allow u32 comparison than memcmp().*/
592          const int is_enforce = CheckCCSEnforce(CCS_TOMOYO_MAC_FOR_NETWORK);          const u32 ip = ntohl(*address);
593          const u32 ip = ntohl(*address); /* using host byte order to allow u32 comparison than memcmp().*/          bool found = false;
594          if (!CheckCCSFlags(CCS_TOMOYO_MAC_FOR_NETWORK)) return 0;          char buf[64];
595          for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) {          ccs_check_read_lock();
596                  if (ptr->type != type || ptr->is_deleted || ptr->u.b[0] != hash || port < ((IP_NETWORK_ACL_RECORD *) ptr)->min_port || ((IP_NETWORK_ACL_RECORD *) ptr)->max_port < port || CheckCondition(ptr->cond, NULL)) continue;          if (!ccs_can_sleep())
                 if (ptr->u.b[1] == IP_RECORD_TYPE_ADDRESS_GROUP) {  
                         if (AddressMatchesToGroup(is_ipv6, address, ((IP_NETWORK_ACL_RECORD *) ptr)->u.group)) break;  
                 } else if (ptr->u.b[1] == IP_RECORD_TYPE_IPv4) {  
                         if (!is_ipv6 && ((IP_NETWORK_ACL_RECORD *) ptr)->u.ipv4.min <= ip && ip <= ((IP_NETWORK_ACL_RECORD *) ptr)->u.ipv4.max) break;  
                 } else {  
                         if (is_ipv6 && memcmp(((IP_NETWORK_ACL_RECORD *) ptr)->u.ipv6.min, address, 16) <= 0 && memcmp(address, ((IP_NETWORK_ACL_RECORD *) ptr)->u.ipv6.max, 16) <= 0) break;  
                 }  
         }  
         if (ptr) {  
                 AuditNetworkLog(is_ipv6, keyword, address, port, 1);  
597                  return 0;                  return 0;
598          }          ccs_init_request_info(&r, NULL, CCS_MAC_FOR_NETWORK);
599          if (TomoyoVerboseMode()) {          is_enforce = (r.mode == 3);
600                  if (is_ipv6) {          if (!r.mode)
601                          char buf[64];                  return 0;
602                          print_ipv6(buf, sizeof(buf), (const u16 *) address);   retry:
603                          printk("TOMOYO-%s: %s to %s %u denied for %s\n", GetMSG(is_enforce), keyword, buf, port, GetLastName(domain));          list_for_each_entry_rcu(ptr, &r.domain->acl_info_list, list) {
604                    struct ccs_ip_network_acl_record *acl;
605                    if (ccs_acl_type2(ptr) != TYPE_IP_NETWORK_ACL)
606                            continue;
607                    acl = container_of(ptr, struct ccs_ip_network_acl_record, head);
608                    if (acl->operation_type != operation || port < acl->min_port ||
609                        acl->max_port < port || !ccs_check_condition(&r, ptr))
610                            continue;
611                    if (acl->record_type == IP_RECORD_TYPE_ADDRESS_GROUP) {
612                            if (!ccs_address_matches_group(is_ipv6, address,
613                                                           acl->u.group))
614                                    continue;
615                    } else if (acl->record_type == IP_RECORD_TYPE_IPv4) {
616                            if (is_ipv6 ||
617                                ip < acl->u.ipv4.min || acl->u.ipv4.max < ip)
618                                    continue;
619                  } else {                  } else {
620                          printk("TOMOYO-%s: %s to %u.%u.%u.%u %u denied for %s\n", GetMSG(is_enforce), keyword, HIPQUAD(ip), port, GetLastName(domain));                          if (!is_ipv6 ||
621                                memcmp(acl->u.ipv6.min, address, 16) > 0 ||
622                                memcmp(address, acl->u.ipv6.max, 16) > 0)
623                                    continue;
624                  }                  }
625                    r.cond = ptr->cond;
626                    found = true;
627                    break;
628          }          }
629          AuditNetworkLog(is_ipv6, keyword, address, port, 0);          memset(buf, 0, sizeof(buf));
630            if (is_ipv6)
631                    ccs_print_ipv6(buf, sizeof(buf),
632                                   (const struct in6_addr *) address);
633            else
634                    snprintf(buf, sizeof(buf) - 1, "%u.%u.%u.%u", HIPQUAD(ip));
635            ccs_audit_network_log(&r, keyword, buf, port, found);
636            if (found)
637                    return 0;
638          if (is_enforce) {          if (is_enforce) {
639                  if (is_ipv6) {                  int err = ccs_check_supervisor(&r, KEYWORD_ALLOW_NETWORK
640                          char buf[64];                                                 "%s %s %u\n", keyword, buf,
641                          print_ipv6(buf, sizeof(buf), (const u16 *) address);                                                 port);
642                          return CheckSupervisor("%s\n" KEYWORD_ALLOW_NETWORK "%s %s %u\n", domain->domainname->name, keyword, buf, port);                  if (err == 1)
643                  }                          goto retry;
644                  return CheckSupervisor("%s\n" KEYWORD_ALLOW_NETWORK "%s %u.%u.%u.%u %u\n", domain->domainname->name, keyword, HIPQUAD(ip), port);                  return err;
645            } else if (ccs_domain_quota_ok(&r)) {
646                    struct ccs_condition *cond = ccs_handler_cond();
647                    ccs_update_network_entry(operation, is_ipv6 ?
648                                             IP_RECORD_TYPE_IPv6 :
649                                             IP_RECORD_TYPE_IPv4,
650                                             NULL, address, address, port, port,
651                                             r.domain, cond, false);
652                    ccs_put_condition(cond);
653          }          }
         if (CheckCCSAccept(CCS_TOMOYO_MAC_FOR_NETWORK)) AddNetworkEntry(operation, is_ipv6 ? IP_RECORD_TYPE_IPv6: IP_RECORD_TYPE_IPv4, NULL, address, address, port, port, domain, 0, NULL);  
654          return 0;          return 0;
655  }  }
656    
657  int AddNetworkPolicy(char *data, struct domain_info *domain, const int is_delete)  /**
658     * ccs_check_network_entry - Check permission for network operation.
659     *
660     * @is_ipv6:   True if @address is an IPv6 address.
661     * @operation: Type of operation.
662     * @address:   An IPv4 or IPv6 address.
663     * @port:      Port number.
664     *
665     * Returns 0 on success, negative value otherwise.
666     */
667    static int ccs_check_network_entry(const bool is_ipv6, const u8 operation,
668                                       const u32 *address, const u16 port)
669  {  {
670          u8 sock_type, operation, record_type;          const int idx = ccs_read_lock();
671          u16 min_address[8], max_address[8];          const int error = ccs_check_network_entry2(is_ipv6, operation,
672          struct address_group_entry *group = NULL;                                                     address, port);
673          u16 min_port, max_port;          ccs_read_unlock(idx);
674          int count;          return error;
675          char *cp1 = NULL, *cp2 = NULL;  }
676          const struct condition_list *condition = NULL;  
677          cp1 = FindConditionPart(data);  /**
678          if (cp1 && (condition = FindOrAssignNewCondition(cp1)) == NULL) goto out;   * ccs_write_network_policy - Write "struct ccs_ip_network_acl_record" list.
679          if ((cp1 = strchr(data, ' ')) == NULL) goto out; cp1++;   *
680          if (strncmp(data, "TCP ", 4) == 0) sock_type = SOCK_STREAM;   * @data:      String to parse.
681          else if (strncmp(data, "UDP ", 4) == 0) sock_type = SOCK_DGRAM;   * @domain:    Pointer to "struct ccs_domain_info".
682          else if (strncmp(data, "RAW ", 4) == 0) sock_type = SOCK_RAW;   * @condition: Pointer to "struct ccs_condition". May be NULL.
683          else goto out;   * @is_delete: True if it is a delete request.
684          if ((cp2 = strchr(cp1, ' ')) == NULL) goto out; cp2++;   *
685          if (strncmp(cp1, "bind ", 5) == 0) {   * Returns 0 on success, negative value otherwise.
686                  operation = (sock_type == SOCK_STREAM) ? NETWORK_ACL_TCP_BIND : (sock_type == SOCK_DGRAM) ? NETWORK_ACL_UDP_BIND : NETWORK_ACL_RAW_BIND;   */
687          } else if (strncmp(cp1, "connect ", 8) == 0) {  int ccs_write_network_policy(char *data, struct ccs_domain_info *domain,
688                  operation = (sock_type == SOCK_STREAM) ? NETWORK_ACL_TCP_CONNECT : (sock_type == SOCK_DGRAM) ? NETWORK_ACL_UDP_CONNECT : NETWORK_ACL_RAW_CONNECT;                               struct ccs_condition *condition,
689          } else if (sock_type == SOCK_STREAM && strncmp(cp1, "listen ", 7) == 0) {                               const bool is_delete)
690    {
691            char *w[4];
692            u8 sock_type;
693            u8 operation;
694            u8 record_type;
695            u16 min_address[8];
696            u16 max_address[8];
697            const char *group_name = NULL;
698            u16 min_port;
699            u16 max_port;
700            u8 count;
701            if (!ccs_tokenize(data, w, sizeof(w)) || !w[3][0])
702                    return -EINVAL;
703            if (!strcmp(w[0], "TCP"))
704                    sock_type = SOCK_STREAM;
705            else if (!strcmp(w[0], "UDP"))
706                    sock_type = SOCK_DGRAM;
707            else if (!strcmp(w[0], "RAW"))
708                    sock_type = SOCK_RAW;
709            else
710                    goto out;
711            if (!strcmp(w[1], "bind"))
712                    switch (sock_type) {
713                    case SOCK_STREAM:
714                            operation = NETWORK_ACL_TCP_BIND;
715                            break;
716                    case SOCK_DGRAM:
717                            operation = NETWORK_ACL_UDP_BIND;
718                            break;
719                    default:
720                            operation = NETWORK_ACL_RAW_BIND;
721                    }
722            else if (!strcmp(w[1], "connect"))
723                    switch (sock_type) {
724                    case SOCK_STREAM:
725                            operation = NETWORK_ACL_TCP_CONNECT;
726                            break;
727                    case SOCK_DGRAM:
728                            operation = NETWORK_ACL_UDP_CONNECT;
729                            break;
730                    default:
731                            operation = NETWORK_ACL_RAW_CONNECT;
732                    }
733            else if (sock_type == SOCK_STREAM && !strcmp(w[1], "listen"))
734                  operation = NETWORK_ACL_TCP_LISTEN;                  operation = NETWORK_ACL_TCP_LISTEN;
735          } else if (sock_type == SOCK_STREAM && strncmp(cp1, "accept ", 7) == 0) {          else if (sock_type == SOCK_STREAM && !strcmp(w[1], "accept"))
736                  operation = NETWORK_ACL_TCP_ACCEPT;                  operation = NETWORK_ACL_TCP_ACCEPT;
737          } else {          else
738                  goto out;                  goto out;
739          }          switch (ccs_parse_ip_address(w[2], min_address, max_address)) {
740          if ((cp1 = strchr(cp2, ' ')) == NULL) goto out; *cp1++ = '\0';          case 2:
         if ((count = sscanf(cp2, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx-%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",  
                                                 &min_address[0], &min_address[1], &min_address[2], &min_address[3],  
                                                 &min_address[4], &min_address[5], &min_address[6], &min_address[7],  
                                                 &max_address[0], &max_address[1], &max_address[2], &max_address[3],  
                                                 &max_address[4], &max_address[5], &max_address[6], &max_address[7])) == 8 || count == 16) {  
                 int i;  
                 for (i = 0; i < 8; i++) {  
                         min_address[i] = htons(min_address[i]);  
                         max_address[i] = htons(max_address[i]);  
                 }  
                 if (count == 8) memmove(max_address, min_address, sizeof(min_address));  
741                  record_type = IP_RECORD_TYPE_IPv6;                  record_type = IP_RECORD_TYPE_IPv6;
742          } else if ((count = sscanf(cp2, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu",                  break;
743                                                             &min_address[0], &min_address[1], &min_address[2], &min_address[3],          case 1:
                                                            &max_address[0], &max_address[1], &max_address[2], &max_address[3])) == 4 || count == 8) {  
                 u32 ip = htonl((((u8) min_address[0]) << 24) + (((u8) min_address[1]) << 16) + (((u8) min_address[2]) << 8) + (u8) min_address[3]);  
                 * (u32 *) min_address = ip;  
                 if (count == 8) ip = htonl((((u8) max_address[0]) << 24) + (((u8) max_address[1]) << 16) + (((u8) max_address[2]) << 8) + (u8) max_address[3]);  
                 * (u32 *) max_address = ip;  
744                  record_type = IP_RECORD_TYPE_IPv4;                  record_type = IP_RECORD_TYPE_IPv4;
745          } else if (*cp2 == '@') {                  break;
746                  if ((group = FindOrAssignNewAddressGroup(cp2 + 1)) == NULL) return -ENOMEM;          default:
747                    if (w[2][0] != '@')
748                            goto out;
749                    group_name = w[2] + 1;
750                  record_type = IP_RECORD_TYPE_ADDRESS_GROUP;                  record_type = IP_RECORD_TYPE_ADDRESS_GROUP;
751          } else {                  break;
752            }
753            count = sscanf(w[3], "%hu-%hu", &min_port, &max_port);
754            if (count != 1 && count != 2)
755                  goto out;                  goto out;
756            if (count == 1)
757                    max_port = min_port;
758            return ccs_update_network_entry(operation, record_type, group_name,
759                                            (u32 *) min_address,
760                                            (u32 *) max_address,
761                                            min_port, max_port, domain, condition,
762                                            is_delete);
763     out:
764            return -EINVAL;
765    }
766    
767    /**
768     * ccs_check_network_listen_acl - Check permission for listen() operation.
769     *
770     * @is_ipv6: True if @address is an IPv6 address.
771     * @address: An IPv4 or IPv6 address.
772     * @port:    Port number.
773     *
774     * Returns 0 on success, negative value otherwise.
775     */
776    static inline int ccs_check_network_listen_acl(const bool is_ipv6,
777                                                   const u8 *address,
778                                                   const u16 port)
779    {
780            return ccs_check_network_entry(is_ipv6, NETWORK_ACL_TCP_LISTEN,
781                                           (const u32 *) address, ntohs(port));
782    }
783    
784    /**
785     * ccs_check_network_connect_acl - Check permission for connect() operation.
786     *
787     * @is_ipv6:   True if @address is an IPv6 address.
788     * @sock_type: Type of socket. (TCP or UDP or RAW)
789     * @address:   An IPv4 or IPv6 address.
790     * @port:      Port number.
791     *
792     * Returns 0 on success, negative value otherwise.
793     */
794    static inline int ccs_check_network_connect_acl(const bool is_ipv6,
795                                                    const int sock_type,
796                                                    const u8 *address,
797                                                    const u16 port)
798    {
799            u8 operation;
800            switch (sock_type) {
801            case SOCK_STREAM:
802                    operation = NETWORK_ACL_TCP_CONNECT;
803                    break;
804            case SOCK_DGRAM:
805                    operation = NETWORK_ACL_UDP_CONNECT;
806                    break;
807            default:
808                    operation = NETWORK_ACL_RAW_CONNECT;
809          }          }
810          if (strchr(cp1, ' ')) goto out;          return ccs_check_network_entry(is_ipv6, operation,
811          if ((count = sscanf(cp1, "%hu-%hu", &min_port, &max_port)) == 1 || count == 2) {                                         (const u32 *) address, ntohs(port));
812                  if (count == 1) max_port = min_port;  }
813                  return AddNetworkEntry(operation, record_type, group, (u32 *) min_address, (u32 *) max_address, min_port, max_port, domain, is_delete, condition);  
814    /**
815     * ccs_check_network_bind_acl - Check permission for bind() operation.
816     *
817     * @is_ipv6:   True if @address is an IPv6 address.
818     * @sock_type: Type of socket. (TCP or UDP or RAW)
819     * @address:   An IPv4 or IPv6 address.
820     * @port:      Port number.
821     *
822     * Returns 0 on success, negative value otherwise.
823     */
824    static int ccs_check_network_bind_acl(const bool is_ipv6, const int sock_type,
825                                          const u8 *address, const u16 port)
826    {
827            u8 operation;
828            switch (sock_type) {
829            case SOCK_STREAM:
830                    operation = NETWORK_ACL_TCP_BIND;
831                    break;
832            case SOCK_DGRAM:
833                    operation = NETWORK_ACL_UDP_BIND;
834                    break;
835            default:
836                    operation = NETWORK_ACL_RAW_BIND;
837          }          }
838   out: ;          return ccs_check_network_entry(is_ipv6, operation,
839          return -EINVAL;                                         (const u32 *) address, ntohs(port));
840    }
841    
842    /**
843     * ccs_check_network_accept_acl - Check permission for accept() operation.
844     *
845     * @is_ipv6: True if @address is an IPv6 address.
846     * @address: An IPv4 or IPv6 address.
847     * @port:    Port number.
848     *
849     * Returns 0 on success, negative value otherwise.
850     */
851    static inline int ccs_check_network_accept_acl(const bool is_ipv6,
852                                                   const u8 *address,
853                                                   const u16 port)
854    {
855            int retval;
856            current->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
857            retval = ccs_check_network_entry(is_ipv6, NETWORK_ACL_TCP_ACCEPT,
858                                             (const u32 *) address, ntohs(port));
859            current->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
860            return retval;
861    }
862    
863    /**
864     * ccs_check_network_sendmsg_acl - Check permission for sendmsg() operation.
865     *
866     * @is_ipv6:   True if @address is an IPv6 address.
867     * @sock_type: Type of socket. (UDP or RAW)
868     * @address:   An IPv4 or IPv6 address.
869     * @port:      Port number.
870     *
871     * Returns 0 on success, negative value otherwise.
872     */
873    static inline int ccs_check_network_sendmsg_acl(const bool is_ipv6,
874                                                    const int sock_type,
875                                                    const u8 *address,
876                                                    const u16 port)
877    {
878            u8 operation;
879            if (sock_type == SOCK_DGRAM)
880                    operation = NETWORK_ACL_UDP_CONNECT;
881            else
882                    operation = NETWORK_ACL_RAW_CONNECT;
883            return ccs_check_network_entry(is_ipv6, operation,
884                                           (const u32 *) address, ntohs(port));
885    }
886    
887    /**
888     * ccs_check_network_recvmsg_acl - Check permission for recvmsg() operation.
889     *
890     * @is_ipv6:   True if @address is an IPv6 address.
891     * @sock_type: Type of socket. (UDP or RAW)
892     * @address:   An IPv4 or IPv6 address.
893     * @port:      Port number.
894     *
895     * Returns 0 on success, negative value otherwise.
896     */
897    static inline int ccs_check_network_recvmsg_acl(const bool is_ipv6,
898                                                    const int sock_type,
899                                                    const u8 *address,
900                                                    const u16 port)
901    {
902            int retval;
903            const u8 operation
904                    = (sock_type == SOCK_DGRAM) ?
905                    NETWORK_ACL_UDP_CONNECT : NETWORK_ACL_RAW_CONNECT;
906            current->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
907            retval = ccs_check_network_entry(is_ipv6, operation,
908                                             (const u32 *) address, ntohs(port));
909            current->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
910            return retval;
911    }
912    
913    #define MAX_SOCK_ADDR 128 /* net/socket.c */
914    
915    /* Check permission for creating a socket. */
916    int ccs_socket_create_permission(int family, int type, int protocol)
917    {
918            int error = 0;
919            /* Nothing to do if I am a kernel service. */
920            if (segment_eq(get_fs(), KERNEL_DS))
921                    return 0;
922            if (family == PF_PACKET && !ccs_capable(CCS_USE_PACKET_SOCKET))
923                    return -EPERM;
924            if (family == PF_ROUTE && !ccs_capable(CCS_USE_ROUTE_SOCKET))
925                    return -EPERM;
926            if (family != PF_INET && family != PF_INET6)
927                    return 0;
928            switch (type) {
929            case SOCK_STREAM:
930                    if (!ccs_capable(CCS_INET_STREAM_SOCKET_CREATE))
931                            error = -EPERM;
932                    break;
933            case SOCK_DGRAM:
934                    if (!ccs_capable(CCS_USE_INET_DGRAM_SOCKET))
935                            error = -EPERM;
936                    break;
937            case SOCK_RAW:
938                    if (!ccs_capable(CCS_USE_INET_RAW_SOCKET))
939                            error = -EPERM;
940                    break;
941            }
942            return error;
943    }
944    
945    /* Check permission for listening a TCP socket. */
946    int ccs_socket_listen_permission(struct socket *sock)
947    {
948            int error = 0;
949            char addr[MAX_SOCK_ADDR];
950            int addr_len;
951            /* Nothing to do if I am a kernel service. */
952            if (segment_eq(get_fs(), KERNEL_DS))
953                    return 0;
954            if (sock->type != SOCK_STREAM)
955                    return 0;
956            switch (sock->sk->sk_family) {
957            case PF_INET:
958            case PF_INET6:
959                    break;
960            default:
961                    return 0;
962            }
963            if (!ccs_capable(CCS_INET_STREAM_SOCKET_LISTEN))
964                    return -EPERM;
965            if (sock->ops->getname(sock, (struct sockaddr *) addr, &addr_len, 0))
966                    return -EPERM;
967            switch (((struct sockaddr *) addr)->sa_family) {
968                    struct sockaddr_in6 *addr6;
969                    struct sockaddr_in *addr4;
970            case AF_INET6:
971                    addr6 = (struct sockaddr_in6 *) addr;
972                    error = ccs_check_network_listen_acl(true,
973                                                         addr6->sin6_addr.s6_addr,
974                                                         addr6->sin6_port);
975                    break;
976            case AF_INET:
977                    addr4 = (struct sockaddr_in *) addr;
978                    error = ccs_check_network_listen_acl(false,
979                                                         (u8 *) &addr4->sin_addr,
980                                                         addr4->sin_port);
981                    break;
982            }
983            return error;
984    }
985    
986    /* Check permission for setting the remote IP address/port pair of a socket. */
987    int ccs_socket_connect_permission(struct socket *sock, struct sockaddr *addr,
988                                      int addr_len)
989    {
990            int error = 0;
991            const unsigned int type = sock->type;
992            /* Nothing to do if I am a kernel service. */
993            if (segment_eq(get_fs(), KERNEL_DS))
994                    return 0;
995            switch (type) {
996            case SOCK_STREAM:
997            case SOCK_DGRAM:
998            case SOCK_RAW:
999                    break;
1000            default:
1001                    return 0;
1002            }
1003            switch (addr->sa_family) {
1004                    struct sockaddr_in6 *addr6;
1005                    struct sockaddr_in *addr4;
1006                    u16 port;
1007            case AF_INET6:
1008                    if (addr_len < SIN6_LEN_RFC2133)
1009                            break;
1010                    addr6 = (struct sockaddr_in6 *) addr;
1011                    if (type != SOCK_RAW)
1012                            port = addr6->sin6_port;
1013                    else
1014                            port = htons(sock->sk->sk_protocol);
1015                    error = ccs_check_network_connect_acl(true, type,
1016                                                          addr6->sin6_addr.s6_addr,
1017                                                          port);
1018                    break;
1019            case AF_INET:
1020                    if (addr_len < sizeof(struct sockaddr_in))
1021                            break;
1022                    addr4 = (struct sockaddr_in *) addr;
1023                    if (type != SOCK_RAW)
1024                            port = addr4->sin_port;
1025                    else
1026                            port = htons(sock->sk->sk_protocol);
1027                    error = ccs_check_network_connect_acl(false, type,
1028                                                          (u8 *) &addr4->sin_addr,
1029                                                          port);
1030                    break;
1031            }
1032            if (type != SOCK_STREAM)
1033                    return error;
1034            switch (sock->sk->sk_family) {
1035            case PF_INET:
1036            case PF_INET6:
1037                    if (!ccs_capable(CCS_INET_STREAM_SOCKET_CONNECT))
1038                            error = -EPERM;
1039                    break;
1040            }
1041            return error;
1042  }  }
1043    
1044  int CheckNetworkListenACL(const int is_ipv6, const u8 *address, const u16 port)  /* Check permission for setting the local IP address/port pair of a socket. */
1045    int ccs_socket_bind_permission(struct socket *sock, struct sockaddr *addr,
1046                                   int addr_len)
1047  {  {
1048          return CheckNetworkEntry(is_ipv6, NETWORK_ACL_TCP_LISTEN, (const u32 *) address, ntohs(port));          int error = 0;
1049            const unsigned int type = sock->type;
1050            /* Nothing to do if I am a kernel service. */
1051            if (segment_eq(get_fs(), KERNEL_DS))
1052                    return 0;
1053            switch (type) {
1054            case SOCK_STREAM:
1055            case SOCK_DGRAM:
1056            case SOCK_RAW:
1057                    break;
1058            default:
1059                    return 0;
1060            }
1061            switch (addr->sa_family) {
1062                    struct sockaddr_in6 *addr6;
1063                    struct sockaddr_in *addr4;
1064                    u16 port;
1065            case AF_INET6:
1066                    if (addr_len < SIN6_LEN_RFC2133)
1067                            break;
1068                    addr6 = (struct sockaddr_in6 *) addr;
1069                    if (type != SOCK_RAW)
1070                            port = addr6->sin6_port;
1071                    else
1072                            port = htons(sock->sk->sk_protocol);
1073                    error = ccs_check_network_bind_acl(true, type,
1074                                                       addr6->sin6_addr.s6_addr,
1075                                                       port);
1076                    break;
1077            case AF_INET:
1078                    if (addr_len < sizeof(struct sockaddr_in))
1079                            break;
1080                    addr4 = (struct sockaddr_in *) addr;
1081                    if (type != SOCK_RAW)
1082                            port = addr4->sin_port;
1083                    else
1084                            port = htons(sock->sk->sk_protocol);
1085                    error = ccs_check_network_bind_acl(false, type,
1086                                                       (u8 *) &addr4->sin_addr,
1087                                                       port);
1088                    break;
1089            }
1090            return error;
1091  }  }
1092    
1093  int CheckNetworkConnectACL(const int is_ipv6, const int sock_type, const u8 *address, const u16 port)  /*
1094     * Check permission for accepting a TCP socket.
1095     *
1096     * Currently, the LSM hook for this purpose is not provided.
1097     */
1098    int ccs_socket_accept_permission(struct socket *sock, struct sockaddr *addr)
1099  {  {
1100          return CheckNetworkEntry(is_ipv6, sock_type == SOCK_STREAM ? NETWORK_ACL_TCP_CONNECT : (sock_type == SOCK_DGRAM ? NETWORK_ACL_UDP_CONNECT : NETWORK_ACL_RAW_CONNECT), (const u32 *) address, ntohs(port));          int error = 0;
1101            int addr_len;
1102            /* Nothing to do if I am a kernel service. */
1103            if (segment_eq(get_fs(), KERNEL_DS))
1104                    return 0;
1105            switch (sock->sk->sk_family) {
1106            case PF_INET:
1107            case PF_INET6:
1108                    break;
1109            default:
1110                    return 0;
1111            }
1112            error = sock->ops->getname(sock, addr, &addr_len, 2);
1113            if (error)
1114                    return error;
1115            switch (addr->sa_family) {
1116                    struct sockaddr_in6 *addr6;
1117                    struct sockaddr_in *addr4;
1118            case AF_INET6:
1119                    addr6 = (struct sockaddr_in6 *) addr;
1120                    error = ccs_check_network_accept_acl(true,
1121                                                         addr6->sin6_addr.s6_addr,
1122                                                         addr6->sin6_port);
1123                    break;
1124            case AF_INET:
1125                    addr4 = (struct sockaddr_in *) addr;
1126                    error = ccs_check_network_accept_acl(false,
1127                                                         (u8 *) &addr4->sin_addr,
1128                                                         addr4->sin_port);
1129                    break;
1130            }
1131            return error;
1132    }
1133    
1134    /* Check permission for sending a datagram via a UDP or RAW socket. */
1135    int ccs_socket_sendmsg_permission(struct socket *sock, struct sockaddr *addr,
1136                                      int addr_len)
1137    {
1138            int error = 0;
1139            const int type = sock->type;
1140            /* Nothing to do if I am a kernel service. */
1141            if (segment_eq(get_fs(), KERNEL_DS))
1142                    return 0;
1143            if (!addr || (type != SOCK_DGRAM && type != SOCK_RAW))
1144                    return 0;
1145            switch (addr->sa_family) {
1146                    struct sockaddr_in6 *addr6;
1147                    struct sockaddr_in *addr4;
1148                    u16 port;
1149            case AF_INET6:
1150                    if (addr_len < SIN6_LEN_RFC2133)
1151                            break;
1152                    addr6 = (struct sockaddr_in6 *) addr;
1153                    if (type == SOCK_DGRAM)
1154                            port = addr6->sin6_port;
1155                    else
1156                            port = htons(sock->sk->sk_protocol);
1157                    error = ccs_check_network_sendmsg_acl(true, type,
1158                                                          addr6->sin6_addr.s6_addr,
1159                                                          port);
1160                    break;
1161            case AF_INET:
1162                    if (addr_len < sizeof(struct sockaddr_in))
1163                            break;
1164                    addr4 = (struct sockaddr_in *) addr;
1165                    if (type == SOCK_DGRAM)
1166                            port = addr4->sin_port;
1167                    else
1168                            port = htons(sock->sk->sk_protocol);
1169                    error = ccs_check_network_sendmsg_acl(false, type,
1170                                                          (u8 *) &addr4->sin_addr,
1171                                                          port);
1172                    break;
1173            }
1174            return error;
1175  }  }
1176    
1177  int CheckNetworkBindACL(const int is_ipv6, const int sock_type, const u8 *address, const u16 port)  #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
1178    #if !defined(RHEL_MAJOR) || RHEL_MAJOR != 5
1179    
1180    static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
1181  {  {
1182          return CheckNetworkEntry(is_ipv6, sock_type == SOCK_STREAM ? NETWORK_ACL_TCP_BIND : (sock_type == SOCK_DGRAM ? NETWORK_ACL_UDP_BIND : NETWORK_ACL_RAW_BIND), (const u32 *) address, ntohs(port));          return skb->nh.iph;
1183  }  }
1184    
1185  int CheckNetworkAcceptACL(const int is_ipv6, const u8 *address, const u16 port)  static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
1186  {  {
1187          return CheckNetworkEntry(is_ipv6, NETWORK_ACL_TCP_ACCEPT, (const u32 *) address, ntohs(port));          return skb->h.uh;
1188  }  }
1189    
1190  int CheckNetworkSendMsgACL(const int is_ipv6, const int sock_type, const u8 *address, const u16 port)  static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb)
1191  {  {
1192          return CheckNetworkEntry(is_ipv6, sock_type == SOCK_DGRAM ? NETWORK_ACL_UDP_CONNECT : NETWORK_ACL_RAW_CONNECT, (const u32 *) address, ntohs(port));          return skb->nh.ipv6h;
1193  }  }
1194    
1195  int CheckNetworkRecvMsgACL(const int is_ipv6, const int sock_type, const u8 *address, const u16 port)  #endif
1196    #endif
1197    
1198    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
1199    static void skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
1200                                  unsigned int flags)
1201  {  {
1202          return CheckNetworkEntry(is_ipv6, sock_type == SOCK_DGRAM ? NETWORK_ACL_UDP_CONNECT : NETWORK_ACL_RAW_CONNECT, (const u32 *) address, ntohs(port));          /* Clear queue. */
1203            if (flags & MSG_PEEK) {
1204                    int clear = 0;
1205                    spin_lock_irq(&sk->sk_receive_queue.lock);
1206                    if (skb == skb_peek(&sk->sk_receive_queue)) {
1207                            __skb_unlink(skb, &sk->sk_receive_queue);
1208                            clear = 1;
1209                    }
1210                    spin_unlock_irq(&sk->sk_receive_queue.lock);
1211                    if (clear)
1212                            kfree_skb(skb);
1213            }
1214            skb_free_datagram(sk, skb);
1215  }  }
1216    #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
1217    static void skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
1218                                  unsigned int flags)
1219    {
1220            /* Clear queue. */
1221            if (flags & MSG_PEEK) {
1222                    int clear = 0;
1223                    spin_lock_bh(&sk->sk_receive_queue.lock);
1224                    if (skb == skb_peek(&sk->sk_receive_queue)) {
1225                            __skb_unlink(skb, &sk->sk_receive_queue);
1226                            clear = 1;
1227                    }
1228                    spin_unlock_bh(&sk->sk_receive_queue.lock);
1229                    if (clear)
1230                            kfree_skb(skb);
1231            }
1232            skb_free_datagram(sk, skb);
1233    }
1234    #endif
1235    
1236  EXPORT_SYMBOL(CheckNetworkListenACL);  /*
1237  EXPORT_SYMBOL(CheckNetworkConnectACL);   * Check permission for receiving a datagram via a UDP or RAW socket.
1238  EXPORT_SYMBOL(CheckNetworkBindACL);   *
1239  EXPORT_SYMBOL(CheckNetworkAcceptACL);   * Currently, the LSM hook for this purpose is not provided.
1240  EXPORT_SYMBOL(CheckNetworkSendMsgACL);   */
1241  EXPORT_SYMBOL(CheckNetworkRecvMsgACL);  int ccs_socket_recvmsg_permission(struct sock *sk, struct sk_buff *skb,
1242                                      const unsigned int flags)
1243    {
1244            int error = 0;
1245            const unsigned int type = sk->sk_type;
1246            if (type != SOCK_DGRAM && type != SOCK_RAW)
1247                    return 0;
1248            /* Nothing to do if I am a kernel service. */
1249            if (segment_eq(get_fs(), KERNEL_DS))
1250                    return 0;
1251    
1252  /***** TOMOYO Linux end. *****/          switch (sk->sk_family) {
1253                    struct in6_addr sin6;
1254                    struct in_addr sin4;
1255                    u16 port;
1256            case PF_INET6:
1257                    if (type == SOCK_DGRAM) { /* UDP IPv6 */
1258                            if (skb->protocol == htons(ETH_P_IP)) {
1259                                    ipv6_addr_set(&sin6, 0, 0, htonl(0xffff),
1260                                                  ip_hdr(skb)->saddr);
1261                            } else {
1262                                    ipv6_addr_copy(&sin6, &ipv6_hdr(skb)->saddr);
1263                            }
1264                            port = udp_hdr(skb)->source;
1265                    } else { /* RAW IPv6 */
1266                            ipv6_addr_copy(&sin6, &ipv6_hdr(skb)->saddr);
1267                            port = htons(sk->sk_protocol);
1268                    }
1269                    error = ccs_check_network_recvmsg_acl(true, type,
1270                                                          (u8 *) &sin6, port);
1271                    break;
1272            case PF_INET:
1273                    if (type == SOCK_DGRAM) { /* UDP IPv4 */
1274                            sin4.s_addr = ip_hdr(skb)->saddr;
1275                            port = udp_hdr(skb)->source;
1276                    } else { /* RAW IPv4 */
1277                            sin4.s_addr = ip_hdr(skb)->saddr;
1278                            port = htons(sk->sk_protocol);
1279                    }
1280                    error = ccs_check_network_recvmsg_acl(false, type,
1281                                                          (u8 *) &sin4, port);
1282                    break;
1283            }
1284            if (!error)
1285                    return 0;
1286            /*
1287             * Remove from queue if MSG_PEEK is used so that
1288             * the head message from unwanted source in receive queue will not
1289             * prevent the caller from picking up next message from wanted source
1290             * when the caller is using MSG_PEEK flag for picking up.
1291             */
1292    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1293            if (type == SOCK_DGRAM)
1294                    lock_sock(sk);
1295    #endif
1296            skb_kill_datagram(sk, skb, flags);
1297    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1298            if (type == SOCK_DGRAM)
1299                    release_sock(sk);
1300    #endif
1301            /* Hope less harmful than -EPERM. */
1302            return -ENOMEM;
1303    }
1304    EXPORT_SYMBOL(ccs_socket_recvmsg_permission);

Legend:
Removed from v.111  
changed lines
  Added in v.2860

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