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

Subversion リポジトリの参照

Contents of /branches/ccs-patch/security/ccsecurity/network.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2922 - (show annotations) (download) (as text)
Wed Aug 19 04:26:56 2009 UTC (14 years, 9 months ago) by kumaneko
File MIME type: text/x-csrc
File size: 24358 byte(s)


1 /*
2 * security/ccsecurity/network.c
3 *
4 * Copyright (C) 2005-2009 NTT DATA CORPORATION
5 *
6 * Version: 1.7.0-pre 2009/08/08
7 *
8 * This file is applicable to both 2.4.30 and 2.6.11 and later.
9 * See README.ccs for ChangeLog.
10 *
11 */
12
13 #include <linux/net.h>
14 #include <linux/inet.h>
15 #include <linux/in.h>
16 #include <linux/in6.h>
17 #include <net/ip.h>
18 #include <net/ipv6.h>
19 #include <net/udp.h>
20 #include "internal.h"
21
22 /**
23 * ccs_audit_network_log - Audit network log.
24 *
25 * @r: Pointer to "struct ccs_request_info".
26 * @operation: The name of operation.
27 * @address: An IPv4 or IPv6 address.
28 * @port: Port number.
29 * @is_granted: True if this is a granted log.
30 *
31 * Returns 0 on success, negative value otherwise.
32 */
33 static int ccs_audit_network_log(struct ccs_request_info *r,
34 const char *operation, const char *address,
35 const u16 port, const bool is_granted)
36 {
37 if (!is_granted && ccs_verbose_mode(r->domain))
38 printk(KERN_WARNING "%s: %s to %s %u denied for %s\n",
39 ccs_get_msg(r->mode == 3), operation, address, port,
40 ccs_get_last_name(r->domain));
41 return ccs_write_audit_log(is_granted, r, CCS_KEYWORD_ALLOW_NETWORK
42 "%s %s %u\n", operation, address, port);
43 }
44
45 /**
46 * ccs_parse_ip_address - Parse an IP address.
47 *
48 * @address: String to parse.
49 * @min: Pointer to store min address.
50 * @max: Pointer to store max address.
51 *
52 * Returns 2 if @address is an IPv6, 1 if @address is an IPv4, 0 otherwise.
53 */
54 int ccs_parse_ip_address(char *address, u16 *min, u16 *max)
55 {
56 int count = sscanf(address, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"
57 "-%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
58 &min[0], &min[1], &min[2], &min[3],
59 &min[4], &min[5], &min[6], &min[7],
60 &max[0], &max[1], &max[2], &max[3],
61 &max[4], &max[5], &max[6], &max[7]);
62 if (count == 8 || count == 16) {
63 u8 i;
64 if (count == 8)
65 memmove(max, min, sizeof(u16) * 8);
66 for (i = 0; i < 8; i++) {
67 min[i] = htons(min[i]);
68 max[i] = htons(max[i]);
69 }
70 return 2;
71 }
72 count = sscanf(address, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu",
73 &min[0], &min[1], &min[2], &min[3],
74 &max[0], &max[1], &max[2], &max[3]);
75 if (count == 4 || count == 8) {
76 u32 ip = htonl((((u8) min[0]) << 24) + (((u8) min[1]) << 16)
77 + (((u8) min[2]) << 8) + (u8) min[3]);
78 memmove(min, &ip, sizeof(ip));
79 if (count == 8)
80 ip = htonl((((u8) max[0]) << 24) + (((u8) max[1]) << 16)
81 + (((u8) max[2]) << 8) + (u8) max[3]);
82 memmove(max, &ip, sizeof(ip));
83 return 1;
84 }
85 return 0;
86 }
87
88 #if !defined(NIP6)
89 #define NIP6(addr) \
90 ntohs((addr).s6_addr16[0]), ntohs((addr).s6_addr16[1]), \
91 ntohs((addr).s6_addr16[2]), ntohs((addr).s6_addr16[3]), \
92 ntohs((addr).s6_addr16[4]), ntohs((addr).s6_addr16[5]), \
93 ntohs((addr).s6_addr16[6]), ntohs((addr).s6_addr16[7])
94 #endif
95
96 /**
97 * ccs_print_ipv6 - Print an IPv6 address.
98 *
99 * @buffer: Buffer to write to.
100 * @buffer_len: Size of @buffer.
101 * @ip: Pointer to "struct in6_addr".
102 *
103 * Returns nothing.
104 */
105 void ccs_print_ipv6(char *buffer, const int buffer_len,
106 const struct in6_addr *ip)
107 {
108 memset(buffer, 0, buffer_len);
109 snprintf(buffer, buffer_len - 1, "%x:%x:%x:%x:%x:%x:%x:%x", NIP6(*ip));
110 }
111
112 /**
113 * ccs_net2keyword - Convert network operation index to network operation name.
114 *
115 * @operation: Type of operation.
116 *
117 * Returns the name of operation.
118 */
119 const char *ccs_net2keyword(const u8 operation)
120 {
121 const char *keyword = "unknown";
122 switch (operation) {
123 case CCS_NETWORK_UDP_BIND:
124 keyword = "UDP bind";
125 break;
126 case CCS_NETWORK_UDP_CONNECT:
127 keyword = "UDP connect";
128 break;
129 case CCS_NETWORK_TCP_BIND:
130 keyword = "TCP bind";
131 break;
132 case CCS_NETWORK_TCP_LISTEN:
133 keyword = "TCP listen";
134 break;
135 case CCS_NETWORK_TCP_CONNECT:
136 keyword = "TCP connect";
137 break;
138 case CCS_NETWORK_TCP_ACCEPT:
139 keyword = "TCP accept";
140 break;
141 case CCS_NETWORK_RAW_BIND:
142 keyword = "RAW bind";
143 break;
144 case CCS_NETWORK_RAW_CONNECT:
145 keyword = "RAW connect";
146 break;
147 }
148 return keyword;
149 }
150
151 /**
152 * ccs_network_entry2 - Check permission for network operation.
153 *
154 * @is_ipv6: True if @address is an IPv6 address.
155 * @operation: Type of operation.
156 * @address: An IPv4 or IPv6 address.
157 * @port: Port number.
158 *
159 * Returns 0 on success, negative value otherwise.
160 *
161 * Caller holds ccs_read_lock().
162 */
163 static int ccs_network_entry2(const bool is_ipv6, const u8 operation,
164 const u32 *address, const u16 port)
165 {
166 struct ccs_request_info r;
167 struct ccs_acl_info *ptr;
168 const char *keyword = ccs_net2keyword(operation);
169 bool is_enforce;
170 const u16 perm = 1 << operation;
171 /* using host byte order to allow u32 comparison than memcmp().*/
172 const u32 ip = ntohl(*address);
173 int error;
174 char buf[64];
175 ccs_assert_read_lock();
176 if (!ccs_can_sleep() ||
177 !ccs_init_request_info(&r, NULL, CCS_MAC_NETWORK))
178 return 0;
179 is_enforce = (r.mode == 3);
180 retry:
181 error = -EPERM;
182 list_for_each_entry_rcu(ptr, &r.domain->acl_info_list, list) {
183 struct ccs_ip_network_acl *acl;
184 if (ptr->is_deleted || ptr->type != CCS_TYPE_IP_NETWORK_ACL)
185 continue;
186 acl = container_of(ptr, struct ccs_ip_network_acl, head);
187 if (!(acl->perm & perm))
188 continue;
189 if (!ccs_compare_number_union(port, &acl->port) ||
190 !ccs_condition(&r, ptr))
191 continue;
192 if (acl->address_type == CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP) {
193 if (!ccs_address_matches_group(is_ipv6, address,
194 acl->address.group))
195 continue;
196 } else if (acl->address_type == CCS_IP_ADDRESS_TYPE_IPv4) {
197 if (is_ipv6 ||
198 ip < acl->address.ipv4.min ||
199 acl->address.ipv4.max < ip)
200 continue;
201 } else {
202 if (!is_ipv6 ||
203 memcmp(acl->address.ipv6.min, address, 16) > 0 ||
204 memcmp(address, acl->address.ipv6.max, 16) > 0)
205 continue;
206 }
207 r.cond = ptr->cond;
208 error = 0;
209 break;
210 }
211 memset(buf, 0, sizeof(buf));
212 if (is_ipv6)
213 ccs_print_ipv6(buf, sizeof(buf),
214 (const struct in6_addr *) address);
215 else
216 snprintf(buf, sizeof(buf) - 1, "%u.%u.%u.%u", HIPQUAD(ip));
217 ccs_audit_network_log(&r, keyword, buf, port, !error);
218 if (error)
219 error = ccs_supervisor(&r, CCS_KEYWORD_ALLOW_NETWORK
220 "%s %s %u\n", keyword, buf, port);
221 if (error == 1)
222 goto retry;
223 if (!is_enforce)
224 error = 0;
225 return error;
226 }
227
228 /**
229 * ccs_network_entry - Check permission for network operation.
230 *
231 * @is_ipv6: True if @address is an IPv6 address.
232 * @operation: Type of operation.
233 * @address: An IPv4 or IPv6 address.
234 * @port: Port number.
235 *
236 * Returns 0 on success, negative value otherwise.
237 */
238 static int ccs_network_entry(const bool is_ipv6, const u8 operation,
239 const u32 *address, const u16 port)
240 {
241 const int idx = ccs_read_lock();
242 const int error = ccs_network_entry2(is_ipv6, operation,
243 address, port);
244 ccs_read_unlock(idx);
245 return error;
246 }
247
248 /**
249 * ccs_write_network_policy - Write "struct ccs_ip_network_acl" list.
250 *
251 * @data: String to parse.
252 * @domain: Pointer to "struct ccs_domain_info".
253 * @condition: Pointer to "struct ccs_condition". May be NULL.
254 * @is_delete: True if it is a delete request.
255 *
256 * Returns 0 on success, negative value otherwise.
257 */
258 int ccs_write_network_policy(char *data, struct ccs_domain_info *domain,
259 struct ccs_condition *condition,
260 const bool is_delete)
261 {
262 struct ccs_ip_network_acl *entry = NULL;
263 struct ccs_acl_info *ptr;
264 struct ccs_ip_network_acl e = {
265 .head.type = CCS_TYPE_IP_NETWORK_ACL,
266 .head.cond = condition,
267 };
268 u16 min_address[8];
269 u16 max_address[8];
270 int error = is_delete ? -ENOENT : -ENOMEM;
271 u8 sock_type;
272 char *w[4];
273 if (!ccs_tokenize(data, w, sizeof(w)) || !w[3][0])
274 return -EINVAL;
275 if (!strcmp(w[0], "TCP"))
276 sock_type = SOCK_STREAM;
277 else if (!strcmp(w[0], "UDP"))
278 sock_type = SOCK_DGRAM;
279 else if (!strcmp(w[0], "RAW"))
280 sock_type = SOCK_RAW;
281 else
282 return -EINVAL;
283 if (!strcmp(w[1], "bind"))
284 switch (sock_type) {
285 case SOCK_STREAM:
286 e.perm = 1 << CCS_NETWORK_TCP_BIND;
287 break;
288 case SOCK_DGRAM:
289 e.perm = 1 << CCS_NETWORK_UDP_BIND;
290 break;
291 default:
292 e.perm = 1 << CCS_NETWORK_RAW_BIND;
293 break;
294 }
295 else if (!strcmp(w[1], "connect"))
296 switch (sock_type) {
297 case SOCK_STREAM:
298 e.perm = 1 << CCS_NETWORK_TCP_CONNECT;
299 break;
300 case SOCK_DGRAM:
301 e.perm = 1 << CCS_NETWORK_UDP_CONNECT;
302 break;
303 default:
304 e.perm = 1 << CCS_NETWORK_RAW_CONNECT;
305 break;
306 }
307 else if (sock_type == SOCK_STREAM && !strcmp(w[1], "listen"))
308 e.perm = 1 << CCS_NETWORK_TCP_LISTEN;
309 else if (sock_type == SOCK_STREAM && !strcmp(w[1], "accept"))
310 e.perm = 1 << CCS_NETWORK_TCP_ACCEPT;
311 else
312 return -EINVAL;
313 switch (ccs_parse_ip_address(w[2], min_address, max_address)) {
314 case 2:
315 e.address_type = CCS_IP_ADDRESS_TYPE_IPv6;
316 e.address.ipv6.min = ccs_get_ipv6_address((struct in6_addr *)
317 min_address);
318 e.address.ipv6.max = ccs_get_ipv6_address((struct in6_addr *)
319 max_address);
320 if (!e.address.ipv6.min || !e.address.ipv6.max)
321 goto out;
322 break;
323 case 1:
324 e.address_type = CCS_IP_ADDRESS_TYPE_IPv4;
325 /* use host byte order to allow u32 comparison.*/
326 e.address.ipv4.min = ntohl(* (u32 *) min_address);
327 e.address.ipv4.max = ntohl(* (u32 *) max_address);
328 break;
329 default:
330 if (w[2][0] != '@')
331 return -EINVAL;
332 e.address_type = CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP;
333 e.address.group = ccs_get_address_group(w[2] + 1);
334 if (!e.address.group)
335 return -ENOMEM;
336 break;
337 }
338 if (!ccs_parse_number_union(w[3], &e.port))
339 goto out;
340 if (!is_delete)
341 entry = kmalloc(sizeof(e), GFP_KERNEL);
342 mutex_lock(&ccs_policy_lock);
343 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
344 struct ccs_ip_network_acl *acl =
345 container_of(ptr, struct ccs_ip_network_acl,
346 head);
347 if (ptr->type != CCS_TYPE_IP_NETWORK_ACL ||
348 ptr->cond != condition ||
349 ccs_memcmp(acl, &e, offsetof(typeof(e), address_type),
350 sizeof(e)))
351 continue;
352 if (is_delete) {
353 acl->perm &= ~e.perm;
354 if (!acl->perm)
355 ptr->is_deleted = true;
356 } else {
357 if (ptr->is_deleted)
358 acl->perm = 0;
359 acl->perm |= e.perm;
360 ptr->is_deleted = false;
361 }
362 error = 0;
363 break;
364 }
365 if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
366 ccs_add_domain_acl(domain, &entry->head);
367 entry = NULL;
368 error = 0;
369 }
370 mutex_unlock(&ccs_policy_lock);
371 out:
372 if (w[2][0] == '@')
373 ccs_put_address_group(e.address.group);
374 else if (e.address_type == CCS_IP_ADDRESS_TYPE_IPv6) {
375 ccs_put_ipv6_address(e.address.ipv6.min);
376 ccs_put_ipv6_address(e.address.ipv6.max);
377 }
378 ccs_put_number_union(&e.port);
379 kfree(entry);
380 return error;
381 }
382
383 /**
384 * ccs_network_listen_acl - Check permission for listen() operation.
385 *
386 * @is_ipv6: True if @address is an IPv6 address.
387 * @address: An IPv4 or IPv6 address.
388 * @port: Port number.
389 *
390 * Returns 0 on success, negative value otherwise.
391 */
392 static inline int ccs_network_listen_acl(const bool is_ipv6,
393 const u8 *address,
394 const u16 port)
395 {
396 return ccs_network_entry(is_ipv6, CCS_NETWORK_TCP_LISTEN,
397 (const u32 *) address, ntohs(port));
398 }
399
400 /**
401 * ccs_network_connect_acl - Check permission for connect() operation.
402 *
403 * @is_ipv6: True if @address is an IPv6 address.
404 * @sock_type: Type of socket. (TCP or UDP or RAW)
405 * @address: An IPv4 or IPv6 address.
406 * @port: Port number.
407 *
408 * Returns 0 on success, negative value otherwise.
409 */
410 static inline int ccs_network_connect_acl(const bool is_ipv6,
411 const int sock_type,
412 const u8 *address,
413 const u16 port)
414 {
415 u8 operation;
416 switch (sock_type) {
417 case SOCK_STREAM:
418 operation = CCS_NETWORK_TCP_CONNECT;
419 break;
420 case SOCK_DGRAM:
421 operation = CCS_NETWORK_UDP_CONNECT;
422 break;
423 default:
424 operation = CCS_NETWORK_RAW_CONNECT;
425 }
426 return ccs_network_entry(is_ipv6, operation,
427 (const u32 *) address, ntohs(port));
428 }
429
430 /**
431 * ccs_network_bind_acl - Check permission for bind() operation.
432 *
433 * @is_ipv6: True if @address is an IPv6 address.
434 * @sock_type: Type of socket. (TCP or UDP or RAW)
435 * @address: An IPv4 or IPv6 address.
436 * @port: Port number.
437 *
438 * Returns 0 on success, negative value otherwise.
439 */
440 static int ccs_network_bind_acl(const bool is_ipv6, const int sock_type,
441 const u8 *address, const u16 port)
442 {
443 u8 operation;
444 switch (sock_type) {
445 case SOCK_STREAM:
446 operation = CCS_NETWORK_TCP_BIND;
447 break;
448 case SOCK_DGRAM:
449 operation = CCS_NETWORK_UDP_BIND;
450 break;
451 default:
452 operation = CCS_NETWORK_RAW_BIND;
453 }
454 return ccs_network_entry(is_ipv6, operation,
455 (const u32 *) address, ntohs(port));
456 }
457
458 /**
459 * ccs_network_accept_acl - Check permission for accept() operation.
460 *
461 * @is_ipv6: True if @address is an IPv6 address.
462 * @address: An IPv4 or IPv6 address.
463 * @port: Port number.
464 *
465 * Returns 0 on success, negative value otherwise.
466 */
467 static inline int ccs_network_accept_acl(const bool is_ipv6,
468 const u8 *address,
469 const u16 port)
470 {
471 int retval;
472 current->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
473 retval = ccs_network_entry(is_ipv6, CCS_NETWORK_TCP_ACCEPT,
474 (const u32 *) address, ntohs(port));
475 current->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
476 return retval;
477 }
478
479 /**
480 * ccs_network_sendmsg_acl - Check permission for sendmsg() operation.
481 *
482 * @is_ipv6: True if @address is an IPv6 address.
483 * @sock_type: Type of socket. (UDP or RAW)
484 * @address: An IPv4 or IPv6 address.
485 * @port: Port number.
486 *
487 * Returns 0 on success, negative value otherwise.
488 */
489 static inline int ccs_network_sendmsg_acl(const bool is_ipv6,
490 const int sock_type,
491 const u8 *address,
492 const u16 port)
493 {
494 u8 operation;
495 if (sock_type == SOCK_DGRAM)
496 operation = CCS_NETWORK_UDP_CONNECT;
497 else
498 operation = CCS_NETWORK_RAW_CONNECT;
499 return ccs_network_entry(is_ipv6, operation,
500 (const u32 *) address, ntohs(port));
501 }
502
503 /**
504 * ccs_network_recvmsg_acl - Check permission for recvmsg() operation.
505 *
506 * @is_ipv6: True if @address is an IPv6 address.
507 * @sock_type: Type of socket. (UDP or RAW)
508 * @address: An IPv4 or IPv6 address.
509 * @port: Port number.
510 *
511 * Returns 0 on success, negative value otherwise.
512 */
513 static inline int ccs_network_recvmsg_acl(const bool is_ipv6,
514 const int sock_type,
515 const u8 *address,
516 const u16 port)
517 {
518 int retval;
519 const u8 operation
520 = (sock_type == SOCK_DGRAM) ?
521 CCS_NETWORK_UDP_CONNECT : CCS_NETWORK_RAW_CONNECT;
522 current->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
523 retval = ccs_network_entry(is_ipv6, operation,
524 (const u32 *) address, ntohs(port));
525 current->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
526 return retval;
527 }
528
529 #define MAX_SOCK_ADDR 128 /* net/socket.c */
530
531 /* Check permission for creating a socket. */
532 int ccs_socket_create_permission(int family, int type, int protocol)
533 {
534 int error = 0;
535 /* Nothing to do if I am a kernel service. */
536 if (segment_eq(get_fs(), KERNEL_DS))
537 return 0;
538 if (family == PF_PACKET && !ccs_capable(CCS_USE_PACKET_SOCKET))
539 return -EPERM;
540 if (family == PF_ROUTE && !ccs_capable(CCS_USE_ROUTE_SOCKET))
541 return -EPERM;
542 if (family != PF_INET && family != PF_INET6)
543 return 0;
544 switch (type) {
545 case SOCK_STREAM:
546 if (!ccs_capable(CCS_INET_STREAM_SOCKET_CREATE))
547 error = -EPERM;
548 break;
549 case SOCK_DGRAM:
550 if (!ccs_capable(CCS_USE_INET_DGRAM_SOCKET))
551 error = -EPERM;
552 break;
553 case SOCK_RAW:
554 if (!ccs_capable(CCS_USE_INET_RAW_SOCKET))
555 error = -EPERM;
556 break;
557 }
558 return error;
559 }
560
561 /* Check permission for listening a TCP socket. */
562 int ccs_socket_listen_permission(struct socket *sock)
563 {
564 int error = 0;
565 char addr[MAX_SOCK_ADDR];
566 int addr_len;
567 /* Nothing to do if I am a kernel service. */
568 if (segment_eq(get_fs(), KERNEL_DS))
569 return 0;
570 if (sock->type != SOCK_STREAM)
571 return 0;
572 switch (sock->sk->sk_family) {
573 case PF_INET:
574 case PF_INET6:
575 break;
576 default:
577 return 0;
578 }
579 if (!ccs_capable(CCS_INET_STREAM_SOCKET_LISTEN))
580 return -EPERM;
581 if (sock->ops->getname(sock, (struct sockaddr *) addr, &addr_len, 0))
582 return -EPERM;
583 switch (((struct sockaddr *) addr)->sa_family) {
584 struct sockaddr_in6 *addr6;
585 struct sockaddr_in *addr4;
586 case AF_INET6:
587 addr6 = (struct sockaddr_in6 *) addr;
588 error = ccs_network_listen_acl(true,
589 addr6->sin6_addr.s6_addr,
590 addr6->sin6_port);
591 break;
592 case AF_INET:
593 addr4 = (struct sockaddr_in *) addr;
594 error = ccs_network_listen_acl(false,
595 (u8 *) &addr4->sin_addr,
596 addr4->sin_port);
597 break;
598 }
599 return error;
600 }
601
602 /* Check permission for setting the remote IP address/port pair of a socket. */
603 int ccs_socket_connect_permission(struct socket *sock, struct sockaddr *addr,
604 int addr_len)
605 {
606 int error = 0;
607 const unsigned int type = sock->type;
608 /* Nothing to do if I am a kernel service. */
609 if (segment_eq(get_fs(), KERNEL_DS))
610 return 0;
611 switch (type) {
612 case SOCK_STREAM:
613 case SOCK_DGRAM:
614 case SOCK_RAW:
615 break;
616 default:
617 return 0;
618 }
619 switch (addr->sa_family) {
620 struct sockaddr_in6 *addr6;
621 struct sockaddr_in *addr4;
622 u16 port;
623 case AF_INET6:
624 if (addr_len < SIN6_LEN_RFC2133)
625 break;
626 addr6 = (struct sockaddr_in6 *) addr;
627 if (type != SOCK_RAW)
628 port = addr6->sin6_port;
629 else
630 port = htons(sock->sk->sk_protocol);
631 error = ccs_network_connect_acl(true, type,
632 addr6->sin6_addr.s6_addr,
633 port);
634 break;
635 case AF_INET:
636 if (addr_len < sizeof(struct sockaddr_in))
637 break;
638 addr4 = (struct sockaddr_in *) addr;
639 if (type != SOCK_RAW)
640 port = addr4->sin_port;
641 else
642 port = htons(sock->sk->sk_protocol);
643 error = ccs_network_connect_acl(false, type,
644 (u8 *) &addr4->sin_addr,
645 port);
646 break;
647 }
648 if (type != SOCK_STREAM)
649 return error;
650 switch (sock->sk->sk_family) {
651 case PF_INET:
652 case PF_INET6:
653 if (!ccs_capable(CCS_INET_STREAM_SOCKET_CONNECT))
654 error = -EPERM;
655 break;
656 }
657 return error;
658 }
659
660 /* Check permission for setting the local IP address/port pair of a socket. */
661 int ccs_socket_bind_permission(struct socket *sock, struct sockaddr *addr,
662 int addr_len)
663 {
664 int error = 0;
665 const unsigned int type = sock->type;
666 /* Nothing to do if I am a kernel service. */
667 if (segment_eq(get_fs(), KERNEL_DS))
668 return 0;
669 switch (type) {
670 case SOCK_STREAM:
671 case SOCK_DGRAM:
672 case SOCK_RAW:
673 break;
674 default:
675 return 0;
676 }
677 switch (addr->sa_family) {
678 struct sockaddr_in6 *addr6;
679 struct sockaddr_in *addr4;
680 u16 port;
681 case AF_INET6:
682 if (addr_len < SIN6_LEN_RFC2133)
683 break;
684 addr6 = (struct sockaddr_in6 *) addr;
685 if (type != SOCK_RAW)
686 port = addr6->sin6_port;
687 else
688 port = htons(sock->sk->sk_protocol);
689 error = ccs_network_bind_acl(true, type,
690 addr6->sin6_addr.s6_addr,
691 port);
692 break;
693 case AF_INET:
694 if (addr_len < sizeof(struct sockaddr_in))
695 break;
696 addr4 = (struct sockaddr_in *) addr;
697 if (type != SOCK_RAW)
698 port = addr4->sin_port;
699 else
700 port = htons(sock->sk->sk_protocol);
701 error = ccs_network_bind_acl(false, type,
702 (u8 *) &addr4->sin_addr,
703 port);
704 break;
705 }
706 return error;
707 }
708
709 /*
710 * Check permission for accepting a TCP socket.
711 *
712 * Currently, the LSM hook for this purpose is not provided.
713 */
714 int ccs_socket_accept_permission(struct socket *sock, struct sockaddr *addr)
715 {
716 int error = 0;
717 int addr_len;
718 /* Nothing to do if I am a kernel service. */
719 if (segment_eq(get_fs(), KERNEL_DS))
720 return 0;
721 switch (sock->sk->sk_family) {
722 case PF_INET:
723 case PF_INET6:
724 break;
725 default:
726 return 0;
727 }
728 error = sock->ops->getname(sock, addr, &addr_len, 2);
729 if (error)
730 return error;
731 switch (addr->sa_family) {
732 struct sockaddr_in6 *addr6;
733 struct sockaddr_in *addr4;
734 case AF_INET6:
735 addr6 = (struct sockaddr_in6 *) addr;
736 error = ccs_network_accept_acl(true,
737 addr6->sin6_addr.s6_addr,
738 addr6->sin6_port);
739 break;
740 case AF_INET:
741 addr4 = (struct sockaddr_in *) addr;
742 error = ccs_network_accept_acl(false,
743 (u8 *) &addr4->sin_addr,
744 addr4->sin_port);
745 break;
746 }
747 return error;
748 }
749
750 /* Check permission for sending a datagram via a UDP or RAW socket. */
751 int ccs_socket_sendmsg_permission(struct socket *sock, struct sockaddr *addr,
752 int addr_len)
753 {
754 int error = 0;
755 const int type = sock->type;
756 /* Nothing to do if I am a kernel service. */
757 if (segment_eq(get_fs(), KERNEL_DS))
758 return 0;
759 if (!addr || (type != SOCK_DGRAM && type != SOCK_RAW))
760 return 0;
761 switch (addr->sa_family) {
762 struct sockaddr_in6 *addr6;
763 struct sockaddr_in *addr4;
764 u16 port;
765 case AF_INET6:
766 if (addr_len < SIN6_LEN_RFC2133)
767 break;
768 addr6 = (struct sockaddr_in6 *) addr;
769 if (type == SOCK_DGRAM)
770 port = addr6->sin6_port;
771 else
772 port = htons(sock->sk->sk_protocol);
773 error = ccs_network_sendmsg_acl(true, type,
774 addr6->sin6_addr.s6_addr,
775 port);
776 break;
777 case AF_INET:
778 if (addr_len < sizeof(struct sockaddr_in))
779 break;
780 addr4 = (struct sockaddr_in *) addr;
781 if (type == SOCK_DGRAM)
782 port = addr4->sin_port;
783 else
784 port = htons(sock->sk->sk_protocol);
785 error = ccs_network_sendmsg_acl(false, type,
786 (u8 *) &addr4->sin_addr,
787 port);
788 break;
789 }
790 return error;
791 }
792
793 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
794 #if !defined(RHEL_MAJOR) || RHEL_MAJOR != 5
795
796 static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
797 {
798 return skb->nh.iph;
799 }
800
801 static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
802 {
803 return skb->h.uh;
804 }
805
806 static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb)
807 {
808 return skb->nh.ipv6h;
809 }
810
811 #endif
812 #endif
813
814 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
815 static void skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
816 unsigned int flags)
817 {
818 /* Clear queue. */
819 if (flags & MSG_PEEK) {
820 int clear = 0;
821 spin_lock_irq(&sk->sk_receive_queue.lock);
822 if (skb == skb_peek(&sk->sk_receive_queue)) {
823 __skb_unlink(skb, &sk->sk_receive_queue);
824 clear = 1;
825 }
826 spin_unlock_irq(&sk->sk_receive_queue.lock);
827 if (clear)
828 kfree_skb(skb);
829 }
830 skb_free_datagram(sk, skb);
831 }
832 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
833 static void skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
834 unsigned int flags)
835 {
836 /* Clear queue. */
837 if (flags & MSG_PEEK) {
838 int clear = 0;
839 spin_lock_bh(&sk->sk_receive_queue.lock);
840 if (skb == skb_peek(&sk->sk_receive_queue)) {
841 __skb_unlink(skb, &sk->sk_receive_queue);
842 clear = 1;
843 }
844 spin_unlock_bh(&sk->sk_receive_queue.lock);
845 if (clear)
846 kfree_skb(skb);
847 }
848 skb_free_datagram(sk, skb);
849 }
850 #endif
851
852 /*
853 * Check permission for receiving a datagram via a UDP or RAW socket.
854 *
855 * Currently, the LSM hook for this purpose is not provided.
856 */
857 int ccs_socket_recvmsg_permission(struct sock *sk, struct sk_buff *skb,
858 const unsigned int flags)
859 {
860 int error = 0;
861 const unsigned int type = sk->sk_type;
862 if (type != SOCK_DGRAM && type != SOCK_RAW)
863 return 0;
864 /* Nothing to do if I am a kernel service. */
865 if (segment_eq(get_fs(), KERNEL_DS))
866 return 0;
867
868 switch (sk->sk_family) {
869 struct in6_addr sin6;
870 struct in_addr sin4;
871 u16 port;
872 case PF_INET6:
873 if (type == SOCK_DGRAM) { /* UDP IPv6 */
874 if (skb->protocol == htons(ETH_P_IP)) {
875 ipv6_addr_set(&sin6, 0, 0, htonl(0xffff),
876 ip_hdr(skb)->saddr);
877 } else {
878 ipv6_addr_copy(&sin6, &ipv6_hdr(skb)->saddr);
879 }
880 port = udp_hdr(skb)->source;
881 } else { /* RAW IPv6 */
882 ipv6_addr_copy(&sin6, &ipv6_hdr(skb)->saddr);
883 port = htons(sk->sk_protocol);
884 }
885 error = ccs_network_recvmsg_acl(true, type,
886 (u8 *) &sin6, port);
887 break;
888 case PF_INET:
889 if (type == SOCK_DGRAM) { /* UDP IPv4 */
890 sin4.s_addr = ip_hdr(skb)->saddr;
891 port = udp_hdr(skb)->source;
892 } else { /* RAW IPv4 */
893 sin4.s_addr = ip_hdr(skb)->saddr;
894 port = htons(sk->sk_protocol);
895 }
896 error = ccs_network_recvmsg_acl(false, type,
897 (u8 *) &sin4, port);
898 break;
899 }
900 if (!error)
901 return 0;
902 /*
903 * Remove from queue if MSG_PEEK is used so that
904 * the head message from unwanted source in receive queue will not
905 * prevent the caller from picking up next message from wanted source
906 * when the caller is using MSG_PEEK flag for picking up.
907 */
908 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
909 if (type == SOCK_DGRAM)
910 lock_sock(sk);
911 #endif
912 skb_kill_datagram(sk, skb, flags);
913 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
914 if (type == SOCK_DGRAM)
915 release_sock(sk);
916 #endif
917 /* Hope less harmful than -EPERM. */
918 return -ENOMEM;
919 }
920 EXPORT_SYMBOL(ccs_socket_recvmsg_permission);

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