15 |
#include <linux/in.h> |
#include <linux/in.h> |
16 |
#include <linux/in6.h> |
#include <linux/in6.h> |
17 |
#include <linux/un.h> |
#include <linux/un.h> |
18 |
|
#include <net/sock.h> |
19 |
|
#include <net/af_unix.h> |
20 |
#include <net/ip.h> |
#include <net/ip.h> |
21 |
#include <net/ipv6.h> |
#include <net/ipv6.h> |
22 |
#include <net/udp.h> |
#include <net/udp.h> |
303 |
int error = 0; |
int error = 0; |
304 |
const u8 type = ccs_inet2mac[address->protocol][address->operation]; |
const u8 type = ccs_inet2mac[address->protocol][address->operation]; |
305 |
if (type && ccs_init_request_info(&r, type) != CCS_CONFIG_DISABLED) { |
if (type && ccs_init_request_info(&r, type) != CCS_CONFIG_DISABLED) { |
306 |
|
struct task_struct * const task = current; |
307 |
|
const bool no_sleep = address->operation == CCS_NETWORK_ACCEPT |
308 |
|
|| address->operation == CCS_NETWORK_RECV; |
309 |
r.param_type = CCS_TYPE_INET_ACL; |
r.param_type = CCS_TYPE_INET_ACL; |
310 |
r.param.inet_network.protocol = address->protocol; |
r.param.inet_network.protocol = address->protocol; |
311 |
r.param.inet_network.operation = address->operation; |
r.param.inet_network.operation = address->operation; |
314 |
r.param.inet_network.port = ntohs(address->inet.port); |
r.param.inet_network.port = ntohs(address->inet.port); |
315 |
/* use host byte order to allow u32 comparison than memcmp().*/ |
/* use host byte order to allow u32 comparison than memcmp().*/ |
316 |
r.param.inet_network.ip = ntohl(*address->inet.address); |
r.param.inet_network.ip = ntohl(*address->inet.address); |
317 |
|
if (no_sleep) |
318 |
|
task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR; |
319 |
do { |
do { |
320 |
ccs_check_acl(&r, ccs_check_inet_acl); |
ccs_check_acl(&r, ccs_check_inet_acl); |
321 |
error = ccs_audit_inet_log(&r); |
error = ccs_audit_inet_log(&r); |
322 |
} while (error == CCS_RETRY_REQUEST); |
} while (error == CCS_RETRY_REQUEST); |
323 |
|
if (no_sleep) |
324 |
|
task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR; |
325 |
} |
} |
326 |
ccs_read_unlock(idx); |
ccs_read_unlock(idx); |
327 |
return error; |
return error; |
350 |
address->unix0.addr_len |
address->unix0.addr_len |
351 |
- sizeof(sa_family_t)); |
- sizeof(sa_family_t)); |
352 |
if (buf) { |
if (buf) { |
353 |
|
struct task_struct * const task = current; |
354 |
|
const bool no_sleep = |
355 |
|
address->operation == CCS_NETWORK_ACCEPT || |
356 |
|
address->operation == CCS_NETWORK_RECV; |
357 |
struct ccs_path_info addr; |
struct ccs_path_info addr; |
358 |
addr.name = buf; |
addr.name = buf; |
359 |
ccs_fill_path_info(&addr); |
ccs_fill_path_info(&addr); |
361 |
r.param.unix_network.protocol = address->protocol; |
r.param.unix_network.protocol = address->protocol; |
362 |
r.param.unix_network.operation = address->operation; |
r.param.unix_network.operation = address->operation; |
363 |
r.param.unix_network.address = &addr; |
r.param.unix_network.address = &addr; |
364 |
|
if (no_sleep) |
365 |
|
task->ccs_flags |= |
366 |
|
CCS_DONT_SLEEP_ON_ENFORCE_ERROR; |
367 |
|
|
368 |
do { |
do { |
369 |
ccs_check_acl(&r, ccs_check_unix_acl); |
ccs_check_acl(&r, ccs_check_unix_acl); |
370 |
error = ccs_audit_unix_log(&r); |
error = ccs_audit_unix_log(&r); |
371 |
} while (error == CCS_RETRY_REQUEST); |
} while (error == CCS_RETRY_REQUEST); |
372 |
|
if (no_sleep) |
373 |
|
task->ccs_flags &= |
374 |
|
~CCS_DONT_SLEEP_ON_ENFORCE_ERROR; |
375 |
kfree(buf); |
kfree(buf); |
376 |
} else |
} else |
377 |
error = -ENOMEM; |
error = -ENOMEM; |
383 |
static bool ccs_same_inet_acl(const struct ccs_acl_info *a, |
static bool ccs_same_inet_acl(const struct ccs_acl_info *a, |
384 |
const struct ccs_acl_info *b) |
const struct ccs_acl_info *b) |
385 |
{ |
{ |
386 |
const struct ccs_inet_acl *p1 = container_of(a, typeof(*p1), |
const struct ccs_inet_acl *p1 = container_of(a, typeof(*p1), head); |
387 |
head); |
const struct ccs_inet_acl *p2 = container_of(b, typeof(*p2), head); |
|
const struct ccs_inet_acl *p2 = container_of(b, typeof(*p2), |
|
|
head); |
|
388 |
return ccs_same_acl_head(&p1->head, &p2->head) |
return ccs_same_acl_head(&p1->head, &p2->head) |
389 |
&& p1->protocol == p2->protocol |
&& p1->protocol == p2->protocol |
390 |
&& p1->address_type == p2->address_type && |
&& p1->address_type == p2->address_type && |
399 |
static bool ccs_same_unix_acl(const struct ccs_acl_info *a, |
static bool ccs_same_unix_acl(const struct ccs_acl_info *a, |
400 |
const struct ccs_acl_info *b) |
const struct ccs_acl_info *b) |
401 |
{ |
{ |
402 |
const struct ccs_unix_acl *p1 = container_of(a, typeof(*p1), |
const struct ccs_unix_acl *p1 = container_of(a, typeof(*p1), head); |
403 |
head); |
const struct ccs_unix_acl *p2 = container_of(b, typeof(*p2), head); |
|
const struct ccs_unix_acl *p2 = container_of(b, typeof(*p2), |
|
|
head); |
|
404 |
return ccs_same_acl_head(&p1->head, &p2->head) && |
return ccs_same_acl_head(&p1->head, &p2->head) && |
405 |
p1->protocol == p2->protocol && |
p1->protocol == p2->protocol && |
406 |
ccs_same_name_union(&p1->name, &p2->name); |
ccs_same_name_union(&p1->name, &p2->name); |
407 |
} |
} |
408 |
|
|
409 |
static bool ccs_merge_inet_acl(struct ccs_acl_info *a, |
static bool ccs_merge_inet_acl(struct ccs_acl_info *a, struct ccs_acl_info *b, |
410 |
struct ccs_acl_info *b, |
const bool is_delete) |
|
const bool is_delete) |
|
411 |
{ |
{ |
412 |
u8 * const a_perm = &container_of(a, struct ccs_inet_acl, head) |
u8 * const a_perm = &container_of(a, struct ccs_inet_acl, head)->perm; |
|
->perm; |
|
413 |
u8 perm = *a_perm; |
u8 perm = *a_perm; |
414 |
const u8 b_perm = container_of(b, struct ccs_inet_acl, head) |
const u8 b_perm = container_of(b, struct ccs_inet_acl, head)->perm; |
|
->perm; |
|
415 |
if (is_delete) |
if (is_delete) |
416 |
perm &= ~b_perm; |
perm &= ~b_perm; |
417 |
else |
else |
420 |
return !perm; |
return !perm; |
421 |
} |
} |
422 |
|
|
423 |
static bool ccs_merge_unix_acl(struct ccs_acl_info *a, |
static bool ccs_merge_unix_acl(struct ccs_acl_info *a, struct ccs_acl_info *b, |
424 |
struct ccs_acl_info *b, |
const bool is_delete) |
|
const bool is_delete) |
|
425 |
{ |
{ |
426 |
u8 * const a_perm = &container_of(a, struct ccs_unix_acl, head) |
u8 * const a_perm = &container_of(a, struct ccs_unix_acl, head)->perm; |
|
->perm; |
|
427 |
u8 perm = *a_perm; |
u8 perm = *a_perm; |
428 |
const u8 b_perm = container_of(b, struct ccs_unix_acl, head) |
const u8 b_perm = container_of(b, struct ccs_unix_acl, head)->perm; |
|
->perm; |
|
429 |
if (is_delete) |
if (is_delete) |
430 |
perm &= ~b_perm; |
perm &= ~b_perm; |
431 |
else |
else |
459 |
char *w[4]; |
char *w[4]; |
460 |
if (!ccs_tokenize(data, w, sizeof(w)) || !w[3][0]) |
if (!ccs_tokenize(data, w, sizeof(w)) || !w[3][0]) |
461 |
return -EINVAL; |
return -EINVAL; |
462 |
for (e.protocol = 0; e.protocol < CCS_MAX_INET_PROTOCOL; |
for (e.protocol = 0; e.protocol < CCS_MAX_INET_PROTOCOL; e.protocol++) |
|
e.protocol++) |
|
463 |
if (!strcmp(w[0], ccs_inet_keyword[e.protocol])) |
if (!strcmp(w[0], ccs_inet_keyword[e.protocol])) |
464 |
break; |
break; |
465 |
for (type = 0; type < CCS_MAX_NETWORK_OPERATION; type++) |
for (type = 0; type < CCS_MAX_NETWORK_OPERATION; type++) |
530 |
char *w[3]; |
char *w[3]; |
531 |
if (!ccs_tokenize(data, w, sizeof(w)) || !w[2][0]) |
if (!ccs_tokenize(data, w, sizeof(w)) || !w[2][0]) |
532 |
return -EINVAL; |
return -EINVAL; |
533 |
for (e.protocol = 0; e.protocol < CCS_MAX_UNIX_PROTOCOL; |
for (e.protocol = 0; e.protocol < CCS_MAX_UNIX_PROTOCOL; e.protocol++) |
|
e.protocol++) |
|
534 |
if (!strcmp(w[0], ccs_unix_keyword[e.protocol])) |
if (!strcmp(w[0], ccs_unix_keyword[e.protocol])) |
535 |
break; |
break; |
536 |
for (type = 0; type < CCS_MAX_NETWORK_OPERATION; type++) |
for (type = 0; type < CCS_MAX_NETWORK_OPERATION; type++) |
554 |
|
|
555 |
#else |
#else |
556 |
|
|
557 |
static bool ccs_check_inet_address(const struct sockaddr *addr, |
static int ccs_check_inet_address(const struct sockaddr *addr, |
558 |
const unsigned int addr_len, |
const unsigned int addr_len, const u16 port, |
559 |
struct ccs_inet_addr_info *address) |
struct ccs_addr_info *address) |
560 |
{ |
{ |
561 |
|
struct ccs_inet_addr_info *i = &address->inet; |
562 |
switch (addr->sa_family) { |
switch (addr->sa_family) { |
563 |
case AF_INET6: |
case AF_INET6: |
564 |
if (addr_len < SIN6_LEN_RFC2133) |
if (addr_len < SIN6_LEN_RFC2133) |
565 |
goto skip; |
goto skip; |
566 |
address->is_ipv6 = true; |
i->is_ipv6 = true; |
567 |
address->address = (u32 *) |
i->address = (u32 *) |
568 |
((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr; |
((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr; |
569 |
address->port = ((struct sockaddr_in6 *) addr)->sin6_port; |
i->port = ((struct sockaddr_in6 *) addr)->sin6_port; |
570 |
break; |
break; |
571 |
case AF_INET: |
case AF_INET: |
572 |
if (addr_len < sizeof(struct sockaddr_in)) |
if (addr_len < sizeof(struct sockaddr_in)) |
573 |
goto skip; |
goto skip; |
574 |
address->is_ipv6 = false; |
i->is_ipv6 = false; |
575 |
address->address = (u32 *) |
i->address = (u32 *) &((struct sockaddr_in *) addr)->sin_addr; |
576 |
&((struct sockaddr_in *) addr)->sin_addr; |
i->port = ((struct sockaddr_in *) addr)->sin_port; |
|
address->port = ((struct sockaddr_in *) addr)->sin_port; |
|
577 |
break; |
break; |
578 |
default: |
default: |
579 |
goto skip; |
goto skip; |
580 |
} |
} |
581 |
return true; |
if (address->protocol == CCS_NETWORK_INET_RAW_PROTOCOL) |
582 |
|
i->port = htons(port); |
583 |
|
return ccs_inet_entry(address); |
584 |
skip: |
skip: |
585 |
return false; |
return 0; |
586 |
} |
} |
587 |
|
|
588 |
static bool ccs_check_unix_address(struct sockaddr *addr, |
static int ccs_unix_entry(const struct ccs_addr_info *address); |
589 |
const unsigned int addr_len, |
|
590 |
struct ccs_unix_addr_info *address) |
static int ccs_check_unix_address(struct sockaddr *addr, |
591 |
|
const unsigned int addr_len, |
592 |
|
struct ccs_addr_info *address) |
593 |
{ |
{ |
594 |
|
struct ccs_unix_addr_info *u = &address->unix0; |
595 |
if (addr->sa_family != AF_UNIX) |
if (addr->sa_family != AF_UNIX) |
596 |
return false; |
return 0; |
597 |
address->addr = ((struct sockaddr_un *) addr)->sun_path; |
u->addr = ((struct sockaddr_un *) addr)->sun_path; |
598 |
address->addr_len = addr_len; |
u->addr_len = addr_len; |
599 |
/* |
/* |
600 |
* Terminate pathname with '\0' like unix_mkname() does. |
* Terminate pathname with '\0' like unix_mkname() does. |
601 |
* This is needed because pathname was copied by move_addr_to_kernel() |
* This is needed because pathname was copied by move_addr_to_kernel() |
602 |
* but not yet terminated by unix_mkname(). |
* but not yet terminated by unix_mkname(). |
603 |
*/ |
*/ |
604 |
if (address->addr[0] && addr_len > sizeof(short) && |
if (u->addr[0] && addr_len > sizeof(short) && |
605 |
addr_len <= sizeof(struct sockaddr_un)) |
addr_len <= sizeof(struct sockaddr_un)) |
606 |
((char *) addr)[addr_len] = '\0'; |
((char *) u->addr)[addr_len] = '\0'; |
607 |
return true; |
return ccs_unix_entry(address); |
608 |
} |
} |
609 |
|
|
610 |
static bool ccs_kernel_service(void) |
static bool ccs_kernel_service(void) |
613 |
return segment_eq(get_fs(), KERNEL_DS); |
return segment_eq(get_fs(), KERNEL_DS); |
614 |
} |
} |
615 |
|
|
616 |
static u8 ccs_sock_family(struct socket *sock) |
static u8 ccs_sock_family(struct sock *sk) |
617 |
{ |
{ |
618 |
if (ccs_kernel_service()) |
if (ccs_kernel_service()) |
619 |
return 0; |
return 0; |
620 |
switch (sock->sk->sk_family) { |
switch (sk->sk_family) { |
621 |
case PF_INET: |
case PF_INET: |
622 |
case PF_INET6: |
case PF_INET6: |
623 |
return 1; |
return 1; |
643 |
/* Check permission for listening a socket. */ |
/* Check permission for listening a socket. */ |
644 |
static int __ccs_socket_listen_permission(struct socket *sock) |
static int __ccs_socket_listen_permission(struct socket *sock) |
645 |
{ |
{ |
|
struct sockaddr_storage addr; |
|
|
int error; |
|
|
int addr_len; |
|
646 |
struct ccs_addr_info address; |
struct ccs_addr_info address; |
647 |
const u8 family = ccs_sock_family(sock); |
const u8 family = ccs_sock_family(sock->sk); |
648 |
const unsigned int type = sock->type; |
const unsigned int type = sock->type; |
649 |
|
struct sockaddr_storage addr; |
650 |
|
int addr_len; |
651 |
if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET)) |
if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET)) |
652 |
return 0; |
return 0; |
653 |
error = sock->ops->getname(sock, (struct sockaddr *) &addr, &addr_len, |
{ |
654 |
0); |
const int error = sock->ops->getname(sock, (struct sockaddr *) |
655 |
if (error) |
&addr, &addr_len, 0); |
656 |
return error; |
if (error) |
657 |
|
return error; |
658 |
|
} |
659 |
address.operation = CCS_NETWORK_LISTEN; |
address.operation = CCS_NETWORK_LISTEN; |
660 |
if (family == 2) { |
if (family == 2) { |
661 |
if (type == SOCK_STREAM) |
if (type == SOCK_STREAM) |
662 |
address.protocol = CCS_NETWORK_UNIX_STREAM_PROTOCOL; |
address.protocol = CCS_NETWORK_UNIX_STREAM_PROTOCOL; |
663 |
else |
else |
664 |
address.protocol = CCS_NETWORK_UNIX_SEQPACKET_PROTOCOL; |
address.protocol = CCS_NETWORK_UNIX_SEQPACKET_PROTOCOL; |
665 |
if (ccs_check_unix_address((struct sockaddr *) &addr, addr_len, |
return ccs_check_unix_address((struct sockaddr *) &addr, |
666 |
&address.unix0)) |
addr_len, &address); |
|
error = ccs_unix_entry(&address); |
|
|
} else { |
|
|
address.protocol = CCS_NETWORK_INET_TCP_PROTOCOL; |
|
|
if (ccs_check_inet_address((struct sockaddr *) &addr, addr_len, |
|
|
&address.inet)) |
|
|
error = ccs_inet_entry(&address); |
|
667 |
} |
} |
668 |
return error; |
address.protocol = CCS_NETWORK_INET_TCP_PROTOCOL; |
669 |
|
return ccs_check_inet_address((struct sockaddr *) &addr, addr_len, 0, |
670 |
|
&address); |
671 |
} |
} |
672 |
|
|
673 |
/* Check permission for setting the remote address of a socket. */ |
/* Check permission for setting the remote address of a socket. */ |
674 |
static int __ccs_socket_connect_permission(struct socket *sock, |
static int __ccs_socket_connect_permission(struct socket *sock, |
675 |
struct sockaddr *addr, int addr_len) |
struct sockaddr *addr, int addr_len) |
676 |
{ |
{ |
|
int error = 0; |
|
|
const unsigned int type = sock->type; |
|
677 |
struct ccs_addr_info address; |
struct ccs_addr_info address; |
678 |
const u8 family = ccs_sock_family(sock); |
const u8 family = ccs_sock_family(sock->sk); |
679 |
|
const unsigned int type = sock->type; |
680 |
if (!family) |
if (!family) |
681 |
return 0; |
return 0; |
682 |
address.operation = CCS_NETWORK_CONNECT; |
address.operation = CCS_NETWORK_CONNECT; |
695 |
default: |
default: |
696 |
return 0; |
return 0; |
697 |
} |
} |
698 |
if (ccs_check_unix_address(addr, addr_len, &address.unix0)) |
return ccs_check_unix_address(addr, addr_len, &address); |
|
error = ccs_unix_entry(&address); |
|
|
} else { |
|
|
switch (type) { |
|
|
case SOCK_STREAM: |
|
|
address.protocol = CCS_NETWORK_INET_TCP_PROTOCOL; |
|
|
break; |
|
|
case SOCK_DGRAM: |
|
|
address.protocol = CCS_NETWORK_INET_UDP_PROTOCOL; |
|
|
address.operation = CCS_NETWORK_SEND; |
|
|
break; |
|
|
case SOCK_RAW: |
|
|
address.protocol = CCS_NETWORK_INET_RAW_PROTOCOL; |
|
|
address.operation = CCS_NETWORK_SEND; |
|
|
break; |
|
|
default: |
|
|
return 0; |
|
|
} |
|
|
if (ccs_check_inet_address(addr, addr_len, &address.inet)) { |
|
|
if (type == SOCK_RAW) |
|
|
address.inet.port = htons(sock->sk->sk_protocol); |
|
|
error = ccs_inet_entry(&address); |
|
|
} |
|
699 |
} |
} |
700 |
return error; |
switch (type) { |
701 |
|
case SOCK_STREAM: |
702 |
|
address.protocol = CCS_NETWORK_INET_TCP_PROTOCOL; |
703 |
|
break; |
704 |
|
case SOCK_DGRAM: |
705 |
|
address.protocol = CCS_NETWORK_INET_UDP_PROTOCOL; |
706 |
|
address.operation = CCS_NETWORK_SEND; |
707 |
|
break; |
708 |
|
case SOCK_RAW: |
709 |
|
address.protocol = CCS_NETWORK_INET_RAW_PROTOCOL; |
710 |
|
address.operation = CCS_NETWORK_SEND; |
711 |
|
break; |
712 |
|
default: |
713 |
|
return 0; |
714 |
|
} |
715 |
|
return ccs_check_inet_address(addr, addr_len, sock->sk->sk_protocol, |
716 |
|
&address); |
717 |
} |
} |
718 |
|
|
719 |
/* Check permission for setting the local address of a socket. */ |
/* Check permission for setting the local address of a socket. */ |
720 |
static int __ccs_socket_bind_permission(struct socket *sock, |
static int __ccs_socket_bind_permission(struct socket *sock, |
721 |
struct sockaddr *addr, int addr_len) |
struct sockaddr *addr, int addr_len) |
722 |
{ |
{ |
|
int error = 0; |
|
|
const unsigned int type = sock->type; |
|
723 |
struct ccs_addr_info address; |
struct ccs_addr_info address; |
724 |
const u8 family = ccs_sock_family(sock); |
const u8 family = ccs_sock_family(sock->sk); |
725 |
|
const unsigned int type = sock->type; |
726 |
if (!family) |
if (!family) |
727 |
return 0; |
return 0; |
728 |
address.operation = CCS_NETWORK_BIND; |
address.operation = CCS_NETWORK_BIND; |
740 |
default: |
default: |
741 |
return 0; |
return 0; |
742 |
} |
} |
743 |
if (ccs_check_unix_address(addr, addr_len, &address.unix0)) |
return ccs_check_unix_address(addr, addr_len, &address); |
|
error = ccs_unix_entry(&address); |
|
|
} else { |
|
|
switch (type) { |
|
|
case SOCK_STREAM: |
|
|
address.protocol = CCS_NETWORK_INET_TCP_PROTOCOL; |
|
|
break; |
|
|
case SOCK_DGRAM: |
|
|
address.protocol = CCS_NETWORK_INET_UDP_PROTOCOL; |
|
|
break; |
|
|
case SOCK_RAW: |
|
|
address.protocol = CCS_NETWORK_INET_RAW_PROTOCOL; |
|
|
break; |
|
|
default: |
|
|
return 0; |
|
|
} |
|
|
if (ccs_check_inet_address(addr, addr_len, &address.inet)) { |
|
|
if (type == SOCK_RAW) |
|
|
address.inet.port = htons(sock->sk->sk_protocol); |
|
|
error = ccs_inet_entry(&address); |
|
|
} |
|
744 |
} |
} |
745 |
return error; |
switch (type) { |
746 |
|
case SOCK_STREAM: |
747 |
|
address.protocol = CCS_NETWORK_INET_TCP_PROTOCOL; |
748 |
|
break; |
749 |
|
case SOCK_DGRAM: |
750 |
|
address.protocol = CCS_NETWORK_INET_UDP_PROTOCOL; |
751 |
|
break; |
752 |
|
case SOCK_RAW: |
753 |
|
address.protocol = CCS_NETWORK_INET_RAW_PROTOCOL; |
754 |
|
break; |
755 |
|
default: |
756 |
|
return 0; |
757 |
|
} |
758 |
|
return ccs_check_inet_address(addr, addr_len, sock->sk->sk_protocol, |
759 |
|
&address); |
760 |
} |
} |
761 |
|
|
762 |
/* Check permission for sending a datagram via a UDP or RAW socket. */ |
/* Check permission for sending a datagram via a UDP or RAW socket. */ |
763 |
static int __ccs_socket_sendmsg_permission(struct socket *sock, |
static int __ccs_socket_sendmsg_permission(struct socket *sock, |
764 |
struct msghdr *msg, int size) |
struct msghdr *msg, int size) |
765 |
{ |
{ |
|
int error = 0; |
|
|
const int type = sock->type; |
|
766 |
struct ccs_addr_info address; |
struct ccs_addr_info address; |
767 |
const u8 family = ccs_sock_family(sock); |
const u8 family = ccs_sock_family(sock->sk); |
768 |
|
const unsigned int type = sock->type; |
769 |
if (!msg->msg_name || !family) |
if (!msg->msg_name || !family) |
770 |
return 0; |
return 0; |
771 |
address.operation = CCS_NETWORK_SEND; |
address.operation = CCS_NETWORK_SEND; |
773 |
if (type != SOCK_DGRAM) |
if (type != SOCK_DGRAM) |
774 |
return 0; |
return 0; |
775 |
address.protocol = CCS_NETWORK_UNIX_DGRAM_PROTOCOL; |
address.protocol = CCS_NETWORK_UNIX_DGRAM_PROTOCOL; |
776 |
if (ccs_check_unix_address((struct sockaddr *) msg->msg_name, |
return ccs_check_unix_address((struct sockaddr *) |
777 |
msg->msg_namelen, &address.unix0)) |
msg->msg_name, msg->msg_namelen, |
778 |
error = ccs_unix_entry(&address); |
&address); |
|
} else { |
|
|
switch (type) { |
|
|
case SOCK_DGRAM: |
|
|
address.protocol = CCS_NETWORK_INET_UDP_PROTOCOL; |
|
|
break; |
|
|
case SOCK_RAW: |
|
|
address.protocol = CCS_NETWORK_INET_RAW_PROTOCOL; |
|
|
break; |
|
|
default: |
|
|
return 0; |
|
|
} |
|
|
if (ccs_check_inet_address((struct sockaddr *) msg->msg_name, |
|
|
msg->msg_namelen, &address.inet)) { |
|
|
if (type == SOCK_RAW) |
|
|
address.inet.port = htons(sock->sk->sk_protocol); |
|
|
error = ccs_inet_entry(&address); |
|
|
} |
|
779 |
} |
} |
780 |
return error; |
switch (type) { |
781 |
|
case SOCK_DGRAM: |
782 |
|
address.protocol = CCS_NETWORK_INET_UDP_PROTOCOL; |
783 |
|
break; |
784 |
|
case SOCK_RAW: |
785 |
|
address.protocol = CCS_NETWORK_INET_RAW_PROTOCOL; |
786 |
|
break; |
787 |
|
default: |
788 |
|
return 0; |
789 |
|
} |
790 |
|
return ccs_check_inet_address((struct sockaddr *) msg->msg_name, |
791 |
|
msg->msg_namelen, sock->sk->sk_protocol, |
792 |
|
&address); |
793 |
} |
} |
794 |
|
|
795 |
/* Check permission for accepting a socket. */ |
/* Check permission for accepting a socket. */ |
796 |
static int __ccs_socket_post_accept_permission(struct socket *sock, |
static int __ccs_socket_post_accept_permission(struct socket *sock, |
797 |
struct socket *newsock) |
struct socket *newsock) |
798 |
{ |
{ |
|
struct sockaddr_storage addr; |
|
|
struct task_struct * const task = current; |
|
|
int error; |
|
|
int addr_len; |
|
|
const u8 family = ccs_sock_family(sock); |
|
799 |
struct ccs_addr_info address; |
struct ccs_addr_info address; |
800 |
|
const u8 family = ccs_sock_family(sock->sk); |
801 |
const unsigned int type = sock->type; |
const unsigned int type = sock->type; |
802 |
|
struct sockaddr_storage addr; |
803 |
|
int addr_len; |
804 |
if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET)) |
if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET)) |
805 |
return 0; |
return 0; |
806 |
error = newsock->ops->getname(newsock, (struct sockaddr *) &addr, |
{ |
807 |
&addr_len, 2); |
const int error = newsock->ops->getname(newsock, |
808 |
if (error) |
(struct sockaddr *) |
809 |
return error; |
&addr, &addr_len, 2); |
810 |
|
if (error) |
811 |
|
return error; |
812 |
|
} |
813 |
address.operation = CCS_NETWORK_ACCEPT; |
address.operation = CCS_NETWORK_ACCEPT; |
|
task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR; |
|
814 |
if (family == 2) { |
if (family == 2) { |
815 |
if (type == SOCK_STREAM) |
if (type == SOCK_STREAM) |
816 |
address.protocol = CCS_NETWORK_UNIX_STREAM_PROTOCOL; |
address.protocol = CCS_NETWORK_UNIX_STREAM_PROTOCOL; |
817 |
else |
else |
818 |
address.protocol = CCS_NETWORK_UNIX_SEQPACKET_PROTOCOL; |
address.protocol = CCS_NETWORK_UNIX_SEQPACKET_PROTOCOL; |
819 |
if (ccs_check_unix_address((struct sockaddr *) &addr, addr_len, |
return ccs_check_unix_address((struct sockaddr *) &addr, |
820 |
&address.unix0)) |
addr_len, &address); |
|
error = ccs_unix_entry(&address); |
|
|
} else { |
|
|
address.protocol = CCS_NETWORK_INET_TCP_PROTOCOL; |
|
|
if (ccs_check_inet_address((struct sockaddr *) &addr, addr_len, |
|
|
&address.inet)) |
|
|
error = ccs_inet_entry(&address); |
|
821 |
} |
} |
822 |
task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR; |
address.protocol = CCS_NETWORK_INET_TCP_PROTOCOL; |
823 |
return error; |
return ccs_check_inet_address((struct sockaddr *) &addr, addr_len, 0, |
824 |
|
&address); |
825 |
} |
} |
826 |
|
|
827 |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
851 |
static int __ccs_socket_post_recvmsg_permission(struct sock *sk, |
static int __ccs_socket_post_recvmsg_permission(struct sock *sk, |
852 |
struct sk_buff *skb) |
struct sk_buff *skb) |
853 |
{ |
{ |
|
struct task_struct * const task = current; |
|
|
int error = 0; |
|
|
const unsigned int type = sk->sk_type; |
|
854 |
struct ccs_addr_info address; |
struct ccs_addr_info address; |
855 |
union { |
const u8 family = ccs_sock_family(sk); |
856 |
struct in6_addr sin6; |
const unsigned int type = sk->sk_type; |
857 |
struct in_addr sin4; |
struct sockaddr_storage addr; |
858 |
} ip_address; |
if (!family) |
859 |
|
return 0; |
860 |
switch (type) { |
switch (type) { |
861 |
case SOCK_DGRAM: |
case SOCK_DGRAM: |
862 |
address.protocol = CCS_NETWORK_INET_UDP_PROTOCOL; |
if (family == 2) |
863 |
|
address.protocol = CCS_NETWORK_UNIX_DGRAM_PROTOCOL; |
864 |
|
else |
865 |
|
address.protocol = CCS_NETWORK_INET_UDP_PROTOCOL; |
866 |
break; |
break; |
867 |
case SOCK_RAW: |
case SOCK_RAW: |
868 |
address.protocol = CCS_NETWORK_INET_RAW_PROTOCOL; |
address.protocol = CCS_NETWORK_INET_RAW_PROTOCOL; |
870 |
default: |
default: |
871 |
return 0; |
return 0; |
872 |
} |
} |
873 |
if (ccs_kernel_service()) |
address.operation = CCS_NETWORK_RECV; |
874 |
return 0; |
if (family == 2) { |
875 |
switch (sk->sk_family) { |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) |
876 |
case PF_INET6: |
struct unix_address *u = unix_sk(skb->sk)->addr; |
877 |
address.inet.is_ipv6 = true; |
#else |
878 |
if (type == SOCK_DGRAM && skb->protocol == htons(ETH_P_IP)) |
struct unix_address *u = skb->sk->protinfo.af_unix.addr; |
879 |
ipv6_addr_set(&ip_address.sin6, 0, 0, htonl(0xffff), |
#endif |
880 |
ip_hdr(skb)->saddr); |
unsigned int addr_len; |
881 |
|
if (!u) |
882 |
|
return 0; |
883 |
|
addr_len = u->len; |
884 |
|
if (addr_len >= sizeof(addr)) |
885 |
|
return 0; |
886 |
|
memcpy(&addr, u->name, addr_len); |
887 |
|
return ccs_check_unix_address((struct sockaddr *) &addr, |
888 |
|
addr_len, &address); |
889 |
|
} else { |
890 |
|
struct in6_addr *sin6 = (struct in6_addr *) &addr; |
891 |
|
struct in_addr *sin4 = (struct in_addr *) &addr; |
892 |
|
switch (sk->sk_family) { |
893 |
|
case PF_INET6: |
894 |
|
address.inet.is_ipv6 = true; |
895 |
|
if (type == SOCK_DGRAM && |
896 |
|
skb->protocol == htons(ETH_P_IP)) |
897 |
|
ipv6_addr_set(sin6, 0, 0, htonl(0xffff), |
898 |
|
ip_hdr(skb)->saddr); |
899 |
|
else |
900 |
|
ipv6_addr_copy(sin6, &ipv6_hdr(skb)->saddr); |
901 |
|
break; |
902 |
|
case PF_INET: |
903 |
|
address.inet.is_ipv6 = false; |
904 |
|
sin4->s_addr = ip_hdr(skb)->saddr; |
905 |
|
break; |
906 |
|
default: |
907 |
|
return 0; |
908 |
|
} |
909 |
|
address.inet.address = (u32 *) &addr; |
910 |
|
if (type == SOCK_DGRAM) |
911 |
|
address.inet.port = udp_hdr(skb)->source; |
912 |
else |
else |
913 |
ipv6_addr_copy(&ip_address.sin6, |
address.inet.port = htons(sk->sk_protocol); |
914 |
&ipv6_hdr(skb)->saddr); |
return ccs_inet_entry(&address); |
|
break; |
|
|
case PF_INET: |
|
|
address.inet.is_ipv6 = false; |
|
|
ip_address.sin4.s_addr = ip_hdr(skb)->saddr; |
|
|
break; |
|
|
default: |
|
|
goto skip; |
|
915 |
} |
} |
|
address.inet.address = (u32 *) &ip_address; |
|
|
if (type == SOCK_DGRAM) |
|
|
address.inet.port = udp_hdr(skb)->source; |
|
|
else |
|
|
address.inet.port = htons(sk->sk_protocol); |
|
|
address.operation = CCS_NETWORK_RECV; |
|
|
task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR; |
|
|
error = ccs_inet_entry(&address); |
|
|
task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR; |
|
|
skip: |
|
|
return error; |
|
916 |
} |
} |
917 |
|
|
918 |
void __init ccs_network_init(void) |
void __init ccs_network_init(void) |