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

Subversion リポジトリの参照

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

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

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

Legend:
Removed from v.776  
changed lines
  Added in v.2209

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