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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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