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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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