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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3129 - (show annotations) (download) (as text)
Mon Nov 2 06:16:30 2009 UTC (14 years, 6 months ago) by kumaneko
Original Path: trunk/1.7.x/ccs-patch/security/ccsecurity/network.c
File MIME type: text/x-csrc
File size: 24360 byte(s)


1 /*
2 * security/ccsecurity/network.c
3 *
4 * Copyright (C) 2005-2009 NTT DATA CORPORATION
5 *
6 * Version: 1.7.1-pre 2009/11/02
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, address,
248 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, const u8 *address,
398 const u16 port)
399 {
400 return ccs_network_entry(is_ipv6, CCS_NETWORK_TCP_LISTEN,
401 (const u32 *) address, ntohs(port));
402 }
403
404 /**
405 * ccs_network_connect_acl - Check permission for connect() operation.
406 *
407 * @is_ipv6: True if @address is an IPv6 address.
408 * @sock_type: Type of socket. (TCP or UDP or RAW)
409 * @address: An IPv4 or IPv6 address.
410 * @port: Port number.
411 *
412 * Returns 0 on success, negative value otherwise.
413 */
414 static inline int ccs_network_connect_acl(const bool is_ipv6,
415 const int sock_type,
416 const u8 *address, const u16 port)
417 {
418 u8 operation;
419 switch (sock_type) {
420 case SOCK_STREAM:
421 operation = CCS_NETWORK_TCP_CONNECT;
422 break;
423 case SOCK_DGRAM:
424 operation = CCS_NETWORK_UDP_CONNECT;
425 break;
426 default:
427 operation = CCS_NETWORK_RAW_CONNECT;
428 }
429 return ccs_network_entry(is_ipv6, operation,
430 (const u32 *) address, ntohs(port));
431 }
432
433 /**
434 * ccs_network_bind_acl - Check permission for bind() operation.
435 *
436 * @is_ipv6: True if @address is an IPv6 address.
437 * @sock_type: Type of socket. (TCP or UDP or RAW)
438 * @address: An IPv4 or IPv6 address.
439 * @port: Port number.
440 *
441 * Returns 0 on success, negative value otherwise.
442 */
443 static int ccs_network_bind_acl(const bool is_ipv6, const int sock_type,
444 const u8 *address, const u16 port)
445 {
446 u8 operation;
447 switch (sock_type) {
448 case SOCK_STREAM:
449 operation = CCS_NETWORK_TCP_BIND;
450 break;
451 case SOCK_DGRAM:
452 operation = CCS_NETWORK_UDP_BIND;
453 break;
454 default:
455 operation = CCS_NETWORK_RAW_BIND;
456 }
457 return ccs_network_entry(is_ipv6, operation,
458 (const u32 *) address, ntohs(port));
459 }
460
461 /**
462 * ccs_network_accept_acl - Check permission for accept() operation.
463 *
464 * @is_ipv6: True if @address is an IPv6 address.
465 * @address: An IPv4 or IPv6 address.
466 * @port: Port number.
467 *
468 * Returns 0 on success, negative value otherwise.
469 */
470 static inline int ccs_network_accept_acl(const bool is_ipv6, const u8 *address,
471 const u16 port)
472 {
473 int retval;
474 current->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
475 retval = ccs_network_entry(is_ipv6, CCS_NETWORK_TCP_ACCEPT,
476 (const u32 *) address, ntohs(port));
477 current->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
478 return retval;
479 }
480
481 /**
482 * ccs_network_sendmsg_acl - Check permission for sendmsg() operation.
483 *
484 * @is_ipv6: True if @address is an IPv6 address.
485 * @sock_type: Type of socket. (UDP or RAW)
486 * @address: An IPv4 or IPv6 address.
487 * @port: Port number.
488 *
489 * Returns 0 on success, negative value otherwise.
490 */
491 static inline int ccs_network_sendmsg_acl(const bool is_ipv6,
492 const int sock_type,
493 const u8 *address, const u16 port)
494 {
495 u8 operation;
496 if (sock_type == SOCK_DGRAM)
497 operation = CCS_NETWORK_UDP_CONNECT;
498 else
499 operation = CCS_NETWORK_RAW_CONNECT;
500 return ccs_network_entry(is_ipv6, operation,
501 (const u32 *) address, ntohs(port));
502 }
503
504 /**
505 * ccs_network_recvmsg_acl - Check permission for recvmsg() operation.
506 *
507 * @is_ipv6: True if @address is an IPv6 address.
508 * @sock_type: Type of socket. (UDP or RAW)
509 * @address: An IPv4 or IPv6 address.
510 * @port: Port number.
511 *
512 * Returns 0 on success, negative value otherwise.
513 */
514 static inline int ccs_network_recvmsg_acl(const bool is_ipv6,
515 const int sock_type,
516 const u8 *address, 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 msghdr *msg,
752 int size)
753 {
754 struct sockaddr *addr = (struct sockaddr *) msg->msg_name;
755 const int addr_len = msg->msg_namelen;
756 int error = 0;
757 const int type = sock->type;
758 /* Nothing to do if I am a kernel service. */
759 if (segment_eq(get_fs(), KERNEL_DS))
760 return 0;
761 if (!addr || (type != SOCK_DGRAM && type != SOCK_RAW))
762 return 0;
763 switch (addr->sa_family) {
764 struct sockaddr_in6 *addr6;
765 struct sockaddr_in *addr4;
766 u16 port;
767 case AF_INET6:
768 if (addr_len < SIN6_LEN_RFC2133)
769 break;
770 addr6 = (struct sockaddr_in6 *) addr;
771 if (type == SOCK_DGRAM)
772 port = addr6->sin6_port;
773 else
774 port = htons(sock->sk->sk_protocol);
775 error = ccs_network_sendmsg_acl(true, type,
776 addr6->sin6_addr.s6_addr,
777 port);
778 break;
779 case AF_INET:
780 if (addr_len < sizeof(struct sockaddr_in))
781 break;
782 addr4 = (struct sockaddr_in *) addr;
783 if (type == SOCK_DGRAM)
784 port = addr4->sin_port;
785 else
786 port = htons(sock->sk->sk_protocol);
787 error = ccs_network_sendmsg_acl(false, type,
788 (u8 *) &addr4->sin_addr, port);
789 break;
790 }
791 return error;
792 }
793
794 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
795 #if !defined(RHEL_MAJOR) || RHEL_MAJOR != 5
796 #if !defined(AX_MAJOR) || AX_MAJOR != 3 || !defined(AX_MINOR) || AX_MINOR < 2
797
798 static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
799 {
800 return skb->nh.iph;
801 }
802
803 static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
804 {
805 return skb->h.uh;
806 }
807
808 static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb)
809 {
810 return skb->nh.ipv6h;
811 }
812
813 #endif
814 #endif
815 #endif
816
817 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
818 static void skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
819 unsigned int flags)
820 {
821 /* Clear queue. */
822 if (flags & MSG_PEEK) {
823 int clear = 0;
824 spin_lock_irq(&sk->sk_receive_queue.lock);
825 if (skb == skb_peek(&sk->sk_receive_queue)) {
826 __skb_unlink(skb, &sk->sk_receive_queue);
827 clear = 1;
828 }
829 spin_unlock_irq(&sk->sk_receive_queue.lock);
830 if (clear)
831 kfree_skb(skb);
832 }
833 skb_free_datagram(sk, skb);
834 }
835 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
836 static void skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
837 unsigned int flags)
838 {
839 /* Clear queue. */
840 if (flags & MSG_PEEK) {
841 int clear = 0;
842 spin_lock_bh(&sk->sk_receive_queue.lock);
843 if (skb == skb_peek(&sk->sk_receive_queue)) {
844 __skb_unlink(skb, &sk->sk_receive_queue);
845 clear = 1;
846 }
847 spin_unlock_bh(&sk->sk_receive_queue.lock);
848 if (clear)
849 kfree_skb(skb);
850 }
851 skb_free_datagram(sk, skb);
852 }
853 #endif
854
855 /*
856 * Check permission for receiving a datagram via a UDP or RAW socket.
857 *
858 * Currently, the LSM hook for this purpose is not provided.
859 */
860 int ccs_socket_recvmsg_permission(struct sock *sk, struct sk_buff *skb,
861 const unsigned int flags)
862 {
863 int error = 0;
864 const unsigned int type = sk->sk_type;
865 if (type != SOCK_DGRAM && type != SOCK_RAW)
866 return 0;
867 /* Nothing to do if I am a kernel service. */
868 if (segment_eq(get_fs(), KERNEL_DS))
869 return 0;
870
871 switch (sk->sk_family) {
872 struct in6_addr sin6;
873 struct in_addr sin4;
874 u16 port;
875 case PF_INET6:
876 if (type == SOCK_DGRAM) { /* UDP IPv6 */
877 if (skb->protocol == htons(ETH_P_IP)) {
878 ipv6_addr_set(&sin6, 0, 0, htonl(0xffff),
879 ip_hdr(skb)->saddr);
880 } else {
881 ipv6_addr_copy(&sin6, &ipv6_hdr(skb)->saddr);
882 }
883 port = udp_hdr(skb)->source;
884 } else { /* RAW IPv6 */
885 ipv6_addr_copy(&sin6, &ipv6_hdr(skb)->saddr);
886 port = htons(sk->sk_protocol);
887 }
888 error = ccs_network_recvmsg_acl(true, type,
889 (u8 *) &sin6, port);
890 break;
891 case PF_INET:
892 if (type == SOCK_DGRAM) { /* UDP IPv4 */
893 sin4.s_addr = ip_hdr(skb)->saddr;
894 port = udp_hdr(skb)->source;
895 } else { /* RAW IPv4 */
896 sin4.s_addr = ip_hdr(skb)->saddr;
897 port = htons(sk->sk_protocol);
898 }
899 error = ccs_network_recvmsg_acl(false, type,
900 (u8 *) &sin4, port);
901 break;
902 }
903 if (!error)
904 return 0;
905 /*
906 * Remove from queue if MSG_PEEK is used so that
907 * the head message from unwanted source in receive queue will not
908 * prevent the caller from picking up next message from wanted source
909 * when the caller is using MSG_PEEK flag for picking up.
910 */
911 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
912 if (type == SOCK_DGRAM)
913 lock_sock(sk);
914 #endif
915 skb_kill_datagram(sk, skb, flags);
916 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
917 if (type == SOCK_DGRAM)
918 release_sock(sk);
919 #endif
920 /* Hope less harmful than -EPERM. */
921 return -ENOMEM;
922 }
923 EXPORT_SYMBOL(ccs_socket_recvmsg_permission);

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